라벨이 스프링인 게시물 표시

(스프링) Ioc컨테이너와 DI

이미지
<IOC 컨테이너를 통해 애플리케이션이 만들어지는 방식> 결국 스프링 애플리케이션이란, POJO클래스와 설정 메타정보를 이용해 IOC 컨테이너가 만들어주는 오브젝트의 조합이다. RootBeanDefinition을 보면 bean클래스가 private volatile Object beanClass; 로 되어있는 것을 볼 수 있다. 이는 volatile을 선언하게 되면 cpu cache에 해당 값을 저장하는 과정 없이 오직  MainMemory에서 값을 읽고, 쓰는 과정을 거친다. 즉, 멀티쓰레드에서 한개의 쓰레드가 read&write를 하더라도 다른 쓰레드에서 읽기를 하는 경우 값이 변하더라도 항상 일관된 값을 유지하게 해준다.

(스프링) JoinPoint의 사용

AOP관련해서 JoinPoint를 파라미터로 전달받을 경우 반드시 첫번째 파라미터로 지정해야 함 (그 외는 예외 발생) JoinPoint 인터페이스는 호출되는 대상 객체, 메소드 그리고 전달되는 파라미터 목록에 접근할 수 있는 메소드를 제공 Signature getSignature() - 호출되는 메소드에 대한 정보를 구함 Object getTarget() - 대상 객체를 구함 Object[] getArgs() - 파라미터 목록을 구함 org.aspectj.lang.Signature 인터페이스는 호출되는 메소드와 관련된 정보를 제공하기 위해 다음과 같은 메소드를 정의 1. String getName() - 메소드의 이름을 구함 2. String toLongname() - 메소드를 완전하게 표현한 문장을 구함(메소드의 리턴타입, 파라미터 타입 모두 표시) 3. String toShortname() - 메소드를 축약해서 표현한 문장을 구함(메소드의 이름만 구함)

(스프링) @ControllerAdvice를 이용한 공통 익셉션 처리

이미지
컨트롤러 클래스에 @ExceptionHandler 애노테이션을 적용하면 해당 컨트롤러에서 발생한 익셉션만을 처리한다. 그런데 다수 컨트롤러에서 동일 타입의 익셉션을 발생시킬 수 있고, 이 때 익셉션 처리 코드가 동일하다면 어떻게 해야 할까? 각 컨트롤러 클래스마다 익셉션 처리 메소드를 구현하는 것은 불필요한 코드 중복을 발생시킨다. 이럴경우, @ControllerAdvice애노테이션을 이용해서 익셉션 처리 메소드 중복을 없앨 수 있다. @ControllerAdvice애노테이션이 적용된 클래스는 지정한 범위의 컨트롤러에서 공통으로 사용될 설정을 지정할 수 있다. 위 코드의 경우 "chap13.spring"패키지 및 그 하위 패키지에 속한 컨트롤러 클래스를 위한 공통기능을 정의하였다. 이 패키지 및 하위 패키지에 속한 컨트롤러에서 RuntimeException이 발생하면 handleRuntimeException()메소드를 통해서 익셉션을 처리한다. @ControllerAdvice 적용 클래스가 동작하려면 해당 클래스를 스프링에 빈으로 등록해주엉 한다. <bean class="chap13.common.CommonExceptionHandler"/> @ControllerAdvice클래스에 있는 @ExceptionHandler메소드와 컨트롤러 클래스에 있는 @ExceptionHandler 메소드 중 우선순위를 갖는 것은 컨트롤러 클래스에 적용된 @ExceptionHandler클래스이다. 즉, 컨트롤러의 메소드를 실행하는 과정에서 익셉션이 발생하면 다음의 순서로 익셉션을 처리할 @ExceptionHandler메소드를 찾는다. 1. 같은 컨트롤러에 위치한 @ExceptionHandler 메소드 중 해당 익셉션을 처리할 수 있는 메소드를 검색 2. 같은 클래스에 위치한 메소드가 익셉션을 처리할 수 없을 경우, @ControllerAdvice클래스에 위치한 @ExceptionHandler메소드...

(스프링) 컨트롤러 익셉션 처리하기

이미지
*익셉션 화면이 보이는 것보다는 알맞게 익셉션을 처리해서 사용자에게 더 적합한 안내를 해 주는 것이 더 좋은 방법이다. MemberNotFoundException의 경우 try-catch로 잡은 뒤 안내 화면을 보여주는 뷰를 보여주면 될 것이다. 그런데, 타입 변환 실패에 따른 익셉션은 어떻게 해야 에러 화면을 보여줄 수 있을까? 이럴때 유용하게 사용할 수 있는 것이 바로 @ExceptionHandler애노테이션이다. 같은 컨트롤러에 @ExceptionHandler애노테이션을 적용한 메소드가 존재하면, 스프링 MVC는 그 메소드가 익셉션을 처리하도록 한다. 따라서, 컨트롤러에서 발생한 익셉션을 직접 처리하고 싶다면 @ExceptionHandler애노테이션을 적용한 메소드를 구현해주면 된다. ---->@ExceptionHandler의 값으로 TypeMimatchException.class를 주었다. 이 익셉션은 경로 변수값의 타입이 올바르지 않은 경우에 발생하는데, 이 익셉션이 발생하면 에러 응답을 보내지 않고 handleTypeMismatchException()메소드를 실행한다. 비슷하게 detail()메소드를 실행하는 과정에서 MemberNotFoundException이 발생하면 handleNotFoundException()메소드를 이용해서 익셉션을 처리한다.

(스프링) @PathVariable을 이용한 경로 변수 처리

이미지
*ID가 10인 회원의 정보를 조회하기 위한 URL을 구성할 때 다음과 같이 ID 값을 요청경로에 포함시키는 방법을 사용할 수 있다. http://localhost:8080/sp4-chap13/member/detail/10 각 회원의 ID값이 달라지므로 회원마다 경로의 마지막 부분이 달라진다. 이렇게 경로의 특정부분의 값이 고정되어 있지 않고 달라질 때 사용할 수 있는 것이 @PathVariable이다. @PathVariable을 사용하면 가변 경로를 처리할 수 있다. 매핑경로에 '{경로변수}'와 같이 중괄호로 둘러싸인 부분을 경로변수라고 부른다.  "{경로변수}"에 해당하는 값은 같은 경로 변수 이름을 지정한 @PathVariable파라미터에 전달된다. 위 코드에서는 {id}에 해당하는 부분이 @PathVariable("id")애노테이션이 적용된 memId파라미터에 전달한다. memId파라미터의 타입은 Long인데 이 경우 String타입을 알맞게 Long타입으로 변환해준다.

(스프링) 변환처리에 대한 이해

이미지
@DateTimeFormat 애노테이션을 사용하면 지정한 형식의 문자열을 Date타입으로 변환해준다. 그럼 누가 문자열을 Date타입으로 변환해줄까? 답은 WebDataBinder에 있다. 스프링 MVC는 @RequestMapping 적용 메소드의 DispatcherServlet 사이를 연결하기 위해 RequestMappingHandlerAdapter객체를 사용하는데, 이 핸들러 어댑터 객체는 요청 파라미터와 커맨드 객체 사이의 객체 사이의 변환 처리를 위해 WebDataBinder라는 것을 이용한다. WebDataBinder는 @RequestMapping적용 메소드의 파라미터에 지정한 커맨드 클래스를 이용해서 커맨드 객체를 생성한다. 그리고 커맨드 객체의 프로퍼티와 같은 이름을 갖는 요청 파라미터를 이용해서 프로퍼티 값을 생성한다 -->WebDataBinder는 직접 타입을 변환하지 않고 위 그림처럼 ConversionService에 그 역할을 위임한다. <mvc:annotation-driven> 태그를 사용하면, ConversionService로 DefaultFormattingConversionService

(스프링) 컨트롤러에서 쿠키 사용하기

이미지
사용자의 편리함을 위해 아이디를 기억해 두었다가 다음에 로그인을 할 때 아이디를 자동으로 넣어주는 사이트가 많다. 이 기능을 구현할 때 쿠키를 사용한다. 여기서는 쿠키를 사용해서 이메일 기억하기 기능을 추가해보자. 이메일 기억하기 기능을 구현하는 방식은 다음과 같다. 로그인 폼에 '이메일 기억하기'옵션을 추가한다. 로그인 시에 '이메일 기억하기'옵션을 선택했으면, 로그인 성공 후 쿠키에 이메일을 저장한다. 이때 쿠키는 웹 브라우저를 닫더라도 삭제되지 않도록 유효시간을 길게 설정한다. 이후, 로그인 폼을 보여줄 때 이메일을 저장한 쿠키가 존재하면 입력 폼에 이메일을 보여준다. LoginCommand클래스에 rememberEmail필드를 추가했다. 이메일 기억하기 기능을 위해 추가해야 할 부분은 다음의 세 곳이다. loginForm.jsp에 이메일 기억하기 선택 항목을 추가한다. LoginController의 form()메소드에서 쿠키가 존재하는 경우 폼에 전달할 커맨드 객체의 email 프로퍼티를 쿠키의 값으로 설정한다. LoginController의 submit()메소드에서, 이메일 기억하기 옵션을 선택한 경우 로그인 성공 후에 이메일을 담고 있는 쿠키를 생성한다. @CookieValue애노테이션의 value속성은 쿠키의 이름을 지정한다. 이 경우는  이름이 REMEMBER인 쿠키를 Cookie타입으로 전달받게 된다. 지정한 이름을 가진 쿠키가 존재하지 않을 수도 있다면 required속성의 값을 false로 지정해주어야 한다.  이 경우 이메일 기억하기를 선택하지 않을 수도 있기 때문에 required속성의 값을 false로 지정했다.  REMEBER쿠키가 존재할 경우 쿠키의 값을 읽어와 커맨드 객체의 email프로퍼티 값을 설정한다. 커맨드 객체를 사용해서 폼을 출력하므로, REMEMBER쿠키가 존재하면 입력 폼의 email부분에 쿠키의 값이 채워져...

(스프링) 인터셉터 사용하기

이미지
로그인 하지 않은 상태에서 비밀번호를 바꾸는 URL주소를 입력하면, 비밀번호 변경 폼이 출력될 것이다. 로그인하지 않았는데 변경 폼이 출력되는 것은 다소 이상하다. 그것보다는 로그인하지 않은 상태에서 비밀번호 변경 폼을 요청하면, 로그인 화면으로 이동시키는 것이 더 좋은 방법인 것 같다. 이를위해, HttpSession에 "authInfo"객체가 존재하는지 검사해서, 존재하지 않으면 로그인 경로로 리다이렉트하도록 구현한 코드를 컨트롤러 클래스에 추가한 것이다. 그런데 실제 웹 어플리케이션에서는 비밀번호 변경 기능외에 더 많은 기능이 로그인 여부를 확읺야 하는데, 각 기능을 구현한 컨트롤러 코드에 위와 같이 세션을 확인하는 코드를 삽입하는 것은 많은 중복을 발생시킨다. 이렇게 다수의 컨트롤러에 대해 동일한 기능을 적용해야 할 때 사용할 수 있는 것이 인터셉터이다. 스프링은 인터셉터를 지원하기 위해 HandlerInterceptor인터페이스를 제공한다. 1. HandlerInterceptor 인터페이스 사용하기 다음의 세 가지 시점에 공통기능을 넣을 수 있다. 컨트롤러(핸들러)실행 전 컨트롤러(핸들러)실행 후, 아직 뷰를 실행하기 전 뷰를 실행한 이후 다음의 세 개의 메소드를 정의하고 있다. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView)throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler,E...

(스프링) 커맨드 객체의 값 검증과 에러 메시지 처리

이미지
*회원가입 처리 부분의 코드가 동작하긴 하지만, 정상적이지 않은 값을 입력해도 정상적으로 동작할 수 있다. 올바르지 않은 이메일 주소를 입력해도 가입 처리가 되고 이름을 입력하지 않아도 가입을 할 수 있다. 또 다른 문제는 중복된 이메일 주소를 입력해서 다시 폼을 보여줄 때 가입이 처리되지 않는 이유에 대한 설명을 보여주지 않는다. 가입이 실패하는 이유를 보여주어야 한다. 그렇지 않으면 사용자는 혼란을 겪는다. 1. 커맨드 객체 검증과 에러 코드 지정하기 다음 두 인터페이스를 사용한다. org.springframework.validation.Validator org.springframework.validation.Errors Validator 인터페이스는 객체를 검증할 때 사용되며, 다음과 같이 정의되어 있다. public interface Validator{    boolean supports(Class<?> clazz);    void validate(Object target, Errors errors); } --->supports()메소드는 Validator가 검증할 수 있는 타입인지를 검사할 목적으로 사용되고, validate()메소드는 첫 번쨰 마라미터로 전달받은 객체를 검증하고 그 결과를 Erros에 담는 기능을 정의한다. -->validate()메소드에서 target을 실제 타입으로 변환한 뒤에 if문에서 값을 검사한다. email프로퍼티의 값이 유효한지를 검사한다. "email"프로퍼티 값이 존재하지 않을 경우(null이나 빈 문자열인 경우) , errors.rejectValue("email", "required"); "required"를 추가한다. matcher을 통해 정규표현식이 일치한지 검사한다.      ValidationUtils.reject...

(스프링) 스프링 MVC 프레임워크 동작방식

이미지
*src/main/webapp/WEB-INF/web.xml 파일에 DispatcherServlet를 설정한다. DispatcherServlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성하는데, HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver등의 빈은 DispatcherServlet이 생성하는 스프링 컨테이너로부터 구한다. <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-   context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> ---->contextConfiguration 초기화 파라미터를 설정하지 않은 경우, DispatcherServlet은 WEB-INF/[서블릿이름]-servlet.ml 파일을 설정파일로 사용한다. 여기서는 다음과 같다. /WEB-INF/spring/a...

(20장) JMX를 이용한 스프링 빈 관리

JMX는 애플리케이션을 관리하고 모니터링하고 설정하는 데 사용할 수 있는 기술이다. JMX를 이용한 관리 목적에 특화되어 있는애플리케이션의 핵심 구성 요소는 관리 빈(MBean, Managed Bean)이다. MBean은 관리 인터페이스를 정의하는 메소드를 노출하는 자바 빈이다. JMX명세에서는 네 가지 타입의 MBean이 정의되어 있다. 표준MBean - 해당 빈 클래스가 구현하는 고정된 자바 인터페이스의 리플렉션에 의해 관리 인터페이스가 결정되는 MBean이다. 동적MBean - 다이내믹 MBean은 실행시에 DynamicMBean인터페이스의 메소드 호출에 읳 관리 인터페이스가 정해진다. 관리 인터페이스가 정적인 인터페이스에 의해 정의되지 않으므로 실행 시마다 달라질 수 있다. 오픈MBean - 특별한 다이내믹 MBean으로서 애트리뷰트와 오퍼레이셔니 프리미티브 타입(primitive type), 프리미티브 타입용 클래스 래퍼(class wrapper), 프리미티브나 프리미티브 래퍼로 분해될 수있는 타입으로 제한된다. 모델MBean - 관리 인터페이스를 관리 리소스로 넘기는 특별한 다이내믹 MBean이다. 모델 MBean은 선언되는 만큼 작성되지는 않는다. 일반적으로 메타 정보를 이용해 관리 인터페이스를 조립하는 팩토리에 의해 만들어진다.

(19장) 스프링을 사용하여 이메일 전송하기

<MimeMessageHelper을 사용하여 첨부를 포함한 이메일 메시지 보내기> public void sendSpittleEmailWithAttachment(String to, Spittle spittle)throws MessagingException{    MimeMessage message=mailSender.createMimeMessage();    MimeMessageHelper helper=new MimeMessageHelper(message,true); <-메시지 헬퍼 생성   String spittlerName=spittle.getSpitter().getFullName();   helper.setFrom("noreply@spitter.com");   helper.setTo(to);   helper.setSubject("New spittle from"+spitterName);   helper.setText(spitterName+" says:"+spittle.getText());   FileSystemResource couponImage=new FileSystemResource("/collateral/coupon.png");   helper.addAttachment("Coupon.png", couponImage) <--첨부 추가   mailSender.send(message); } *내장된 이미지를 메시지에 추가하는 작업은 첨부파일 추가 작업과 거의 동일하다. helper의 addAttachment()메소드를 호출하는 대신에 addInline()메소드를 호출하면 된다. ClassPathResource image=new ClassPathResource("spitter_logo_50.png"); helper.addInline("spitterLogo",image);...

웹 소켓에 대한 아주 좋은 글

참고: http://barunmo.blogspot.kr/2014_07_01_archive.html

(18장) WebSocekt과 STOMP를 사용하여 메시징하기

이미지
웹 소켓은 단일 소켓을 통해서 풀듀플렉스(full-duplex) 통신을 제공하는 프로토콜이다. 웹 브라우저오 서버간의 비동기 메시징을 활성화한다. 풀 듀플렉스는 서버가 브라우저에 메시지를 전송할 수 있고, 브라우저도 서버에 메시지를 전송할 수 있음을 의미한다. 스프링4.0은 웹 소켓 통신을 지원하며, 다음을 포함한다. 메시지 전송과 수신을 위한 하위 레벨 API 스프링 MVC 컨트롤러에서의 메시지 처리를 이한 상위 레벨 API 메시지 전송을 위한 메시징 템플릿 브라우저, 서버, 프록시에서 웹 소켓 지원 부족을 지원하기 위한 SockJS 1. 스프링의 하위 레벨 웹 소켓 API사용하기 간단한 형태로 웹 소켓은 두 애플리케이션 사이의 통신 채널이다. 풀 듀플렉스이므로 양쪽 종단은 메시지를 전송할 수 있고, 다른 쪽은 그 메시지를 받아서 처리한다. 웹 소켓 통신은 여러 종류의 애플리케이션 사이에서 사용될 수 있다. 그러나 웹 소켓의 대부분은 서버와 브라우저 기반 애플리케이션 사이의 통신을 용이하게 하기 위해서 사용된다. 브라우저에서의 자바스크립트 클라이언트는 서버에 대한 연결을 오픈하고, 서버는 그 연결을 통해 브라우저에 업데이트하라고 보낸다. 이러한 방법은 업데이트를 위해 서버를 폴링(Polling)하는 일반적인 방식보다 더 효율적이며, 좀 더 자연스럽다. 하위 레벨 웹 소켓을 지원하기 위해서 스프링에서 메시지를 처리하고, WebSocketHandler를 구현한 클래스를 작성한다. public interface WebSocketHandler{   void afterConnectionEstablished(WebSocketSession session)throws Exception;  void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception;  void ...

(스프링) 16장 스프링 MVC로 REST API 사용하기

SOAP는 전형적인 동작과 프로세싱에 집중하고 있으며, REST의 관심은 데이터 처리에 있다. 1. 휴식(REST)를 취하다 1.1 REST의 개념 REST는 SOAP의 수 많은 XML네임스페이스를 이용하지 않고 평범한 HTTP URL을 통해 호출한다. REST는 RPC와 거의 관련이 없다. RPC가 서비스 지향적이고 액션과 동사에 초점을 맞추는데 반해, REST는 리소스 지향적이고 애플리케이션을 표현하는 객체와 명사를 강조한다. *REST의 약어 표현(Representational)- REST리소스는 XML, JSON, 심지어 HTML을 포함하여 리소스 사용자에게 가장 적합한, 사실상 거의 모든 형식으로 표현한다. 상태(State)- REST와 작업할 경우 리소스에 대해 취할 수 있는 액션보다 리소스의 상태에 대해 더 많은 관심을 둔다. 전달(Transfer)- REST는 한 애플리케이션에서 다른 애플리케이션으로 어떤 표현 형식으로 리소스 데이터 전달을 포함한다. 간단히 말하면, REST는 가장 적합한 형식이 무엇이든지 간에 서버에서 클라이언트(또는 그 반대로)리소스의 상태를 전달하는 것이다. 1.2 스프링이 REST를 지원하는 방법 컨트롤러는 REST의 네 가지 주요 메소드인 GET,PUT, DELETE 그리고 POST를 포함하여 모든 HTTP메소드에 대한 요청을 처리한다. 스프링 3.2 및 상위 버전은 PATCH메소드도 지원한다. 새로운 @PathVariable 애너테이션은 컨트롤러가 파라미터화된 URL(경로의 일부분에 변수 입력이 있는 URL)에 대한 요청을 처리할 수 있도록 한다. 리소스는 XML, JSON, Atom 그리고 RSS같은 데이터 모델 렌더링을 위한 새로운 뷰 구현을 포함하여 스프링의 뷰와 뷰 리졸버를 이용해 다양한 방식으로 표현한다. 클라이언트에 대한 가장 적합한 표현은 새로운 ContentNegotiatingViewResolver를 이용해 선택한다. 뷰 기반의 ...

(스프링) 15장 원격 서비스 이용하기

이미지
1. 스프링 리모팅 개요 리모팅(Remoting)은 클라이언트 애플리케이션과 서비스 간의 대화다. 클라이언트 측에서 애플리케이션의 범위에 없는 어떤 기능이 필요해지면 클라이언트 애플리케이션이 그 기능을 제공할 수 있는 다른 시스템에 접촉을 한다. 원격 애플리케이션은 그 기능을 원격 서비스를 통해 노출시킨다. 다른 애플리케이션과의 통신은 클라이언트 애플리케이션에서 호출하는 원격 프로시저 호출(RPC, Remote Procedure Call) 로 시작된다. 표면적으로 RPC는 로컬 객체에 있는 메소드 호출과 유사하다. 즉, 원격호출과 로컬호출 둘 다 호출되는 프로시저가 완료될 때까지 호출코드에서 실행을 블록하는 동기식 작업이다. <RPC와 기타원격 기술 비교> 원격 메소드 호출(RMI) : 방화벽과 같은 네트워크 제약이 고려 대상이 아닐 경우, 자바 기반 서비스에 접속하거나 노출시킬 때 Hessian 또는 Burlap : 네트워크 제약이 고려 대상일 경우, HTTP를 거쳐 자바 기반 서비스에 접속하거나 노출시킬 때, Hessian은 바이너리 프로토콜이고, Burlap은 XML기반이다. HTTP호출자 : 네트워크 제약이 고려대상이고 XML이나 독자적인 직렬화를 통한 자바 직렬화를 원하는 경우, 스프링기반 서비스에 접속하거나 서비스를 노출 시킬 때 JAX-RPC와 JAX-WS : 플랫폼 중립적인 SOAP기반 웹 서비스에 접속하거나 서비스를 노출 시킬 때 모든 모델에서 서비스는 애플리케이션에 스프링 관리 빈으로 구성될 수 있는데, 이것은 프록시 팩토리 빈을 이용해 원격 서비스를 마치 로컬 객체들인 것처럼 다른 빈의 프로퍼티에 연결할 수 있기 때문에 가능한 일이다.  2. RMI활용 스프링은 RMI서비스를 로컬 자바빈즈(JavaBeans)인 것처럼 스프링 애플리케이션에 연결할 수 있게 해주는 프록시 팩토리 빈을 제공함으로써 RMI모델을 단순화한다. 스프링은 또한 스프링관리 빈을 RMI서비스로 ...