모든 트랜잭션이 같은 방식으로 동작하는 건 아니다. 전체가 같이 실패하거나 성공하는 하나의 작업으로 묶인다는 점에서는 다를바 없겠지만, 세밀히 따져보면 몇 가지 차이점이 있다. 스프링은 트랜잭션의 경계를 설정할 때 네 가지 트랜잭션 속성을 지정할 수 있다. 또, 선언적 트랜잭션에서는 롤백과 커밋의 기준을 변경하기 위해 두 가지 추가 속성을 지정할 수 있다. 선언적 트랜잭션 기준으로 보자면 모든 트랜잭션 경계는 여섯 가지 속성을 갖고 있는 셈이다.

트랜잭션 속성의 지정은 tx/aop 스키마의 태그를 이용하는 경우에는 다음과 같이 <tx:method> 태그의 애트리뷰트로 지정할 수 있다. <tx:method> 의 애트리뷰트는 메소드 이름 패턴을 담은 name 애트리뷰트를 제외하면 모두 디폴트 값이 정의되어 있으므로 생략가능하다.


<tx:attributes>

    <tx:method name="..."

               read-only="..."

               isolation="..."

               propatation="..."

               timeout="..."

               rollback-for="..."

               no-rollback-for="..." />

</tx:attributes>


@Transactional 을 이용했을 때는 다음과 같이 애노테이션의 앨리먼트로 트랜잭션 속성을 지정할 수 있다.


@Transactional(readOnly=...,

               isolation=...,

               propagation=...,

               timeout=...,

               rollbackFor=..., rollbackForClassName=...,

               noRollbackFor=..., noRollbackForClassName=...)


모든 앨리먼트는 디폴트 값이 정의되어 있으므로 생략 가능하다. 이제 트랜잭션 속성에 대해 자세히 알아보자.


트랜잭션 전파(propagation)


이제 트랜잭션을 시작하거나 기존 트랜잭션에 참여하는 방법을 결정하는 속성이다.선언적 트랜잭션 경계설정 방식의 장점은 여러 트랜잭션 적용 범위를 묶어서 커다란 트랜잭션 경계를 만들 수 있다는 점이다. 트랜잭션 경계의 시작 지점에서 트랜잭션 전파 속성을 참조해서 해당 범위의 트랜잭션을 어떤 식으로 진행시킬지 결정할 수 있다.


스프링이 지원하는 트랜잭션 전파 속성은 다음 여섯 가지가 있다. 모든 속성이 모든 종류의 트랜잭션 매니저와 데이터 액세스 기술에서 다 지원되진 않음을 주의해야 한다. 각 트랜잭션 매니저의 API문서에는 사용 가능한 트랜잭션 전파 속성이 설명되어 있으니 사용하기 전에 꼭 참고해 봐야 한다.


 <tx:method> 에서는 propagation 애트리뷰트 값으로, @Transactional 에서는 propagation 앨리먼트로 지정한다. propagation 앨리먼트의 이늄 값은 org.springframework.transaction.annotation.Propagation 에 정의된 것을 사용한다.


REQUIRED


디폴트 속성이다. 모든 트랜잭션 매니저가 지원하며, 대개 이속성이면 충분하다. 미리 시작된 트랜잭션이 있으면 참여하고 없으면 새로 시작한다. 자연스럽고 간단한 트랜잭션 전파 방식이지만 사용해보면 매우 강력하고 유용하다는 사실을 알 수 있다. 하나의 트랜잭션이 시작된 후에 다른 트랜잭션 경계가 설정된 메소드를 호출하면 자연스럽게 같은 트랜잭션으로 묶인다.


SUPPORTS


이미 시작된 트랜잭션이 있으면 참여하고 그렇지 않으면 트랜잭션 없이 진행하게 만든다. 트랜잭션이 없긴 하지만 해당 경계 안에서 Connection이나 하이버네이트 Session 등을 공유할 수 있다.


MANDATORY


REQUIRED와 비슷하게 이미 시작된 트랜잭션이 있으면 참여한다. 반면에 트랜잭션이 시작된 것이 없으면 새로 시작하는 대신 예외를 발생시킨다. 혼자서는 독립적으로 트랜잭션을 진행하면 안 되는 경우에 사용한다.


REQUIRES_NEW


항상 새로운 트랜잭션을 시작한다. 이미 진행 중인 트랜잭션이 있으면 트랜잭션을 잠시 보류시킨다. JTA 트랜잭션 매니저를 사용한다면 서버의 트랜잭션 매니저에 트랜잭션 보류가 가능하도록 설정되어 있어야 한다.


NOT_SUPPORTED


트랜잭션을 사용하지 않게 한다. 이미 진행 중인 트랜잭션이 있으면 보류시킨다.


NEVER


트랜잭션을 사용하지 않도록 강제한다. 이미 진행 중인 트랜잭션도 존재하면 안된다 있다면 예외를 발생시킨다.


NESTED


이미 진행중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다. 중첩 트랜잭션은 트랜잭션 안에 다시 트랜잭션을 만드는 것이다. 하지만 독립적인 트랜잭션을 마드는 REQUIRES_NEW와는 다르다.


중첩된 트랜잭션은 먼저 시작된 부모 트랜잭션의 커밋과 롤백에는 영향을 받지만 자신의 커밋과 롤백은 부모 트랝개션에게 영향을 주지 않는다. 예를 들어 어떤 중요한 작업을 진행하는 중에 작업 로그를 DB에 저장해야 한다고 해보자. 그런데 로그를 저장하는 작업이 실패하더라도 메인 작업의 트랜잭션까지는 롤백해서는 안되는 경우가 있다. 힘들게 처리한 시급한 작업을 단지 로그를 남기는 작업에 문제가 있다고 모두 실패로 만들 수는 없기 때문이다. 반면에 로그를 남긴 후에 핵심 작업에서 예외가 발생한다면 이때는 저장한 로그도 제거해야 한다. 바로 이럴 때 로그 작업을 메인 트랜잭션에서 분리해서 중첩 트랜잭션으로 만들어 두면 된다. 메인 트랜잭션이 롤백되면 중첩된 로그 트랜잭션도 같이 롤백되지만, 반대로 중첩된 로그 트랜잭션이 롤백돼도 메인 작업에 이상이 없다면 메인 트랜잭션은 정상적으로 커밋된다.


중첩 트랜잭션은 JDBC 3.0 스펙의 저장포인트(savepoint)를 지원하는 드라이버와 DataSourceTransactionManager 를 이용할 경우에 적용 가능하다. 또는 중첩 트랜잭션을 지원하는 일부 WAS의 JTA 트랜잭션 매니저를 이용할 때도 적용할 수 있다. 유용한 트랜잭션 전파 방식이지만 모든 트랜잭션 매니저에 다 적용 가능한 건 아니므로, 적용하려면 사용할 트랜잭션 매니저와 드라이버, WAS의 문서를 참조해 보고, 미리 학습 테스트를 만들어서 검증해봐야 한다.


트랜잭션 격리 수준(isolation)


트랜잭션 격리수준은 동시에 여러 트랜잭션이 진행될 때에 트랜잭션의 작업 결과를 여타 트랜잭션에게 어떻게 노출할 것인지를 결정하는 기준이다. 스프링은 다음 다섯 가지 격리수준 속성을 지원한다.


격리수준은 <tx:method>의 isolation 애트리뷰트와 @Transactional 의 isolation 앨리먼트로 지정할 수 있다.


DEFAULT


사용하는 데이터 액세스 기술 또는 DB 드라이버의 디폴트 설정을 따른다. 보통 드라이버의 격리수준은 DB의 격리수준을 따르는게 일반적이다. 대부분의 DB는 READ_COMMITTED를 기본 격리수준으로 갖는다. 하지만 일부 DB는 디폴트 값이 다른 경우도 있으므로 DEFAULT를 사용할 경우에는 드라이버와 DB의 문서를 참고해서 디폴트 격리수준을 확인해야 한다.


READ_UNCOMMITTED


가장 낮은 격리수준이다. 하나의 트랜잭션이 커밋되기 전에 그 변화가 다른 트랜잭션에 그대로 노출되는 문제가 있다. 하지만 가장 빠르기 때문에 데이터의 일관성이 조금 떨어지더라도 성능을 극대화할 때 의도적으로 사용하기도 한다.


READ_COMMITTED


실제로 가장 많이 사용되는 격리수준이다. 물론 스프링에서는 DEFAULT로 설정해둬도 DB의 기본 격리수준을 따라서 READ_COMMITTED로 동작하는 경우가 대부분이므로 명시적으로 설정하지 않기도 한다. READ_UNCOMMITTED와 달리 다른 트랜잭션이 커밋하지 않은 정보는 읽을 수 없다. 대신 하나의 트랜잭션이 읽은 로우를 다른 트랜잭션이 수정할 수 있다. 이 때문에 처음 트랜잭션이 같은 로우를 읽을 경우 다른 내용이 발견될 수 있다.


REPEATABLE_READ


하나의 트랜잭션이 읽은 로우를 다른 트랜잭션이 수정하는 것을 막아준다. 하지만 새로운 로우를 추가하는 것은 제한하지 않는다. 따라서 SELECT로 조건에 맞는 로우를 전부 가져오는 경우 트랜잭션이 끝나기 전에 추가된 로우가 발견될 수 있다.


SERIALIZABLE


가장 강력한 트랜잭션 격리수준이다. 이름 그대로 트랜잭션을 순차적으로 진행시켜 주기 때문에 여러 트랜잭션이 동시에 같은 테이블의 정보를 액세스하지 못한다. 가장 안전한 격리수준이지만 가장 성능이 떨어지기 때문에 극단적인 안전한 작업이 필요한 경우가 아니라면 자주 사용되지 않는다.


트랜잭션 제한시간(timeout)


이 속성을 이용하면 트랜잭션에 제한시간을 지정할 수 있다. 값은 초 단위로 지정한다. 디폴트는 트랜잭션 시스템의 제한시간을 따르는 것이다. 트랜잭션 제한시간을 직접 지정하는 경우 이 기능을 지원하지 못하는 일부 트랜잭션 매니저는 예외를 발생시킬 수 있다.


XML에서는 <tx:method> 의 timeout 애트리뷰트를 이용하고 @Transactional 애노테이션에는 timeout 엘리먼트로 지정할 수 있다.


읽기전용 트랜잭션(read-only, readOnly)


트랜잭션을 읽기 전용으로 설정할 수 있다. 성능을 최적화하기 위해 사용할 수도 있고 특정 트랜잭션 작업 안에서 쓰기 작업이 일어나는 것을 의도적으로 방지하기 위해 사용할 수도 있다. 트랜잭션을 준비하면서 읽기 전용 속성이 트랜잭션 매니저에게 전달된다. 그에 따라 트랜잭션 매니저가 적절한 작업을 수행한다. 그런데 일부 트랜잭션 매니저의 경우 읽기전용 속성을 무시하고 쓰기 작업을 허용할 수도 있기 때문에 주의해야 한다. 일반적으로 읽기 전용 트랜잭션이 시작된 이후 INSERT, UPDATE, DELETE 같은 쓰기 작업이 진행되면 예외가 발생한다. 


aop/tx 스키마로 트랜잭션 선언을 할 때는 이름 패턴을 이용해 읽기 전용 속성으로 만드는 경우가 많다. 보통 get이나 find 같은 이름의 메소드를 모두 읽기전용으로 만들어 사용하면 편리하다. @Transactional 의 경우는 각 메소드에 일일이 읽기 전용 지정을 해줘야 한다.


read-only 애트리뷰트 또는 readOnly 앨리먼트로 지정한다.


트랜잭션 롤백 예외(rollback-for, rollbackFor, rollbackForClassName)


선언적 트랜잭션에서는 런타임 예외가 발생하면 롤백한다. 반면에 예외가 전혀 발생하지 않거나 체크 예외가 발생하면 커밋한다. 체크 예외를 커밋 대상으로 삼은 이유는 체크 예외가 예외적인 상황에서 사용되기보다는 리턴 값을 대신해서 비즈니스적인 의미를 담은 결과를 돌려주는 용도로 많이 사용되기 때문이다. 스프링에서는 데이터 액세스 기술의 예외는 런타임 예외로 전환돼서 던져지므로 런타임 예외만 롤백 대상으로 삼은 것이다.


하지만 원한다면 기본 동작방식을 바꿀 수 있다. 체크 예외지만 롤백 대상으로 삼아야 하는 것이 있다면 XML의 rolback-for 애트리뷰트나 애노테이션의 rollbackFor 또는 rollbackForClassName 앨리먼트를 이용해서 예외를 지정하면 된다. 


rollback-for 나 rollbackForClassName 은 예외 이름을 넣으면 되고, rollbackFor 는 예외 클래스를 직접 넣는다.


<tx:method> 라면 다음과 같이 지정하면 된다.


<tx:method name="get*" read-only="true" rollback-for="NoSuchMemberException" />


@Transactional 에서는 다음과 같이 클래스 이름 대신 클래스를 직접 사용해도 된다.


@Transactional(readOnly=true, rollbackFor=NoSuchMemberException.class)


트랜잭션 커밋 예외


(no-rollback-for, noRollbackFor, noRollbackForClassName)


rollback-for 속성과는 반대로 기본적으로는 롤백 대상인 런타임 예외를 트랜잭션 커밋 대상으로 지정해 준다.


사용 방법은 rollback-for 와 동일하다.


이 여섯가지 트랜잭션 속성은 모든 트랜잭션 경계설정 속성에 사용할 수 있다. 하지만 모든 트랜잭션마다 일일이 트랜잭션 속성을 지정하는 건 매우 번거롭고 불편한 일이다. 세밀하게 튜닝해야 하는 시스템이 아니라면 메소드 이름 패턴을 이용해서 트랜잭션 속성을 한 번에 지정하는 aop/tx 스키마 태그 방식이 편리하다. 보통은 read-only 속성 정도만 사용하고 나머지는 디폴트로 지정하는 경우가 많다. 세밀한 속성은 DB나 WAS의 트랜잭션 매니저의 설정을 이용해도 되기 때문이다.


세밀한 트랜잭션 속성 지정이 필요한 경우에는 @Transactional 을 사용하는 편이 좋다. 대신 트랜잭션 속성이 전체적으로 어떻게 지정되어 있는지 한눈에 보기 힘들다는 단점이 있고, 개발자가 코드를 만들 때 트랜잭션 속성을 실수로 잘못 지정하는 등의 위험이 있기 때문에 사전에 트랜잭션 속성 지정에 관한 정책이나 가이드라인을 잘 만들어 둬야 한다.

Request 객체의 메소드
return String getParameter(name) // 파라미터 변수 name에 저장된 변수를 얻어내는 메소드로, 이때 변수의 값은 String으로 리턴된다. String getParameterValues(name) // 파라미터 변수 name에 저장된 모든 변수값을 얻어내는 메소드로, 이때 변수의 값은 String 배열로 리턴된다. checkbox에서 주로 사용된다. Enumeration getParameterNames() // 요청에 의해 넘어오는 모든 파라미터 변수를 Enum타입으로 리턴한다. String Protocol() // 웹 서버로 요청 시, 사용 중인 프로토콜을 리턴한다. String getServerName() // 웹 서버로 요청 시, 서버의 도메인 이름을 리턴한다. String getMethod() // 웹 서버로 요청 시, 요청에 사용된 요청 방식(GET, POST, PUT 등)을 리턴한다. String QueryString() // 웹 서버로 요청 시, 요청에 사용된 QueryString을 리턴한다. String getRequestURI() // 웹 서버로 요청 시, 요청에 사용된 URL 로부터 URI 값을 리턴한다. String getRemoteAddr() // 웹 서버로 정보를 요청한 웹 브라우저의 IP주소를 리턴한다. int ServerPort() // 웹 서버로 요청 시, 서버의 Port번호를 리턴한다. String getContextPath() // 해당 JSP 페이지가 속한 웹 어플리케이션의 콘텍스트 경로를 리턴한다. String getHeader(name) // 웹 서버로 요청 시, HTTP 요청 헤더(header)의 헤더 이름인 name에 해당하는 속성값을 리턴한다. Enumeration HeaderNames() // 웹 서버로 요청 시, HTTP 요청 헤더(header)에 있는 모든 헤더 이름을 리턴한다.
Response 객체의 메소드
return void setHeader(name, value) // 헤더 정보의 값을 수정하는 메소드로, name에 해당하는 헤더 정보를 value값으로 설정한다. void setContentType(type) // 웹 브라우저의 요청의 결과로 보일 페이지의 contentType을 설정한다. void sendRedirect(url) // 페이지를 이동시키는 메소드로, url로 주어진 페이지로 제어가 이동한다.
Session 객체의 메소드
return String getId() // 해당 웹 브라우저에 대한 고유한 세션 ID를 리턴한다. long getCreationTime() // 해당 세션이 생성된 시간을 리턴한다. long getLastAccessedTime() // 웹 브라우저의 요청이 시도된 마지막 접근시간을 리턴한다. void setMaxInactiveInterval(time) // 해당 세션을 유지할 시간을 초단위로 설정한다. int getMaxInactiveInterval() // 기본값은 30분으로 setMaxInactiveInterval(time) 로 지정된 값을 리턴한다. boolean isNew() // 현재의 웹 브라우저가 새로 부른 즉, 새로 생성된 세션의 경우 true 값을 리턴한다. void invalidate() // 현재 정보의 유지로 사용 시, 설정된 세션의 속성 값을 모두 제거한다. 주로 세션을 무효화 시킬때 사용 HttpSession session = request.getSession(false); //기존 세션 객체가 있으면 그 걸 리턴, 없으면 null 리턴


XFF 는 HTTP Header 중 하나로 HTTP Server 에 요청한 clinet 의 IP 를 식별하기 위한 사실상의 표준이다.

 

웹 서버나 WAS 앞에 L4 같은 Load balancers 나 Proxy server(HAProxy), caching server(Varnish), HTTP 서버용 WAS Connector(웹로직 커넥터 - mod_wl, 톰캣 커넥터 - mod_jk 등) 등이 있을 경우

이런 제품들은 웹서버/WAS 에 HTTP 나 전용 프로토콜(AJP)로 요청을 보낸후에 받은 결과를 가공하여 클라이언트에 재전송하게 된다.

이로 인해 처리한 웹 서버나 WAS에서 request.getRemoteAddr(); 등으로 클라이언트 IP를 얻을 경우 L4 나 Proxy 의 IP 를 얻게 되는데 이는 원하는 결과가 아니다.

 

X-Forwarded-For는 이 문제를 해결하기 위해 사용하는 http header 로 squid caching server 에서 처음 사용되었다.

다음과 같이 콤마를 구분자로 client 와 proxy IP 가 들어가게 되므로 첫번째 IP 를 가져오면 클라이언트를 식별할 수 있다.

X-Forwarded-For: client, proxy1, proxy2

 

WAS 에서 사용

여기까지 읽고 웹 어플리케이션을 개발할 경우 client ip 를 식별할 필요가 있다면 먼저 저 헤더가 있는지 확인한 후에 없으면 getRemoteAddr() 로 IP 를 얻으면 되겠지라고 생각할 수도 있겠지만 이게 끝은 아니다.

XFF 는 사실상의 표준이지 정식 RFC 에 포함된게 아니므로 대개는 착실하게 저 헤더를 사용하지만 엉뚱한 헤더를 사용하는 제품들이 있다.

그중에 하나인 WebLogic Connector(mod_wl) 는 저 헤더를 사용하지 않고 WL-Proxy-Client-IP 나 Proxy-Client-IP  같은 전혀 엉뚱한 헤더를 사용하므로 만약 만드는 웹 어플리케이션이 

WebServer, WAS, L4, proxy 종류에 상관없이 client IP 를 잘 가져오기를 바란다면 다음과 같은 순서로 IP 를 얻어내야 한다.

 

 String ip = request.getHeader("X-Forwarded-For");
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
     ip = request.getHeader("Proxy-Client-IP"); 
 
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
     ip = request.getHeader("WL-Proxy-Client-IP"); 
 
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
     ip = request.getHeader("HTTP_CLIENT_IP"); 
 
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
     ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 
 
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
     ip = request.getRemoteAddr(); 
 }

이외에도 X-Real-IP 나 X-RealIP 라는 헤더를 사용하는 제품도 있다고 한다.

 

Apache httpd Web Server 에서 사용

아파치 웹 서버에서는 LogFormat 지시자나 접근 권한 체크시 Remote Address 를  사용하는데 앞에 Reverse Proxy가 있다면 의도한 대로 동작하지 않으므로 XFF 헤더를 사용하도록 수정해야 한다.

 

로그포맷

기본 로그포맷은 %h 로 리모트 Address 를 사용하므로 다음과 같이 %{X-Forwarded-For}i 를 사용하도록 수정한다.

## 수정전
## LogFormat "%h %l %u %t \"%r\" %>s %b" common
  
## 수정후
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" common

접근 제어(ACL)

ACL이 필요할 경우 다음과 같이 전역 변수를 설정하고 ACL 이 필요한 곳에서 이 변수를 사용하는게 편리하다.

SetEnvIf X-Forwarded-For ^192\.168\.1\. admin_1
SetEnvIf X-Forwarded-For ^192\.168\.2\. admin_2
  
<Files wp-config.php>
    order Deny,Allow
    deny from all
</Files>
 
## 워드프레스 로그인은 내부 IP 에서만 허용
<Files ~ "^wp-login.php">
    Order Deny,Allow
    Deny from all
## 내부 IP 만 관리자 로그인 허용
    Allow From env=admin_1
    Allow From env=admin_2
</Files>

 

nginx

nginx 는 --with-http_realip_module 옵션을 주고 컴파일해야 실제 ip 를 얻어올 수 있다. 배포판에 포함된 nginx 는 기본 컴파일 옵션일것이라고 생각되며 다음 명령어로 지원 여부를 확인할 수 있다.

nginx -V

 

nginx 가 지원한다면 다음 설정을 nginx.conf 에 넣어주면 실제 ip 가 로그 파일에 기록된다.

http {
set_real_ip_from   127.0.0.1; # proxy/L4 서버 IP
real_ip_header      X-Forwarded-For; #proxy/L4 가 실제 IP 를 설정하는 HTTP Header


'Server Enterprise > Java' 카테고리의 다른 글

[Split] | 자르기  (0) 2018.04.26
[Java] Json 파싱  (0) 2018.03.05
[알고리즘] 문제 출제 및 유용한 사이트  (0) 2016.08.08
[Java] Design Pattern  (0) 2016.07.07
[Book] 알고리즘 관련 서적 for java  (0) 2016.07.05

1. getSession(), getSession(true)

 - HttpSession이 존재하면 현재 HttpSession을 반환하고 존재하지 않으면 새로이 세션을 생성합니다


2. getSession(false)

 - HttpSession이 존재하면 현재 HttpSession을 반환하고 존재하지 않으면 새로이 생성하지 않고 그냥 null을 반환합니다


3. 사용 예

HttpSession session = request.getSession();

HttpSession session = request.getSession(true);

위는 동일한 결과를 반환합니다

새로 생성된 놈인지 확인은 session.isNew() 로 가능합니다

그리고 getSession(), getSession(true)는 null 체크없이 바로 getAttribute()를 사용해도 무방하지만, getSession(false)는 null을 리턴할수 있기 때문에 null체크를 해야 합니다.

HttpSession session = request.getSession(false);

if (session != null)

    User user = (User) session.getAttribute("User");

환경

java 1.7.0

maven 3.2.2

단순 참조만 필요한 경우

maven repository 가 없는 로컬 jar 파알을 maven 프로젝트에 추가 하기 위해서는 사설 repository를 만드는 방법도 있지만

다음과 같이 "dependency" 정의 시 scope 노드와 systemPath 노드를 사용하여 프로젝트에 포함된 jar 파일을 지정하여 줄 수 있다.

<dependency>
    <groupId>smack</groupId>
    <artifactId>smack-custom</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/smack-custom.jar</systemPath>
</dependency>

groupId, artifactId, version 은 임의로 정의해도 무방하다

${project.basedir} 는 프로젝트의 ROOT 패스

로컬을 Repository 를 활용하는 방법

위와 같이 처리하는 경우는 문제점이 있다. scrop 의 system 이기 때문에 maven 빌드 시 해당 jar 파일이 포함되지 않는다.

이런 경우는 pom.xml 에 다음과 같이 정의하여 로컬을 repositoy로 활용하는 방법도 있다.

<dependency>
    <groupId>smack</groupId>
    <artifactId>smack-custom</artifactId>
    <version>1.0.0</version>
</dependency>
<repository>
	<id>in-project</id>
	<name>custom jars</name>
	<url>file://${project.basedir}/lib</url>
</repository>

이 때 ${project.basedir}/lib 는 maven 디렉토리 구조를 따르도록 구성해주어야 한다.

위의 예제에서는 디렉토리 및 파일명은 다음과 같이 구성해야 한다.

${project.basedir}/lib/smack/smack-custom/1.0.0/smack-custom-1.0.0.jar

만일 jenkins에서 maven 빌드를 하는 경우라면 다음과 같이 repository를 하나 더 추가해준다.

<repository>
	<id>in-project-jenkins</id>
	<name>custom jars-jenkins</name>
	<url>file://${JENKINS_HOME}/jobs/${JOB_NAME}/workspace/lib</url>
</repository>


'Server Enterprise > Gradle & Maven' 카테고리의 다른 글

[Gradle] cache 삭제  (0) 2021.08.12
[Maven] M2Eclipse project 생성 3  (0) 2015.08.26
[Maven] M2Eclipse project 생성 2  (0) 2015.08.26
[Maven] M2Eclipse project 생성 1  (0) 2015.08.26
[MAVEN] 설치 및 이클립스 연동  (0) 2015.08.17

Spring + ibatis/mybatis 연동에 필요한 JDBC 라이브러리 파일들을 

각 DBMS별로 pom.xml에 등록을 위한 포스팅 해보도록 하겠습니다.


연동하고자 하는 JDBC 라이브러리는 

MySQL, Oracle, MSSQL JDBC를 메이븐을 통해서 받도록 하겠습니다.


먼저 Maven에서 기본적으로 제공해주는 MySQL JDBC 라이브러리를 등록해보도록 하겠습니다.



MySQL JDBC Dependency 등록


1
2
3
4
5
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.31</version>
</dependency>




상단 코드를 작성하고 저장을 해주셨다면 


Properties -> Java Build Path -> Libraries탭에서 Maven Dependencies를 확인 해보시면  

MySQL JDBC가 등록된 것을 확인하실 수 있을겁니다.









ORACLE JDBC Dependency 등록


ojdbc jar 파일을 Maven Repository 사이트에서 검색하여 나오는 dependency로는 라이브러리 다운로드를 받을 수 없습니다.



1
2
3
4
5
<dependency>
    <groupId>ojdbc</groupId>
    <artifactId>ojdbc</artifactId>
    <version>14</version>
</dependency>



"Missing artifact ojdbc:ojdbc:jar:14" 에러가 날 것이므로 

상단 코드 대신 다른 dependency를 등록 해주도록 합니다.



1
2
3
4
5
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc14</artifactId>
     <version>10.2.0.4.0</version>
</dependency>



위코드를 작성하셔도 아직은 dependency 코드부분에 여전히 

"Missing artifact com.oracle:ojdbc14:jar:10.2.0.4.0" 오류가 나타날 것입니다.

<properties> 바로 위에 다음코드를 추가해주세요



1
2
3
4
5
6
<repositories>
    <repository>
        <id>mesir-repo</id>
    </repository>
</repositories>



그럼 오라클의 dependency 오류는 사라질 것이며

다음처럼 ojdbc14.jar 라이브러리가 등록될 것입니다.






MSSQL JDBC Dependency 등록



MSSQL JDBC 연동을 위한 라이브러리인 sqljdbc는 메이븐에서 제공을 하지 않아 

별도로 로컬상의 Maven repository로 연동이 되어야 합니다.


제일먼저 SQL Server용 JDBC 를 다운로드 받도록 합니다.


http://www.microsoft.com/ko-kr/download/details.aspx?id=11774







상단 URL 접속 후 다운로드 버튼을 클릭합니다.







윈도우 기준으로 설명하기에 exe 파일 체크 후 Next버튼을 클릭하여 파일다운로드를 받았습니다.


다운로드 받은 exe파일을 실행을 합니다.







Unzip해준 경로를 보면 sqljdbc_4.0 디렉토리가 생성되어있습니다.

kor 디렉토리를 들어가시면 sqljdbc.jar 파일과 sqljdbc4.jar 파일이 존재하는데 아마 요즘 프로젝트들은

JRE 6.0 이상의 환경에서 작업하므로 sqljdbc4.jar 파일을 등록시켜주면 될겁니다.


아파치 메이븐으로 install 해주기위하여 

하단 사이트에 접속하여 메이븐 파일을 다운로드 받도록 합니다.


http://maven.apache.org/download.cgi








압축을 해제 후 CMD 창을 띄워줍니다.


다운받아서 해제한 apache-maven의 bin디렉토리까지 이동을 합니다.






다음 명령어를 실행합니다.


1
mvn install:install-file -Dfile=D:\sqljdbc_4.0\kor\sqljdbc4.jar -Dpackaging=jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.0









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom
---
[INFO] Installing D:\sqljdbc_4.0\kor\sqljdbc4.jar to C:\Users\jgh\.m2\repository
\com\microsoft\sqlserver\sqljdbc4\4.0\sqljdbc4-4.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.960 s
[INFO] Finished at: 2014-11-14T01:23:05+09:00
[INFO] Final Memory: 5M/15M
[INFO] ------------------------------------------------------------------------



로그가 출력되면 정상 설치 된것입니다.

그럼 MSSQL JDBC 라이브러리 Dependency를 등록해보도록 하겠습니다.



1
2
3
4
5
<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>sqljdbc4</artifactId>
    <version>4.0</version>
</dependency>



위와같이 pom.xml에 등록해주면 오류없이 정상적으로 라이브러리 추가가 된 것을 확인 할 수 있습니다.









MySQL, Oracle, MSSQL JDBC 라이브러리 파일을 pom.xml에 등록하는 방법에 대하여 포스팅해보았습니다.


다음장은 spring3 + mybatis 연동설정에 대하여 포스팅하도록 하겠습니다.



1. 설치

STS는 스피링을 사용하는 개발자에게 특화된 Eclipse 기반의 IDE이다.

다운로드는 아래 링크를 통해 받을 수 있다.


Spring Boot 프로젝트는 Spring의 경량화 버전이다.

기본적으로 Tomcat을 내장하고 있어 프로젝트를 구동하기 편하다.


https://spring.io/tools


2. 프로젝트 만들기


Package Explorer에서 오른쪽 버튼을 클릭하고

New - Sping Starer Project를 선택한다.




선택하면 아래와 같은 팝업이 뜨는데

Name과 Artifact는 프로젝트를 유니크하게 구별하는 식별자이다.


입맛에 맞게 설정해주자.





다음은 이 프로젝트에서 사용할 모듈설정 화면이다.

여기서는 Web 정도만 선택한다.

추후 Pom.xml에서 추가할 수 있다.




처음 프로젝트를 생성하면 프로젝트 구조는 아래와 같다.



여기서 Controller를 만들기 위해

Controller Package를 만들고 그 아래 HelloWorldContoller Class를 하나 만든 다음

아래와 같이 코딩하자.


중요한 점은 public class위에 

@RestController 를 달았다는 것과


public String HelloWolrd위에 

@RequestMapping 를 달았다는 것이다.


이 2가지 Annotation은 

컨트롤러를 구성하는데 꼭 필요한 요소로


Controller로 쓰는 클래스위에는

Controller는 URL을 입력했을 떄 처음 그 요청을 받아 처리해주는 로직을 담은

클래스 정도로 생각하면 된다.


아래와 같이 RestController Annotation을 붙여주고

URL을 매핑 시켜주는 RequstMapping Annotation을 통해

그 내부를 구성한다.



이렇게 한다음 Rus As - Spring boot App을 눌러 프로젝트를 구동시키고

웹 브라우져로 위에 적은 URL대로 Request를 해보면

아래와 같은 메시지가 뜨는 것을 볼수 있다.


리턴은 Vo로도 가능하다.

Vo를 리턴하면 Json형식으로 리턴된다.




오일러 프로젝트(Project Euler)


수학적인 문제들을 프로그래밍으로 해결하는 퀴즈 풀이 사이트


Synap에서 한글로 번역한 사이트를 제공하고 있다. 본 사이트의 모든 문제가 번역되어 있진 않지만 현재 100여개의 문제가 번역되어 있고 많은 사람들이 사용하고 있다. 자신이 원하는 언어로 문제를 풀고 답만 입력하면 된다. 입력한 답이 정답일 경우 다른 사람들이 문제를 푼 코드들을 볼 수 있다.


(Project Euler @kr : http://euler.synap.co.kr/)


(Project Euler @net : https://projecteuler.net/)





알고 스팟(Algospot)


프로그래밍 대회에서 배우는 '알고리즘 문제해결 전략'의 저자 구종만씨가 운영하는 사이트


C, Java, Python, C++, Scala, Javascript, Rust, Haskell, Go등 다양한 언어로 문제 풀이가 가능하며 문제별 채점결과(속도, 크기) 랭킹을 제공해준다. 다양한 알고리즘 대회의 양질의 문제들을 제공해 주고 있다. 알고스팟 캘린더에는 알고리즘 대회 스케쥴을 제공해 주고 있다. 국내 알고리즘 사이트 중에서는 Dovelet과 함께 양강체제를 구축하고 있다. 코딩 테스트를 준비하고 있다면 반드시 풀어봐야 할 사이트.


(Algospot : https://algospot.com/)




더블릿(Dovelet)


알고 스팟과 양대산맥을 이루는 알고리즘 트레이닝 사이트


C, Java, Python, C++, Perl로 문제 풀이가 가능하다. 1~30계단, 옥상으로 단계를 구분해서 운영하고 있는데 무료로 1~3계단, 옥상 레벨의 문제를 풀 수가 있다. 정회원이 되려면 소정의 금액을 지불해야 한다. 랭킹 30위 안에 들면 1년 이상 무료로 이용이 가능하다. 코딩 테스트를 준비하고 있다면 반드시 풀어봐야 할 사이트.


(Dobelet : http://59.23.113.171/index.php)




코딜리티(Codility)


해외에서 정말 유명한 알고리즘 문제 사이트


문제가 영어로 제공되어 해석의 어려움이 있을 수는 있지만 Web에서 코드를 작성하고 컴파일 결과를 확인할 수 있는 장점이 있다. 코드를 제출하게 되면 시간 복잡도와 공간 복잡도를 서버에서 채점하고 등급을 알려준다. 많은 언어를 제공하며 완성도가 높은 사이트이다. 마찬가지로 코딩 테스트를 준비하고 있다면 반드시 풀어봐야 할 사이트.


(Codility : https://codility.com/)




코딩도장


운동 도장에 매일 다니며 수련하는 것 같이 프로그래밍 문제풀이를 통해서 코딩 실력을 수련하자는 목표로 만들어진 사이트


구글, 페이스북등 유명 해외 기업과 국내 유명 기업의 코딩 문제들도 수록되어 있다. 채점은 되지 않지만 풀이를 댓글로 작성할 수 있고 다른 사람들의 풀이도 볼 수 있다.


(코딩도장 : http://codingdojang.com/)

1. 자바 디자인 패턴 1 – Iterator

 

2. 자바 디자인 패턴 2 – Adapter

 

3. 자바 디자인 패턴 3 - Factory Method

 

4. 자바 디자인 패턴 4 - Template Method

 

5. 자바 디자인 패턴 5 – Singleton

 

6. 자바 디자인 패턴 6 – Strategy

 

7. 자바 디자인 패턴 7 – Composite

 

8. 자바 디자인 패턴 8 – Decorator

 

9. 자바 디자인 패턴 9 - Chain of Responsibility

 

10. 자바 디자인 패턴 10 – Facade


11. 자바 디자인 패턴 11 – Observer

 

12. 자바 디자인 패턴 12 – Prototype

 

13. 자바 디자인 패턴 13 – Flyweight

 

14. 자바 디자인 패턴 14 – Builder

 

15. 자바 디자인 패턴 15 – Mediator

 

16. 자바 디자인 패턴 16 – Visitor



http://www.sws.bfh.ch/~amrhein/ADP/HeadFirstDesignPatterns.pdf


다양한 예제로 학습하는 데이터 구조와 알고리즘 for Java

+ Recent posts