<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m  (%F:%L) \n"/>
        
    
	
	
		
		
			<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m  (%F:%L) \n" />
		
	
	
	
		
		
			<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m  (%F:%L) \n" />
		
	
	
	
        <priority value="debug" />
		<appender-ref ref="FILE_USER" />
    
    
    
         <priority value="debug" />
		 <appender-ref ref="FILE_DB" />
    
    
        <priority value ="error" />
        <appender-ref ref="STDOUT" />
    
    


// foreach
public Person(String fn, String ln, int a, Person... kids)
{
        this.firstName = fn; this.lastName = ln; this.age = a;
        for (Person child : kids)
            children.add(child);
}

// 배열 역순
Collections.reverse(list);

[출처] http://blog.naver.com/galahad76?Redirect=Log&logNo=20042609592


유닉스에서 자바 이미지 객체를 사용하려 할때 다음과 같은 에러가 발생한다.

 

Exception in thread "main" java.lang.InternalError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.

 

이것은 일종의 JDK의 버그이다. 원인은 자바가 BufferedImage 를 생성하고 실제로 Graphics 객체를 얻어오기 위해 getGraphics나 createGraphics 메소드를 부를때, 실제로 display하거나 mouse, keyboard 자원을 하나도 쓰지 않을 것임에도 불구하고 내부적으로 AWT Toolkit이 그것들에 대한 자원을 얻어오게 되어있었기 때문이다. 

Sun에서는 이걸 버그로 취급하며 해결 방법은 2가지가 있다. 


1. JRE 1.3 이하 일경우 www.x.org 에서 다운로드 받을 수 있는 Xvfb 라는 것을 사용하는 방법이다. 이것은 X-server 에뮬레이터이다.



2. JRE 1.4 이상에서  Headless AWT Toolkit을 이용해서 이 문제를 해결한다. 파일을 실행할때 간단히 -Djava.awt.headless=true 옵션을 주는것만으로 가능하다.


Tomcat

catalina.sh 파일에 CATALINA_OPTS=-Djava.awt.headless=true를 추가하고 재구동하면 된다.



[출처] http://blog.naver.com/galahad76?Redirect=Log&logNo=20042609592


Console

java -Djava.awt.headless=true "class 파일명"


JEUS

Tmax에서 답변 기다리는대로 업데이트 하겠음.

시스템팀에서 알아서 해줬음 ㅡㅡ;



Struts 이용 중 Redirect 시 parameter 을 넘겨야 할 필요성이 있다.

struts 1.2 버전 밑에서는 아래와 같이 한다.

return new ActionForward("/index.do?param=value", true);

하지만 이 방법은 이동 URL을 JAVA 파일에 정의하게되어  struts의 struts-config.xml 설정파일과 별도로 관리해야 하는 단점이 있다.


그래서 struts 1.2 이상에서부터는 아래와 같은 방법을 제공한다.

ActionRedirect redirect = new ActionRedirect( mapping.findForward("success") );
redirect.addParameter("param", "123");
return redirect;

"success" 이름으로 struts-config.xml 에 정의된 URL에 param 이라는 parameter 정보를 붙여준다.

또한 1.2 이후 부터는 단순 jsp 이동 시 아래 방법은 이용 못하고, 
<action path="/index2" type="org.apache.struts.actions.ForwardAction" forward="/index.jsp" />

이 방법을 사용해야 된다.
<action path="/index" forward="/index.jsp" />

int ramdomInt = (int) (Math.random() * (899999999 - 800000000 + 1)) + 800000000;
Spring Messages 설정 시 아래와 같은 오류가 날 경우,

org.apache.jasper.JasperException: No message found under code, No message found under code ... for locale 'ko'.

[web.xml] 에 아래 설정을 넣어줘야 함.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

[JAVA 로만 이용(]
 
public static void main(String[] args) {
	
	JavaMailSender sender = getSender();
	/*
	SimpleMailMessage msg = new SimpleMailMessage();
	msg.setTo("ddakker@~");
	msg.setSubject("제목");
	msg.setFrom("ddakker@~");
	msg.setText("내용");
	sender.send(msg);
	*/
	
	MimeMessage msg = sender.createMimeMessage();
	MimeMessageHelper helper;
	try {
		helper = new MimeMessageHelper(msg, true, "UTF-8");
		helper.setSubject("제목");
		helper.setTo("ddakker@~");
		helper.setFrom("ddakker@~");
		helper.setText("내용", true);
		sender.send(msg);
	} catch (MessagingException e) {
		e.printStackTrace();
	}
    
}

private static JavaMailSenderImpl getSender(){
	JavaMailSenderImpl sender = new JavaMailSenderImpl();
	sender.setHost("도메인 및 아이피");
	sender.setUsername("계정 아이디");
	sender.setPassword("비밀번호");
	
	Properties props = new Properties();
	props.put("mail.smtp.auth", "true");
	
	sender.setJavaMailProperties(props);
	return sender;
}

[JAVA 와 Spring DI 와 함께 이용]

	
		${mailHost}
	
	
		${mailAdminId}
	
	
		${mailAdminPwd}
	
	
		
			true
		
	
 

 
JavaMailSender sender = (JavaMailSender) getBean("sender");

MimeMessage msg = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(msg, true, "UTF-8");
helper.setSubject(p_subject);
helper.setTo(p_to);
helper.setFrom(p_from);
helper.setText(p_message, true);
sender.send(msg);

1 : [Config] Table
     boardCode PK
N: [Board] Table
     BoardCode FK

Board를 조회 할 경우 항상 Config와 함께 JOIN이 필요 할 경우 Config Class 는 특별한 설정이 필요 없다.
Config 조회 할경우에는 단순히 Config 만 조회한다.

Board Class
     boardCode 변수를 생성할 필요 없다.


 
// fetch=FetchType.LAZY: 요청할때만 JOIN한다.,  EAGER: 무조껀 JOIN한다.
// cascade=CascadeType=ALL, MERGE, PERSIST, REFRESH, REMOVE
@ManyToOne(fetch=FetchType.LAZY, cascade = {CascadeType.REMOVE}, targetEntity=Config.class )
@JoinColumn(name = "boardCode")
@ForeignKey(name = "FK_CONFIG_BOARD_CODE")
private Config config; // getter, setter 만들어준다.


JOIN 시 FK로 Where을 걸 경우
 
Session session = getSession();
		
Criteria crit = session.createCriteria(Board.class, "B");
crit.createCriteria("Config", "C");
crit.add(Restrictions.eq("C.boardCode", boardCode));
crit.setFirstResult(firstIndex);
crit.setMaxResults(pageSize);
crit.addOrder(Order.desc("regdate"));

SELECT


select * from tbl_zipcode
Criteria crit = sess.createCriteria(Zipcode.class);
List<Zipcode> zipcodeList = crit.list();

select seq, zipcode, st_bunji, ed_bunji from tbl_zipcode
Criteria crit = sess.createCriteria(Zipcode.class);
  
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.id().as("seq"));
projectionList.add(Projections.property("zipcode").as("zipcode"));
projectionList.add(Projections.property("stBunji").as("stBunji"));
projectionList.add(Projections.property("edBunji").as("edBunji"));
  
crit.setProjection(projectionList);
crit.setResultTransformer(new AliasToBeanResultTransformer(Zipcode.class));
  
List<Zipcode> zipcodeList = crit.list();
 
원하는 칼럼을 뽑아낼 때 쓰는 ProjectionList와 Projections을 사용합니다.(테이블 하나 조회하면서는 안쓸듯...)

해보니까 Projections 에서 꼭 as() 를 사용해서 Zipcode 클래스의 필드명과 이름을 맞춰줘야 하더군요... -0-/

Projections.id() 와 Projections.property() 는 뭐가 다른지 아시겠죠? ㅎㅎ;; id() 가 PK가 되는 필드 입니다.


select count(*) from tbl_zipcode
Criteria crit = sess.createCriteria(Zipcode.class);
crit.setProjection( Projections.rowCount() );
  
List<Integer> zipcodeList = crit.list();
System.out.println("count : " + zipcodeList.get(0));

select count(seq) as count from tbl_zipcode
Criteria crit = sess.createCriteria(Zipcode.class);
crit.setProjection(Projections.count("seq").as("count"));
   
List<Integer> zipcodeList = crit.list();
System.out.println("count : " + zipcodeList.get(0));




ORDER BY

select * from tbl_zipcode order by seq desc
Criteria crit = sess.createCriteria(Zipcode.class);
crit.addOrder(Order.desc("seq"));
   
List<Zipcode> zipcodeList = crit.list();

Order.asc(String propertyName) 도 있습니다~ +_+




Criteria crit = sess.createCriteria(Zipcode.class);
List<Zipcode> zipcodeList = crit.list();

생략하겠습니다~


WHERE

where문은 Restrictions을 사용합니다. 내용이 많으니 자세한것은 API를 봐주세요~

select * from tbl_zipcode where seq = 1555
crit.add(Restrictions.eq("seq", 1555));

select * from tbl_zipcode where seq = 45
crit.add(Restrictions.idEq(45));    // idEq() 를 사용하면 PK 칼럼으로 검색합니다.

select * from tbl_zipcode where dong like '방화%'
crit.add(Restrictions.like("dong", "방화", MatchMode.START));    // '방화%'

MatchMode 종류는 ANYWHERE, END, EXACT, START 4가지 종류가 있습니다.

딱 보면 아시겠지만 '%방화%', '방화%', '방화', '%방화' 이렇게 됩니다.


select * from tbl_zipcode where sido = '서울' and zipcode like '157%'
crit.add(Restrictions.eq("sido", "서울"));
crit.add(Restrictions.like("zipcode", "157", MatchMode.START)); 

여러개의 조건을 사용할 때에는 계속 .add() 해주면 됩니다.


select * from tbl_zipcode where where (st_bunji = '514' and sido = '서울' and dong = '방화2동')
Map<String, String> m = new Hashtable<String, String>();
m.put("sido", "서울");
m.put("dong", "방화2동");
m.put("stBunji", "514");
  
crit.add(Restrictions.allEq(m));

여러개의 eq를 사용할 경우 Map 을 사용할 수 있습니다.


select * from tbl_zipcode where seq >= 5300
crit.add(Restrictions.ge("seq", new Integer(50300)));

주의 해야 할 것은 2번째 인자는 Object 형태라는 것입니다. +_+;

ge(>=), gt(>), le(<=), lt(<) 가 있습니다.

select * from tbl_zipcode where sido in ('서울', '부산')
String[] in = {"서울", "부산"};
crit.add(Restrictions.in("sido", in));    // Collection 또는 Object[] 사용 가능

select * from tbl_zipcode where ( sido = '서울' and zipcode like '157%' )
crit.add(
    Restrictions.conjunction()    // and 연산으로 그룹
        .add( Restrictions.eq("sido", "서울") )
        .add( Restrictions.like("zipcode", "157", MatchMode.START) )
);

and 조건을 여러개 사용할 경우 그냥 계속 .add() 해도 되지만 Restrictions.conjunction() 로 그룹할 수 있습니다.

Restrictions.conjunction() 은 and 로 그룹하고, Restrictions.disjunction() 은 or 로 그룹합니다.


select * from tbl_zipcode where ( (dong like '방화%' or dong like '%1동') and (zipcode like '157%' or zipcode like '431') )
crit.add(
    Restrictions.conjunction()
        .add(
            Restrictions.disjunction()
                .add(Restrictions.like("dong", "방화", MatchMode.START))
                .add(Restrictions.like("dong", "1동", MatchMode.END))
        )
        .add(
            Restrictions.disjunction()
                .add(Restrictions.like("zipcode", "157", MatchMode.START))
                .add(Restrictions.like("zipcode", "431", MatchMode.START))
        )
);

- 동이 '방화'로 시작하거나 '1동'으로 끝나고 우편번호가 157로 시작하거나 431로 시작하는 데이터를 조회 합니다.
- (동이 '방화'로 시작 or 동이 '1동'으로 끝) and (우편번호가 '157'로 시작 or 우편번호가 '431'로 시작)

정도가 되겠네요... (헷갈리.. ㅠㅠ)


select * from tbl_zipcode where st_bunji between '157' and '158'
crit.add(Restrictions.between("stBunji", "157", "158"));

select * from tbl_zipcode where ( dong like '방%' and dong like '%1동' )
crit.add( Restrictions.and( Restrictions.eq("sido", "서울"), Restrictions.like("dong", "1동", MatchMode.END) ) );

Restrictions.and(조건, 조건) 은 두개의 조건을 and 로 그룹합니다.
Restrictions.or(조건, 조건) 은 두개의 조건을 or 로 그룹합니다.


select * from tbl_zipcode where not ( sido in ('서울', '부산') )
crit.add( Restrictions.not( Restrictions.in("sido", new String[] { "서울", "부산" }) ) );


INNER JOIN

키를 기준으로 일치하는 데이터만 가져옵니다. (다 아시졍? +_+)

// select * from tbl_emp e
Criteria crit = sess.createCriteria(Emp.class, "e");
// join tbl_dept d on this.deptno = d.deptno
crit.createCriteria("dept", "d");
   
// Result 를 Map 형태로 변환
crit.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);

List<Map<String, Object>> joinList = crit.list();

int size = joinList.size();
for(int i=0 ; i < size ; i++) {
   Map<String, Object> map = joinList.get(i);
   Emp emp = (Emp) map.get("e");
   Dept dept = (Dept) map.get("d");

   System.out.println("row: " + (i+1));
   System.out.println(emp);
   System.out.println(dept);
}


Criteria crit = sess.createCriteria(Emp.class);

Session.createCriteria(클리스명) 를 통해서 생성한 Critereria 객체에 다시 createCriteria(String associationPath, String alias) 를 사용해서 JOIN 을 하면 됩니다.

이렇게 JOIN 한 결과는 Emp 객체도 Dept 객체도 아니기 때문에, Criteria의 setResultTransformer 메소드를 사용하여 Criteria를 이용한 조회 결과를 별도 정의한 객체 형태나 Map 형태로로 전달받아야 하겠습니다.

근데 전 객체로 변형하는 법은 잘 안되서... 걍 Map 으로 ㄱㄱㄱ!

여기서 두번째 인자로 넣는 엘리어스명은 쿼리에서 쓰는 엘리어스명도 되지만 나중에 Map 에서 꺼 낼때의 키도 되기 때문에 꼭 지정해줘야 할 것입니다....

실행 되는 쿼리는 아래와 같습니다.

    select
        this_.empno as empno0_1_,
        this_.ename as ename0_1_,
        this_.job as job0_1_,
        this_.hire_date as hire4_0_1_,
        this_.deptno as deptno0_1_,
        d1_.deptno as deptno1_0_,
        d1_.dname as dname1_0_,
        d1_.loc as loc1_0_ 
    from
        tbl_emp this_ 
    inner join
        tbl_dept d1_ 
            on this_.deptno=d1_.deptno


이러면 당연히 부서가 없는 'TOM' 은 목록에 나오지가 않겠죠? 만약 사원 목록을 본다면 부서가 없는 사원이 나오면 안되겠죠?



LEFT JOIN

두개의 테이블을 조인할 때 왼쪽 테이블을 기분으로 오른쪽 테이블을 조인 시키는 LEFT JOIN 을 해봅시다...

createCriteria(String associationPath, String alias, int joinType) 를 사용하면 됩니다.

// select * from tbl_emp e
Criteria crit = sess.createCriteria(Emp.class, "e");
// join tbl_dept d on this.deptno = d.deptno
crit.createCriteria("dept", "d", Criteria.LEFT_JOIN);
   
// Result 를 Map 형태로 변환
crit.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);

List<Map<String, Object>> joinList = crit.list();

int size = joinList.size();
for(int i=0 ; i < size ; i++) {
   Map<String, Object> map = joinList.get(i);
   Emp emp = (Emp) map.get("e");
   Dept dept = (Dept) map.get("d");

   System.out.println("row: " + (i+1));
   System.out.println(emp);
   System.out.println(dept);
}

실행되는 쿼리는 아래와 같습니다. 엘리어스 사용에 주의 하세요~

    select
        this_.empno as empno0_1_,
        this_.ename as ename0_1_,
        this_.job as job0_1_,
        this_.hire_date as hire4_0_1_,
        this_.deptno as deptno0_1_,
        d1_.deptno as deptno1_0_,
        d1_.dname as dname1_0_,
        d1_.loc as loc1_0_ 
    from
        tbl_emp this_ 
    left outer join
        tbl_dept d1_ 
            on this_.deptno=d1_.deptno



Pagination

많은 자료를 조회할 때 일정한 양의 자료를 한 페이지만 보여주도록 하는 기능입니다.

꼭 필요한 기능이고, 그다지 복잡할 것도 없지만, 막상 쿼리 날리려면 DBMS 마다 쿼리도 틀리고... 쉽지 안쵸 ㅠ_ㅠ

하지만 하이버네이트에서는

setFirstResult(int firstResult) 과 setMaxResults(int maxResults) 메소드 두개면 해결 됩니다! ㅋㅋㅋ

전부터 해오던 우편번호 테이블 가지고 해봅시다...


Criteria crit = sess.createCriteria(Zipcode.class);
crit.setFirstResult(40);   // 시작 로우 라인 번호(?)
crit.setMaxResults(10);    // 시작 로우 라인 번호로 부터 몇개?!

List<Zipcode> list = crit.list();
   
int size = list.size();
for(int i=0 ; i < size ; i++) {
   Zipcode z = list.get(i);
   System.out.println(z.toString());
}

한 페이지에 10개씩 보여준다고 하고 4페이지의 내용을 보여주게 됩니다. 


페이징 처리가 되있는 우편번호 검색 페이지를 만들어봤습니다.


 pagination.war


몇개의 DMBS 에서 돌려보니까 아래와 같은 쿼리가 나오네요


MySQL 5.1.38
    select
        this_.seq as seq0_0_,
        this_.zipcode as zipcode0_0_,
        this_.sido as sido0_0_,
        this_.gugun as gugun0_0_,
        this_.dong as dong0_0_,
        this_.ri as ri0_0_,
        this_.bldg as bldg0_0_,
        this_.st_bunji as st8_0_0_,
        this_.ed_bunji as ed9_0_0_ 
    from
        tbl_zipcode this_ limit ?,
        ?


Oracle 10g Express Edition
    select
        * 
    from
        ( select
            row_.*,
            rownum rownum_ 
        from
            ( select
                this_.seq as seq0_0_,
                this_.zipcode as zipcode0_0_,
                this_.sido as sido0_0_,
                this_.gugun as gugun0_0_,
                this_.dong as dong0_0_,
                this_.ri as ri0_0_,
                this_.bldg as bldg0_0_,
                this_.st_bunji as st8_0_0_,
                this_.ed_bunji as ed9_0_0_ 
            from
                tbl_zipcode this_ ) row_ 
        where
            rownum <= ?
        ) 
    where
        rownum_ > ?


Microsoft SQL Server 2005
    select
        top 20 this_.seq as seq0_0_,
        this_.zipcode as zipcode0_0_,
        this_.sido as sido0_0_,
        this_.gugun as gugun0_0_,
        this_.dong as dong0_0_,
        this_.ri as ri0_0_,
        this_.bldg as bldg0_0_,
        this_.st_bunji as st8_0_0_,
        this_.ed_bunji as ed9_0_0_ 
    from
        tbl_zipcode this_



소스상에서 직접 호출이 아닌 특정 문자열을 획득 및 다이나믹하게 조합한 문자열의 함수를 호출 하고자 할때 이용한다.
(commons-beanutils-1.7.0.jar 파일 필요) 

ActionScript3 에서는 간단히 처리할 수 있는 방법이지만 java에서는 약간 볶잡한 것 같다.


	public String execute(){
		String voidTest = (String) MethodUtils.invokeMethod(this, "testFun", null);
		System.out.println("voidTest: " + voidTest);
			
		Object arr[] = new Object[2];
		arr[0] = 1;
		arr[1] = "str";
		String paramTest = (String) MethodUtils.invokeMethod(this, "testFun", arr);
		System.out.println("paramTest: " + paramTest);
	}

	public String testFun(){
		System.out.println("Test1Action.testFun()");
		return "zzzz";
	}
	
	public String testFun(int test, String str){
		System.out.println("Test1Action.testFun(int test=" + test + ", String str=" + str + ")");
		return "zzzz";
	}

+ Recent posts