캠핑과 개발


ckeditor를 사용하던 중에 파일 업로드와 관련하여 업로드 처리를 하였으나 업로드 후
이전 페이지에 완료된 값을 보내주는 리턴값에 대해서 한참 시간을 보냈다.

하지만 의외로 간단하게 함수 하나만 호출해 주면 된다.

String funcNum = request.getParameter("CKEditorFuncNum");
String fileUrl = 업로된 파일의 경로
out.write("<script>window.parent.CKEDITOR.tools.callFunction(" + funcNum + ", '" + url + "');</script>");


ibatis 작업중 로그를 보여줍니다.


사용법 
1. ibatis-2.3.0.677.jar 파일을 WEB-INF/lib 폴더 아래로 복사합니다.
2. log4j.properties 파일에 다음 줄을 추가해줍니다.

log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG

간혹 안나오는 경우는 log4j.jar 파일이 WEB-INF/lib 폴더에 존재하는지 확인하기 바란다.

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

스트링 배열을 리스트에 담는다.
 
String[] strs = {"1", "2", "3"};
java.util.List<String> list = new ArrayList<String>(Arrays.asList(strs));
if(list != null){
    for(int i = 0; i < list.size(); i++){
        System.out.println(list.get(i));
    }
}

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

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");


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


파일 하나만으로 jsp파일의 수정, 삭제, 보기가 가능한 프로그램
보통은 jsp파일의 내용을 보지 못하나 이프로그램을 업로드후에 파일의 내용을 볼수가 있다.
상당히 잘 만든 프로그램