캠핑과 개발


날씨가 조금 추워지네요..
요즘 아이폰 만지는 재미에 아침이 밝아 오는지도 모르고 유용한 어플을 찾아서 헤매고 있습니다. 이제 좀 정신좀 차려야 되는데 말이죠.. ㅜㅜ

간단하게 ResourceBundle을 사용하는 법을 올려봅니다.
좀 더 사용하기 쉽게 만들수도 있겠지만 그건 개인에 따라서 수정하면 될테고 어떻게 사용되는지만 알면 수정은 쉬우니까요^^


package pe.kr.anaconda.hmjkor.util;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * @author diem
 *
 */
public class ResourceUtil {
	
	
	/*
	 * url.properties
	 * url = http://hmjkor.tistory.com
	 */
	private static final String CONF_PATH = "config.url";	
	private static ResourceBundle resource = ResourceBundle.getBundle(CONF_PATH);
	private static HashMap sourceMap = new HashMap();
	
	static{
		Enumeration enu = resource.getKeys();
		String key = null;
		while(enu.hasMoreElements()){
			key = enu.nextElement();
			sourceMap.put(key, resource.getString(key));
		}		
	}	
	public static String getKey(String key){
		return sourceMap.get(key);
	}
	
	public static Map getSourceMap(){
		return sourceMap;
	}
	
	public static void main(String args){
		System.out.println(ResourceUtil.getKey("url"));
	}
}

 파일 클래스 속성 및 사용법

1. File 클래스 및 속성
package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.io.IOException;

/**
 * File 클래스 사용법 및 속성
 * @author diem
 *
 */
public class FileEx1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		File f = new File("c:\\logs\\123.txt");
		
		String fileName = f.getName();
		int pos = fileName.lastIndexOf(".");
		
		System.out.println("경로를 제외한 파일 이름 : " + f.getName());
		System.out.println("확장자를 제외한 파일 이름 : " + fileName.substring(0, pos));
		System.out.println("확장자 : " + fileName.substring(pos + 1));
		System.out.println("경로를 포함한 파일이름 : " + f.getPath());
		System.out.println("파일의 절대경로 : " + f.getAbsolutePath());
		System.out.println("파일이 속해 있는 경로 : " + f.getParent());
		System.out.println();
		System.out.println("File.pathSeparator : " + File.pathSeparator);
		System.out.println("File.pathSeparatorChar : " + File.pathSeparatorChar);
		System.out.println("File.separator : " + File.separator);
		System.out.println("File.separatorChar : " + File.separatorChar);
		System.out.println();
		System.out.println("user.dir : " + System.getProperty("user.dir"));
		System.out.println("sun.boot.class.path : " + System.getProperty("sun.boot.class.path"));
	}
}


2. 파일 리스트
package kr.pe.anaconda.test.io.file;

import java.io.File;

/**
 * 디렉터리 리스트
 * @author diem
 *
 */
public class FileEx2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		if(args.length != 1){
			System.out.println("USAGE : java FileEx2 DIRECTORY");
			System.exit(0);
		}
		File f = new File("c:\\log");
		//File f = new File(args[0]);
		
		if(!f.exists() || !f.isDirectory()){
			System.out.println("유효하지 않은 디렉토리입니다.");
			System.exit(0);
		}
		
		File[] files = f.listFiles();
		
		for(int i = 0; i < files.length; i++){
			String fileName = files[i].getName();
			System.out.println(files[i].isDirectory() ? "["+ fileName +"]" : fileName);
		}
	}
}

3. 파일 디렉터리의 파일 갯수와 디렉터리 숫자 보여주기
package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.util.ArrayList;

/**
 * 특정 디렉터리의 파일의 갯수와 디렉터리의 숫자를 보여준다.
 * @author diem
 *
 */
public class FileEx3 {

	static int totalFiles = 0;
	static int totalDirs = 0;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub	
		
		if(args == null || args.length == 0){
			args = new String[1];
		}
		
		System.out.println(args.length);
		
		args[0] = "c:\\logs";
		
		if(args.length != 1){
			System.out.println("USAGE : java FileEx3 DIRECTORY");
			System.exit(0);
		}
		
		File dir = new File(args[0]);
		if(!dir.exists() || !dir.isDirectory()){
			System.out.println("유효하지 않은 디렉토리입니다.");
			System.exit(0);
		}
		
		printFileList(dir);
		System.out.println();
		System.out.println("총 " + totalFiles + "개의 파일");
		System.out.println("총 " + totalDirs + "개의 디렉터리");
		
	}

	public static void printFileList(File dir) {
		System.out.println(dir.getAbsolutePath() + " 디렉터리");
		File[] files = dir.listFiles();
		
		ArrayList subDir = new ArrayList();
				
		for(int i = 0; i < files.length; i++){
			String fileName = files[i].getName();
			if(files[i].isDirectory()){
				fileName = "["+ fileName +"]";
				subDir.add(i+"");
			}
			System.out.println(fileName);
		}
		
		int dirNum = subDir.size();
		int fileNum = files.length - dirNum;
		
		totalFiles += fileNum;
		totalDirs += dirNum;
		
		System.out.println(fileNum + "개의 파일, " + dirNum + "개의 디렉터리");
		System.out.println();
		
		for(int i = 0; i < subDir.size(); i++){
			int index = Integer.parseInt((String)subDir.get(i));
			printFileList(files[index]);
		}
	}
}

4. 파일 리스트를 출력

package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.text.SimpleDateFormat;

/**
 * 파일 리스트를 출력한다.
 * 출력시 파일의 속성과 수정일을 함께 출력한다.
 * @author diem
 *
 */
public class FileEx4 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub	
		String currDir = System.getProperty("user.dir");
		File dir = new File(currDir);
		
		File[] files = dir.listFiles();
		
		for(int i = 0; i < files.length; i++){
			File f = files[i];
			String name = f.getName();
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mma");
			String attribute = "";
			String size = "";
			
			if(files[i].isDirectory()){
				attribute = "DIR";
			}else{
				size = f.length() + "";
				attribute = f.canRead() ? "R" : "";
				attribute += f.canWrite() ? "W" : "";
				attribute += f.isHidden() ? "H" : "";
			}
			
			System.out.printf("%s %3s %6s %s\n", df.format(f.lastModified()), attribute, size, name);
		}
	}
}

5. 파일 정렬
package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Comparator;

/**
 * 파일 정렬을 한다.
 * @author diem
 *
 */
public class FileEx5 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		if (args.length != 1 || args[0].length() != 1
				|| "tTlLnN".indexOf(args[0]) == -1) {
			System.out.println("USAGE : java FileEx5 SORT_OPTION ");
			System.out.println("	SORT_OPTION : 				");
			System.out.println(" 	t Time asending sort.		");
			System.out.println("	T Time descending sort.		");
			System.out.println("	l Length ascending sort.	");
			System.out.println("	L Length descending sort.	");
			System.out.println("	n Name asending sort.		");
			System.out.println("	N Name descending sort.		");
		}

		final char option = args[0].charAt(0);

		String currDir = System.getProperty("user.dir");
		File dir = new File(currDir);

		File[] files = dir.listFiles();

		Comparator comp = new Comparator() {
			public int compare(Object o1, Object o2) {
				long time1 = ((File) o1).lastModified();
				long time2 = ((File) o2).lastModified();

				long length1 = ((File) o1).length();
				long length2 = ((File) o2).length();

				String name1 = ((File) o1).getName().toLowerCase();
				String name2 = ((File) o2).getName().toLowerCase();

				int result = 0;

				switch (option) {
				case 't':
					if (time1 - time2 > 0)
						result = 1;
					else if (time1 - time2 == 0)
						result = 0;
					else if (time1 - time2 < 0)
						result = -1;
					break;
				case 'T':
					if (time1 - time2 > 0)
						result = -1;
					else if (time1 - time2 == 0)
						result = 0;
					else if (time1 - time2 < 0)
						result = 1;
					break;
				case 'l':
					if (length1 - length2 > 0)
						result = -1;
					else if (length1 - length2 == 0)
						result = 0;
					else if (length1 - length2 < 0)
						result = 1;
					break;
				case 'L':
					if (length1 - length2 > 0)
						result = 1;
					else if (length1 - length2 == 0)
						result = 0;
					else if (length1 - length2 < 0)
						result = -1;
					break;
				case 'n':
					result = name1.compareTo(name2);
					break;
				case 'N':
					result = name2.compareTo(name1);
					break;
				}
				return result;
			}

			public boolean equals(Object o) {
				return false;
			}
		};

		Arrays.sort(files, comp);

		for (int i = 0; i < files.length; i++) {
			File f = files[i];
			String name = f.getName();
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mma");
			String attribute = "";
			String size = "";

			if (files[i].isDirectory()) {
				attribute = "DIR";
			} else {
				size = f.length() + "";
				attribute = f.canRead() ? "R" : "";
				attribute += f.canWrite() ? "W" : "";
				attribute += f.isHidden() ? "H" : "";
			}

			System.out.printf("%s %3s %6s %s\n", df.format(f.lastModified()),
					attribute, size, name);
		}
	}
}


6. 특정 확장자를 가진 파일 출력
package kr.pe.anaconda.test.io.file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
 * 특정 확장자를 가진 파일을 출력한다.
 * @author diem
 *
 */
public class FileEx6 {

	static int found = 0;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 2) {
			System.out.println("USAGE : java FileEx6 DIRECTORY KEYWORD");
			System.exit(0);
		}

		File dir = new File(args[0]);
		String keyword = args[1];

		if (!dir.exists() || !dir.isDirectory()) {
			System.out.println("유효하지 않은 디렉터리 입니다.");
			System.exit(0);
		}

		try {
			findInFiles(dir, keyword);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void findInFiles(File dir, String keyword) throws IOException {
		// TODO Auto-generated method stub
		File[] files = dir.listFiles();

		for (int i = 0; i < files.length; i++) {
			if (files[i].isDirectory()) {
				findInFiles(files[i], keyword);
			} else {
				//파일이름
				String filename = files[i].getName();
				//파일 확장자
				String extension = filename
						.substring(filename.lastIndexOf(".") + 1);
				extension = "," + extension + ",";
				
				if(",java,txt,bak,".indexOf(extension) == -1) continue;
				
				filename = dir.getAbsolutePath() + File.separator + filename;
				
				FileReader fr = new FileReader(files[i]);
				BufferedReader br = new BufferedReader(fr);
				
				String data = "";
				int lineNum = 0;
				
				while((data = br.readLine()) != null){
					lineNum++;
					if(data.indexOf(keyword) != -1){
						found++;
						System.out.println("["+filename+"("+lineNum+") ]" + data);
					}					
				}
				br.close();
			}
		}
	}
}

7. 특정한 이름을 포함한 파일의 목록을 출력

package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.io.FilenameFilter;

/**
 * 특정한 이름을 포함한 파일의 목록을 보여준다.
 * @author diem
 *
 */
public class FileEx7 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("USAGE : java FileEx7 pattern");
			System.exit(0);
		}
		
		String currDir = System.getProperty("user.dir");
		//currDir = "c:\\logs";

		File dir = new File(currDir);
		final String pattern = args[0];
		
		
		//String[] list = (FilenameFilter filter)
		String[] files = dir.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				// TODO Auto-generated method stub
				return name.indexOf(pattern) != -1;
			}
		});
		
		for(int i = 0; i < files.length; i++){
			System.out.println(files[i]);
		}		
	}
}

8. 지정된 디렉터리에 정의한 확장자를 가진 파일을 삭제
package kr.pe.anaconda.test.io.file;

import java.io.File;
import java.io.FilenameFilter;

/**
 * 지정된 디렉터리에 정의한 확장자를 가진 파일을 삭제한다.
 * @author diem
 *
 */
public class FileEx8 {
	
	static int deleteFiles = 0;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("USAGE : java FileEx8 Extension");
			System.exit(0);
		}
		
		String currDir = System.getProperty("user.dir");
		currDir = "c:\\logs";

		File dir = new File(currDir);
		//final String ext = "." + args[0];
		final String ext = ".bak";
		delete(dir, ext);
		System.out.println(deleteFiles + " 개의 파일이 삭제 되었습니다.");
	}

	private static void delete(File dir, String ext) {
		// TODO Auto-generated method stub
		
		File[] files = dir.listFiles();
		
		for(int i = 0; i < files.length; i++){
			if(files[i].isDirectory()){
				delete(files[i], ext);
			}else{
				String filename = files[i].getAbsolutePath();
				
				if(filename.endsWith(ext)){
					System.out.print(filename);
					if(files[i].delete()){
						System.out.println("-삭제 성공");
						deleteFiles++;
					}else{
						System.out.println("-삭제 실패");
					}
				}				
			}
		}		
	}		
}

9. 지정된 디렉터리에 파일명이 숫자인 경우 파일명을 변경
package kr.pe.anaconda.test.io.file;

import java.io.File;

/**
 * 지정된 디렉터리에 파일명이 숫자인 경우 파일명을 변경한다.
 * ex) 1.gif -> 00001.gif
 * @author diem
 *
 */
public class FileEx9 {	

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 0) {
			System.out.println("USAGE : java FileEx9 DIRECTORY");
			System.exit(0);
		}
		
		//File dir = new File(args[0]);
		File dir = new File("c:\\logs");
		if(!dir.exists() || !dir.isDirectory()){
			System.out.println("유효하지 않은 디렉토리입니다.");
			System.exit(0);
		}
		
		File[] files = dir.listFiles();
		for(int i = 0; i < files.length; i++){
			String fileName = files[i].getName();
			//파일명
			System.out.println("파일이름 :" + fileName);
			String newFileName = "0000" + fileName;
			newFileName = newFileName.substring(newFileName.length() - 7);
			System.out.println("변경된 파일 이름 : " + newFileName );
			files[i].renameTo(new File(dir, newFileName));
		}
	}		
}

java에서 파일에 추가 라인을 입력하고 싶을때 옵션입니다. 15라인 참고하면 됩니다.

  1. package kr.pe.anaconda.test;
  2.  
  3. import java.io.FileNotFoundException;
  4. import java.io.FileWriter;
  5. import java.io.IOException;
  6. import java.io.PrintWriter;
  7.  
  8. public class Test {
  9.  
  10.     public static void main(String[] args) {       
  11.        
  12.         String file = "C:/logs/log.log";
  13.         PrintWriter pw = null;
  14.         try {
  15.             pw = new PrintWriter(new FileWriter(file, true));
  16.             pw.write(String.valueOf(System.currentTimeMillis()));
  17.             pw.write("\n");
  18.         } catch (FileNotFoundException e) {        
  19.             e.printStackTrace();
  20.         } catch (IOException e) {          
  21.             e.printStackTrace();
  22.         }finally{
  23.             if(pw != null) pw.close();
  24.         }
  25.     }
  26. }



하드디스크 정보를 확인하는 코드
FIle 클래스에 요런게 있는지는 오늘 알았네요 ^^;;
기초 공부 좀 많이 해야겠습니다.

package test;
import java.io.File;
public class Test {
	public static void main(String[] args) {
		File[] roots = File.listRoots();
		for(File root: roots){
			System.out.println("드라이브명  " + root.getAbsolutePath());
			System.out.println("HDD 남은 공간 : " + root.getFreeSpace());
			System.out.println("HDD 사용 가능 공간 : " + root.getUsableSpace());
			System.out.println("HDD 사용 공간 : " + (root.getTotalSpace() - root.getFreeSpace()));
		}
	}
}


Ajax를 사용하다 보면 서버로부터 객체를 가져와 브라우저에 보여 줘야 하는 경우가 있다.
예전에는 이를 xml 형태로 많이 했지만 최근에는 json 형식으로 가져와서 보여주는 경우가 많은데 이는 json형식이 핸들링 하기도 더 쉽고 여러가지로 작업하기가 편하기 때문이다.
하지만 이런 xml도 마찬가지겠지만 json 형식도 알맞은 형태로 가공을 해서 보내주려면 여러모로 불편한 사항이 많이 있다 하나의 유틸성 메소드를 많들어서 사용해도 되지만 편하게 사용할수 있도록 많은 라이브러리도 제공을 해준다 그중에 하나가 JSONObject를 이용하는 방법인데 사용법이 간단하다.
    
import org.json.simple.JSONObject;
/**
 * @author diem
 *
 */
public class JSONObjectTest {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		JSONObject obj = new JSONObject();
		obj.put("param1", "1");
		obj.put("param2", "2");
		obj.put("param3", "3");		
		System.out.println(obj.toString());
		
		JSONObject subObj = new JSONObject();
		subObj.put("subParam1", "sub1");
		subObj.put("subParam2", "sub2");
		subObj.put("subParam3", "sub3");
		subObj.put("subParam4", "sub4");
		System.out.println(subObj.toString());
		
		obj.put("param4", subObj);
		System.out.println(obj.toString());		
	}
}

Spring2.5 annotation 설정

없으면 에러 낼거야
이건 2.5이전부터 있던건데 그냥 한번 짚고 넘어 갑니다.
@Required 가 붙은 setter 메소드는 반드시 XML 설정에 의존성 삽입이 정의 되어 있어야 합니다.
(@Autowired도 안됩니다.)
XML 설정에 명시적인 의존성 삽입이 없다면 런타임 예외가 던져 집니다.
이 애노테이션을 처리하기 위한 후처리기는 다음과 같습니다.
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>


자동으로 묶어 줄게
@Autowried 는 타입에 일치하는 bean을 의존성 삽입 해줍니다.
필드에 사용 할 경우 setter가 존재하지 않아도 됩니다.
@Autowried
private Foo foo;

여러개의 인자를 가진 메소드에 사용 할 수 있습니다.
@Autowried
public void setUp(Foo foo, Bar bar) {
    this.foo = foo;
    this.bar = bar;
}

@Autowired의 속성인 required의 기본값이 true이기 때문에 발견되는 bean이 없다면 예외가 던져 집니다.
발견 되는 bean이 없더라도 예외가 던져지지 않기를 원하면 required 속성을 fasle로 설정하면 됩니다.
@Autowried(required=false)
private Foo foo;

일치하는 타입을 찾기 때문에 발견되는 bean이 여러개인 경우 예외가 던져 집니다.
이를 방지 하기 위해 <bean /> 요소의 추가된 속성인 primary를 설정 합니다.
발견되는 bean이 여러개 일지라도 primary가 설정된 bean이 참조 됩니다.
<bean id="foo" class="example.Foo" primary="true" />
<bean id="foo2" class="example.Foo"/>

이 애노테이션을 처리하기 위한 후처리기는 다음과 같습니다.
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>


정확한 이름을 알려줄게
@Autowired을 사용 할 때 타입으로 bean을 찾기 때문에 여러개의 bean이 발견되면 primary로 해결 했습니다.  하지만 @Qualifier를 이용해 찾으려는 bean의 id를 넘길 수 있습니다.
@Autowried
@Qualifier("foo")
private Foo foo;

필드에만 사용 가능 하기 때문에 메소드에 적용시 다음과 같이 설정 합니다.
@Autowried
public void setUp(@Qualifier("foo") Foo foo, @Qualifier("foo2") Foo foo2) {
    this.foo = foo;
    this.foo2 = foo2;
}

이 애노테이션을 처리하기 위한 후처리기는 @Autowried의 후처리기와 동일 합니다.


JSR-250 애노테이션 지원
-@Resource
-@PostConstruct
-@PreDestroy
위 세가지 애노테이션을 사용하기 위해서는 후처리기를 등록 해야 합니다.
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>

@Resource
JNDI의 리소스 및 Spring 컨테이너의 bean을 찾아 autowring 합니다.
name 속성을 생략 할 경우 해당 필드명으로 찾고 해당 bean이 발견되지 않는다면 타입으로 찾습니다.

필드에 사용 할 경우 setter가 존재하지 않아도 됩니다.
@Resource(name="dataSource")
private DataSource dataSource;

한개의 인자를 가진 setter 메소드만 적용 할 수 있습니다.
@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
}

타입으로 찾지 않길 원한다면 다음과 같은 설정을 합니다.
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
    <property name="fallbackToDefaultTypeMatch" value="false"></property>
</bean>

JNDI 리소스만 참조 하려면 다음과 같은 설정을 합니다.
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
    <property name="alwaysUseJndiLookup" value="true"/>
</bean>

@PostConstruct 와 @PreDestroy
기존에는 생명 주기를 다루는 방법이 2가지가 있었습니다.
1.InitializingBean, DisposableBean을 구현하는 방법
2.XML 설정파일에서 <bean /> 요소의 init-method, destroy-method 속성 설정

2.5에서 추가된 두 애노테이션은 기존의 방식과 동일한 결과를 가져 옵니다.
@PostConstruct
public void init() {
    ...
}
   
@PreDestroy
public void preDestroy() {
    ...
}

만약 3가지 방식 모두 사용할 경우
우선순위는 애노테이션->XML설정->인터페이스 구현 입니다.


이거 하나면 OK
위에서 나온 애노테이션을 사용하기 위해서는 3가지의 BeanPostProcessor를 등록해야 했습니다.
하지만 이거  하나면 3개가 모두 등록 됩니다.
<context:annotation-config />


알아서 찾아줄게
위에서 나온 애노테이션으로 XML설정을 줄이더라도 bean 선언은 반드시 해야 했습니다.
하지만 component-scan 을 이용하면 bean선언 조차 생략 할 수 있습니다.
component-scan의 대상이 되기 위해서는 스테레오타입 애노테이션을 사용해야 합니다.

4개의 스테레오타입 애노테이션
@Component
- 스테레오타입 애노테이션의 조상 입니다.
@Controller
-Spring MVC에서 컨트롤러로 인식 합니다.
@Service
-역할부여 없이 스캔 대상이 되는데 비즈니스 클래스에 사용하면 될 것 같습니다.
@Repository
-DAO에 사용되며 DB Exception을 DataAccessException으로 변환해 줍니다.

간단한 예제 입니다.
테스트에 사용될 2개의 클래스
@Component("bar")
public class Bar {
}

@Component("foo")
public class Foo  {
    @Autowired
    private Bar bar;
   
    public Bar getBar() {
        return bar;
    }
}

지정된 패키지의 하위패키지까지 재귀적으로 스테레오타입이 있는 클래스를 찾습니다.
필터를 이용해 제외 검색 대상에서 제외 시킬 수 있으며
<context:annotation-config /> 까지 자동으로 등록됩니다.
<context:component-scan base-package="example" />

테스트는 통과 합니다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"Beans.xml"})
public class ScanTest {
    @Autowired
    private Foo foo;
   
    @Test
    public void fooTest() {
        assertNotNull(foo.getBar());
    }
}

@Scope를 함께 사용 하여 Scope를 설정 할 수 있습니다.
@Scope("request")
@Component("bar")
public class Bar {
}
singleton인 foo에서 request scope인 bar를 사용 하면 어떻게 될 까요?
역시 scope문제가 발생 합니다.

이 문제를 해결하기 위해 <context:component-scan /> 요소의 scoped-proxy 속성이 존재 합니다.
scoped-proxy 속성은 <aop:scoped-poxy/> 요소처럼 WebApplicationContext 에서만 유효하며
"session", "globalSession", "request" 이외의 scope는 무시 됩니다.

아래 3가지 값을 지정 할 수 있습니다.
no - 디폴트값, proxy를 생성하지 않습니다.
interfaces - JDK Dynamic Proxy를 이용한 Proxy 생성
targetClass - CGLIB를 이용한 Proxy 생성

Bar는 인터페이스 기반이 아니기 때문에 CGLIB를 이용 했습니다.
<context:component-scan base-package="example" scoped-proxy="targetClass"/>

만약 스캔된 bean들 중 @Scope의 값이 "session", "request" 일 때
scoped-proxy 속성 값이 "targetClass", "interfaces" 가 아닐경우 예외가 던져지고 초기화에 실패 합니다.

component-scan을 이용하면 method-lookup도 불가능 하므로 참조되는 bean이 web-scope가 아니고
prototype일 경우의 문제는 해결 할수 없을것 같습니다.

출처 : http://blog.daum.net/calmknight/15785980

Effective Java

일상/책2009. 9. 18. 10:39
이전 팀장이 가지며 보던 책인데 잠깐 봤지만 먼가 있어보이는 책이였다.
하지만 너무 오래전에 출간이 되고 구매를 하려 하니 절판이 되고 구하지도 못했는데
인터넷 서점을 다니다가 재출간된걸 보고 바로 질러 버렸다.
또 재출간에 꽂혔버렸다.
출퇴근 하면서 봐야겠다.



제목 : Effective java 제2판
저자 : 지은이  Joshua Bloch/심재철
출판사 : 도서출판 대웅
가   격 :  27,000원

'일상 > ' 카테고리의 다른 글

[서평] 난 정말 JAVA를 공부한 적이 없다구요.  (0) 2010.02.23
사랑하기 때문에  (0) 2009.09.18
Adobe FLEX 3 실전 트레이닝 북  (0) 2009.09.18
퍼레이드  (0) 2009.09.09
마왕  (0) 2009.09.08

  1. 파일다운로드

    http://java.sun.com 에서 Linux 용 jdk 또는 jre를 다운로드 받는다.

  2. 파일설치

    [root@ihelpers src]# chmod 755 jdk-6-linux-i586.bin
    [root@ihelpers src]# ./jdk-6-linux-i586.bin
    [root@ihelpers src]# mv jdk1.6.0 /usr/local/jdk1.6.0

  3. 환경설정

    [root@ihelpers src]# vi /etc/profile

    PATH="$PATH:/usr/local/jdk1.6.0/bin"
    export JAVA_HOME="/usr/local/jdk1.6.0"
    export CLASSPATH=".:/usr/local/jdk1.6.0/jre/lib"

    [root@ihelpers src]# source /etc/profile
    [root@ihelpers src]# echo $PATH
    [root@ihelpers src]# echo $CLASSPATH

  4. 확인

    [root@ihelpers /]# java -version
    java version "1.6.0"
    Java(TM) SE Runtime Environment (build 1.6.0-b105)
    Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

[출처] http://blog.naver.com/ppolok81/140057597030



기존 open jdk 삭제
#rpm -qa | grep java      기존에 설치된 자바 검색
#rpm -qa | grep jdk      기존에 설치된 jdk 검색
기존 패키지 모두 삭제
#rpm -e --nodeps 패키지명

'DEVELOPMENT > Linux' 카테고리의 다른 글

vi 사용하기  (0) 2009.09.10
[linux] 시스템(하드웨어) 사양 보기  (0) 2009.02.18
[linux] Tomcat 설치  (0) 2009.02.15
[redhat9] yum install  (0) 2009.02.15
[fedora] Fedora 10 네트워크 설정하기  (0) 2009.01.29

쿠키는 웹 어플리케이션에서 클라이언트의 정보를 임시로 저장하기 위해 많이 사용된다. 또한, 클라이언트의 상태를 유지할 때 사용되는 세션을 구현하기 위해 쿠키를 사용하기도 한다. 쿠키를 사용함으로써 좀더 쉽고 간결한 방법으로 웹 어플리케이션을 구현할 수 있게 되는 경우가 많은데 이를 좀더 편하게 관리하기 위해서는 쿠기를 사용할 수 있는 보조 클래스를 만들어서 사용하게 되면 편리하다.

CookieBox.java

/*
 * @(#)CookieBox.java
 * Copyright (c) 2000~ NowOnPlay.com inc., All rights reserved.
 * Total E-Business Group, http://www.nowonplay.com
 *
 * 최초작성일자 : April 15, 2008 (hmjkor@nowonplay.com)
 * 수정이력 :
 */
package kevin.common.utils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;

import java.util.HashMap;
import java.util.Map;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.io.IOException;

/**
 * 쿠기를 보다 관리하기 쉽도록 만든 클래스로서
 * http://javacan.madvirus.net/에 있는 내용을 토대로 작성되었다.
 * @author diem
 *
 */
public class CookieBox {
   
    /* 쿠기를 담기위한 맵 */
    private Map cookieMap = new HashMap();
   
    /**
     * 생성자
     * request로 받은 쿠키값을 Key, value 값으로 매핑한다.
     * @param request
     */
    public CookieBox(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0 ; i < cookies.length ; i++) {
                cookieMap.put(cookies[i].getName(), cookies[i]);
            }
        }
    }
   
    /**
     * 쿠키를 저장한다.
     * @param name 이름
     * @param value 값
     * @return
     * @throws IOException
     */
    public static Cookie createCookie(String name, String value)
    throws IOException {
        return new Cookie(name, URLEncoder.encode(value, "euc-kr"));
    }
   
    /**
     * 쿠키를 저장한다.
     * @param name 이름
     * @param value 값
     * @param path 경로
     * @param maxAge 유효시간
     * @return
     * @throws IOException
     */

    public static Cookie createCookie(
            String name, String value, String path, int maxAge)
    throws IOException {
        Cookie cookie = new Cookie(name,
                                URLEncoder.encode(value, "euc-kr"));
        cookie.setPath(path);
        cookie.setMaxAge(maxAge);
        return cookie;
    }
   
    /**
     * 쿠키를 저장한다.
     * @param name 이름
     * @param value 값
     * @param domain 도메인
     * @param path 경로
     * @param maxAge 유효시간
     * @return
     * @throws IOException
     */
    public static Cookie createCookie(
            String name, String value, 
            String domain, String path, int maxAge)
    throws IOException {
        Cookie cookie = new Cookie(name,
                  URLEncoder.encode(value, "euc-kr"));
        cookie.setDomain(domain);
        cookie.setPath(path);
        cookie.setMaxAge(maxAge);
        return cookie;
    }
   
    /**
     * 해당되는 쿠키를 가져온다.
     * @param name
     * @return 쿠키값
     */
    public Cookie getCookie(String name) {
        return (Cookie)cookieMap.get(name);
    }
   
    /**
     * 요청한 쿠키 이름의 값을 가져온다.
     * 가져온 값이 없을 경우 null을 리턴한다.
     * @param name 쿠키 이름
     * @return
     * @throws IOException
     */
    public String getValue(String name) throws IOException {
        Cookie cookie = (Cookie)cookieMap.get(name);
        if (cookie == null) return null;
        return URLDecoder.decode(cookie.getValue(), "euc-kr");
    }
   
    /**
     * 요청한 쿠기값이 있는지의 여부를 가져온다.
     * @param name 요청할 쿠키값
     * @return
     */
    public boolean exists(String name) {
        return cookieMap.get(name) != null;
    }
}

소스를 간단하게 설명을 하면 쿠기를 담는 맵을 생성 한 후  그 맵에 Key, Value 값으로 담아두고 Key에 해당하는 쿠기를 가져오는 클래스이다.

이를 사용하기 위해서는 다음과 같이 사용하면 된다.
// CookieBox 클래스의 생성자는 request로부터 쿠키 정보를 추출
CookieBox cookieBox = new CookieBox(request);

// 쿠키가 존재하지 않으면 null 리턴
Cookie idCookie = cookieBox.getCookie("id");

// 지정한 이름의 쿠키가 존재하는지의 여부
if (cookieBox.exists("name")) { ... }

//지정한 이름의 쿠키가 존재하지 않으면 값으로 null 리턴
 String value = cookieBox.getValue("key");


이글은 최범균님의 홈페이지에서 참고한것 입니다.

오늘 공부한 패턴은 Iterator 패턴이다. Iterator패턴이란 사전적 의미로는 반복자이다.
책에 쓰인 정의로는 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공해준다라고 되어 있다.

쉬운 예로 게시판을 예로 들어보자. 게시물의 들어가는 모든 내용(제목, 작성자, 내용, 등록을 등.)을 Board라는 객체를 만들어서 한번에 담아서 사용한다고 가장을 한다고 하면 대충 Board.java 안에는 이런 코드가 들어갈 것이다.

Board.java
package hmj.pattern.Iterator;

public class Board {
   
    private String name;
    private String subject;
    private String contents;
    private String registeDate;
   
    public Board(){}
    public Board(String name, String subject, String contents, String registeDate){
        this.name = name;
        this.subject = subject;
        this.contents = contents;
        this.registeDate = registeDate;
    }
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getContents() {
        return contents;
    }
    public void setContents(String contents) {
        this.contents = contents;
    }
    public String getRegisteDate() {
        return registeDate;
    }
    public void setRegisteDate(String registeDate) {
        this.registeDate = registeDate;
    }   
}


일반적으로 게시판에 들어가는 내용은 저정도일리 없겠지만 Iterator 패턴을 설명하기에는 부족함이 없을꺼 같다. 다른 두사람이 각기 다른 게시판의 리스트를 불러오는 작업을 했다고 가정을 하자. 

A라는 사람은,
public ArrayList<Board> getList() throws Exception { /* 리스트를 불러오기 위한 로직 */ } 을 사용하고

또 다른 B라는 사람은,
public Board[] getList() throws Exception { /*  리스트를 불러오기 위한 로직 */ } 을 사용하였다.

이런식으로 넘겨 받은 객체들은 View페이지에서 각기 리턴형식이 다르기 때문에 서로 다른 형식으로 루프를 돌면서 객체를 꺼내와야 될것이다. 그안에 들어있는 객체는 똑같이 Board형식인 객체인데 말이다. 그리고 또 C가 나타나서 또 다른 방법으로 리스트 목록을 불러오는 메소드를 만든다면 또 다른 방법으로 그 객체를 가져와야 할것이다. 이런 방법은 정말 불편할것이다. 또한 코드 관리 및 확장도 어려울 것이다.

디자인 원칙중에는 "바뀌는 부분을 캡술화 하라" 라는 디자인 원칙이 있다.
위에 리스트 목록을 불러오기 위해서 각기 서로 다른 방법으로 Board 객체를 불러와서 리스트 페이지에 뿌려준다. 이렇게 서로 다른 방식으로 객체를 가져오는 부분을 캡술화를 할수 있을까?

Iterator iterator = NoticeBoardFacade.createIterator();
while(iterator.hasNext()){
    Board board = (Board)iterator.next();
}

이런식으로 Iterator라는 객체를 만들어서 사용하면 어떨까? 리스트 목록을 Iterator라는 객체에 담아서 Iterator 내부에서 ArrayList이건 Board[] 배열이건 캡술화 해서 가져오게 하면 되지 않을까? 된다.. 이게 바로 Iterator 패턴이다..

모르겠으면 일단 한번 해보면 될것 아닌가? 열번 듣는것보다 한번 소스를 보는게 낫고 직접 타이핑을 해보면 더욱 좋다. 내가 그런게 아니고 다들 그러더라.. ㅡㅡ;
소스 코드를 보기 전에 가장 먼저 알아야 할것은 Iterator라는 인터페이스에 의존한다는 점이다.

Iterator.java
/*
 * @(#)Iterator.java
 * Copyright (c) 2000~ NowOnPlay.com inc., All rights reserved.
 * Total E-Business Group, http://www.nowonplay.com
 *
 * 최초작성일자 : April 14, 2008 (hmjkor@nowonplay.com)
 * 수정이력 :
 */
package hmj.pattern.Iterator.Iterator;

public interface Iterator {   
    public boolean hasNext();
    public Object next();
}

일단 이렇게 인터페이를 만들어 두면 그 어떤 종류의 객체 컬렉션도 알맞게 구현하여 반복자를 구현 할 수가 있다.

그럼 Iterator 인터페이스를 구현한 클래스 또한 봐야 이해가 갈것이다. 그럼 보자

NoticeBoardIterator.java
/*
 * @(#)NoticeBoardIterator.java
 * Copyright (c) 2000~ NowOnPlay.com inc., All rights reserved.
 * Total E-Business Group, http://www.nowonplay.com
 *
 * 최초작성일자 : April 14, 2008 (hmjkor@nowonplay.com)
 * 수정이력 :
 */
package hmj.pattern.Iterator.board;

import hmj.pattern.Iterator.Board;
import hmj.pattern.Iterator.Iterator.Iterator;

public class NoticeBoardIterator implements Iterator {
    
    private Board[] boards;
    private int position = 0;
    
    /**
     * 생성자
     * @param boards
     */
    public NoticeBoardIterator(Board[] boards) {
        // TODO Auto-generated constructor stub
        this.boards = boards;
    }
    
    /**
     * 해당 배열에 다음 객체가 있는지 여부를 리턴한다.
     */
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if(position >= boards.length || boards[position] == null){
            return false;
        }else{
            return true;
        }        
    }
    
    /**
     * 해당 포지션에 대한 객체를 가져오고 해당 위치에 해당하는 포지션을 다음 포지션으로
     * 이동 시키기 위해  1 더해준다.
     */
    public Object next() {
        // TODO Auto-generated method stub
        Board board = boards[position];
        position = position + 1;
        return board;
    }
}

코드가 그리 어렵지 않아서 자세하진 않지만 간단한 주석만 봐도 알수 있을것이다.
Iterator 인터페이를 구현하여 hasnext(), next() 메소드를 정의해줬다. hasnext()메소드는 Board[]배열에 현재 위치값에서 다음 값이 있는지를 나타내는 메소드이고, next() 메소드는 현재 포지션의 객체를 리턴하고 다음 객체를 얻기 위해 포지션을 1 증가 시키는 메소드이다.

그럼 NoticeBoardFacade 에서는  public Board[] getList() {  ..코드 ..} 이런식으로 넘겨줬던 코드를 Iterator에 맞게 다시 수정을 해야 할것이다. 다음과 같이 말이다.

public Iterator createIterator() {
    /* boards 객체를 가져오기 위한 코드 */
    return new NoticeBoardIterator(boards);
}

이런식으로 넘겨 받은 객체를 View 페이지에서는 간단하게

Iterator iterator = NoticeBoardFacade.createIterator();
while(iterator.hasNext()){
    Board board = (Board)iterator.next();
    board.getName();
    board.getSubject();
    .
    .
}

위와 같은 식으로 사용하면 된다. 이렇게 되면 사용자들은 내부에서는 어떻게 돌아가는지 알지 못해도 간단하게 사용 할 수가 있다. 이게 바로 Iterator 패턴인다.
내용은 그리 어렵지 않은데 설명은 무척이나 길게 한듯하다..ㅠㅠ
오늘도 패턴 하나를 알았다. 패턴 정말 재미있어진다.