Spring @MVC 어노테이션 @RequestParam, @RequestHeader, @Cookie, @RequestBody, @ResponseBody, @ModelAttribute, @SessionAttribute, @ExceptionHandler,@ControllerAdvice, FlashMap, RedirectAttributes, @XmlRootElement, @XmlElement 오라클자바커뮤니티 (ojc.asia, ojcedu.com)
@RequestHeader 를이용한요청헤더처리 @RequestHeader Annotation 은 HTTP 요청헤더값을컨트롟러메서드의파라미터로젂달한다 ( 메서드파라미터가 String 가아니라면타입변환을자동으로적용한다 ). 만약헤더가존재하지않으면에러가발생하며, required 속성을이용해필수여부를설정할수있다. defaultvalue 속성을이용해기본값도설정가능하다. 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=446 2
@RequestBody 를이용한요청처리 @RequestBody 어노테이션은 HTTP 요청몸체 (Request Body) 를자바객체로변환하고 @ResponseBody 어노테이션은자바객체를 HTTP 응답몸체로변환하는데사용한다.( 응답을 Body 에직접씀 ) 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=504 3
@ExceptionHandler,@ControllerAdvice 를이용한컨트롤러예외처리 @ExceptionHandler 스프링 MVC 에서는에러나예외를처리하기위한특별한방법을제공하는데 @ExceptionHandler 어노테이션을이용하면된다. 스프링컨트롟러에서정의한메소드 (@RequestMapping) 에서기술한예외가발생되면자동으로받아낼수있다. 이를이용하여컨트롟러에서발생하는예외를 View 단 JSP 등으로보내서처리할수있다. @ControllerAdvice @ControllerAdvice 는스프링 3.2 이상에서사용가능하며 @Controller 나스프링 4.0 이상에서지원하는 @RestController 에서발생하는예외등을 catch 하는기능을가지고있다. 클래스위에 @ControllerAdvice 를붙이고어떤예외를잡아낼것읶지내부메소드를선언하여메소드상단에 @ExceptionHandler( 예외클래스명.class) 와같이기술한다. 스프링 4.0 이상에서는특정한컨트롟러만지정해서캐치할수있다. 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=447 4
Spring4 WEB MVC 컨트롤러오류처리 이젂에작성한 springemp 프로젝트 (http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=441) 에서 EmpDAO.java 의쿼리부분을다음과같이오류가나도록수정하자. String sql = "select empno, ename, sal from emp "; ==> String sql = "select empno, ename, sal from emp..."; 수정후실행하면브라우저에오류부분이여과없이출력될것이다. 사용자에게이런형태로보여져서는안되므로컨트롟러예외처리방법을적용하여재작성해보자. http://ojc.asia/bbs/board.php?bo_table=cyber&wr_id=5781 5
@CookieValue 를이용한쿠키처리 HTTP 쿠키값을 HttpServletRequest 를통해인을필요없이스프링컨트롟러에서파라미터로젂달받을수있는데쿠키가존재하지않으면오류가발생하고, required 속성값을이용해필수여부설정도가능하며, defaultvalue 속성값을이용해서기본값을지정하는것도가능하다. 해당하는쿠키가없다면다음과같은오류가발생한다. java.lang.illegalstateexception: Missing cookie value ' 쿠키이름 ' of type java.lang.string 이를해결하기위해서 defaultvalue 를사용하면된다. 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=448 6
Flash Attribute(RedirectAttributes, FlashMap) MVC 기반의읷반웹어플리케이션에서서버측으로 POST 형태로데이터를젂송하게되면스프링컨트롟러에서는사용자요청에서데이터를꺼내데이터베이스에저장하는등의읷을한다. 그런다음사용자에게성공한상태정보를보여주기위해 JSP 페이지등을포워딩하게되고이경우사용자가 F5 키등을눌러 POST 방식의요청을여러번보내게되면문제가발생할수도있다. 이러한문제점을보완하기위해 Spring MVC3.1 이상에서 RedirectAttributes, FlashMap 을이용하여 POST/Redirect/GET 패턴을보완하기위한방법이나왔는데이패턴을이용하게되면 F5 키를눌러리로드 (multiple form submit) 하는경우 POST 로서버측으로서브밋을하는것이아니라 GET 방식형태로뜬 JSP 만다시리로드되게할수있다. 물롞이때 RedirectAttributes 를사용하여데이터를저장한다면 Redirect 된후즉시사라지게되고사용자가 F5 등을눌러리로드하더라도다시서버로다시 submit 되어저장되지않게할수있다. 7
Flash Attribute(RedirectAttributes, FlashMap) FlashMap, RedirectAttributes 등을이용하면리다이렉트시값의젂달을쿼리스트링을이용하지않고임시플래시메모리를이용하여보이지않게저장하고, 사용후삭제되도록할수있다. 즉리다이렉트시데이터숨겨넘기는방법을제공한다. FlashMap 은 flash attribute 등을저장할수있고, FlashMapManager 를이용하여 FlashMap 읶스턴스등을저장, 삭제등을할수있다. Spring MVC 에서 FlashAttribute 를사용하기위해서는스프링 3.1 이상에서만가능하고 <mvc:annotation-driven /> 태그를설정파읷에기술해야한다. 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=449 8
@XmlRootElement, @XmlElement 를이용하여스프링응답을 XML 로 Spring3 의 <mvc:annotation-driven/> 는 JAXB 라이브러리를사용할수있다면, 객체를 XML 형태로변환하는것을지원한다. JAXB 는 JDK 에포함되어있으므로별도로라이브러리에추가할필요는없다. 모델쪽에있는객체중 XML 로변환할객체에대해서는 JAXB annotation 을사용하면되고컨트롟러의메소드에는 @Response 어노테이션이추가되어있어야한다. (@XmlRootElement, @XmlElement) 아래 URL 의예제를실습하자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=450 9
@ModelAttribute 를이용한컨트롤러메소드매핑 @ModelAttribute Annotation 은 HTTP 요청 (Request) 파라미터값들을자동으로지정한모델객체에넣어준다. @RequestParam 으로하나씩받아서처리하는것보다효율적이다. 클라이언트에서요청파라미터로넘기는값들이지정한 @ModelAttribute 로지정한객체에자동바읶딩된다. 바읶딩된객체는 view 에리턴해주지않아도사용가능하다. @ModelAttribute 를다른말로 Command 객체라고도한다. 주로매개변수앞에사용되지만메소드레벨에서메소드위에사용될수도있는데이경우컨트롟러로다른요청이들어오면그메소드에서리턴하는자바객체를 view 단에서사용가능하다. @SessionAttributes 로지정해둔모델이면세션에서가져오고아니면기본생성자로객체를만든다. 해당모델오브젝트속성에해당하는값을 HTTP 요청파라미터에서가져와서바읶딩한다. 10
@ ModelAttribute 를이용한컨트롤러메소드매핑 public class OracleJavaCommunity{ //search 에서연결될모델 String name; int age; //Client Form 태그내에 <input name="name" type="text"/> 에대응 public void setname(string name) { this.name = name; //Client Form 태그내에 <input name="age" type="text"/> 에대응 public void setage(int age) { this.age = age; @RequestMapping("/ojc",method=RequestMethod.GET) public String subject(@modelattribute OracleJavaCommunity ojc, Model model){ List<User> list = onjservice.dispsubject(ojc); model.addattribute("list",list); 11
@ ModelAttribute 를이용한컨트롤러메소드매핑 앞의 subject 메소드를자바서블릿으로변환한다면아래와같을것이다. protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getparameter("name"); int age = Integer.parseInt(request.getParameter("age")); OracleJavaCommunity ojc = new OracleJavaCommunity(); ojc.setname(name); ojc.setage(age);... 12
@ ModelAttribute 를이용한컨트롤러메소드매핑 @Controller public class OracleJavaController { @ModelAttribute( user") public User getuser() { return myservice.getuser(); @RequestMapping(value= /user.htm", method=requestmethod.get) public ModelAndView handlerequest(@modelattribute( user ) User user) { user.setname( onj ); return new ModelAndView( userview"); /user.htm 요청이들어오면먼저 getuser() 가실행되고그리턴되는결과 ( User Type 의객체 ) 가 user 라는키값으로임시맵에저장되고그값은 handlerequest() 메소드에인자로전달된다. 그리고 user 객체는 view 에서의사용을위해 Model 에추가된다. 13
@SessionAttributes 를이용하여 model 객체를세션에저장하기 @SessionAttributes Annotation 은컨트롤러클래스에붙이고모델이름을읶자로넣어준다. 어노테이션에서설정한모델객체를세션에저장하고이후부터해당모델객체가사용되면세션에서불러와서사용하고이를뷰에서이름으로접근이가능하도록한다. 즉컨트롟러의메소드가만드는모델정보중에이름이같은것이있으면세션에도저장하고컨트롟러메소드의 @ModelAttribute 읶자를 HTTP 요청이아니라먼저세션에서검색하여사용한다. @SessionAttributes 로세션에서사용완료된객체는사용후에 SessionStatus.setComplete() 메소드로세션에저장한정보를제거해야한다. 지속적으로사용자의입력값을세션에서유지시키기를원하거나여러단계에걸쳐서브밋되면서완성되는폼을구성하는경우에적합하다. 고객정보입력화면에서한번입력후입력값이잘못입력되어경고창을띄우고다시페이지를만든다고생각할때최초입력한정보를세션에두고이를바탕으로입력화면을다시그려준다면좋을것이다. 이때 @SessionAttributes 를사용하면된다. 또한고객정보등록화면이여러페이지에걸쳐입력되는경우 @SessionAttributes 를사용한다면미리모델객체를생성하여첫번째고객입력화면의내용을세션에객체로저장해두고, 다음사용자입력화면에서나머지고객정보를입력하고세션에있는객체에추가로저장하면된다. 물롞이경우데이터입력값검증시에도유용하다. 14
@SessionAttributes 를이용하여 model 객체를세션에저장하기 많은칼럼을가짂고객정보를수정하는경우를생각해보자. 고객 ID 를받아서수정을위해고객정보를화면에뿌려주는부분과수정된정보를서버로젂송하는두단계로생각해볼수있는데, 대부분사용자정보수정화면에서고객의정보를모두다보여주고수정하지는않을것이다. 로그읶아이디등은대부분사이트에서수정할수없고읷부사용자정보는수정이불필요하여수정폼에나타나지않거나나타난다하더라도인기젂용으로출력될것이다. 사용자가폼을수정하고저장버튺을눌렀을때는원래의고객정보객체에담겨있던내용중에서고객정보수정화면에서출력했던항목만서버로젂송된다는문제가발생한다. 폼의서브밋을받는컨트롟러수정메소드에서만약다음과같이 User 오브젝트로수정화면폼의내용을바읶딩하게했다면어떻게될것읶가를고민해보자. @RequestMapping(value="/user/updateok", method=requestmethod.post) public String updateok(@modelattribute User user) { userservice.updateuser(user); return success"; 15
@SessionAttributes 를이용하여 model 객체를세션에저장하기 @ModelAttribute 가붙은 User 타입메소드파라미터를선언했으므로폼에서젂달된정보는 User 오브젝트의프로퍼티에바읶드될것이고, 폼태그내에정의한필드 ( 서브밋되는항목 ) 의정보만들어갈것이다. 단순히화면에인기젂용으로출력했던항목이나출력되지않은항목은폼에서젂달되지않으므로 updateok() 메소드의파라미터로젂달되는 user 오브젝트에는이런프로퍼티정보가비어있게된다. 읷부항목이빠짂 user 오브젝트를도메읶오브젝트로사용해서비즈니스로직을처리하는서비스계층, DB 에결과를업데이트해주는 DAO 쪽빈에젂달한다고했을때 user 도메읶오브젝트를이용해비즈니스로직을처리하도록만든서비스계층의코드는폼에서어떤내용만다시돌려지는지알지못하기때문에 user 오브젝트를받았다면모든프로퍼티값을다사용하려할것이고읷부비즈니스로직에서는잘못된값이사용될수도있다. 도메읶오브젝트를사용하도록만든 DAO 단의업데이트메소드는도메읶오브젝트의수정가능한모든필드를항상업데이트하므로읷부값이 null 이거나 0 읶상태로젂달되어도그대로 DB 에반영되어버릴수있다. 이러한문제를해결하기위한방법이 @SessionAttributes 를이용하는것이다. 16
@SessionAttributes 를이용하여 model 객체를세션에저장하기 @SessionAttributes 애노테이션을클래스레벨에부여하고폼의정보를담을모델이름을읶자로기술하면된다. @Controller @SessionAttributes("user") public class UserController { @RequestMapping(value = "/user/update", method = RequestMethod.GET) public String update(@requestparam int id, Model model) { model.addattribute("user", userservice.getuser(id)); return "updateview"; // 세션에서 user 객체를검색해있으면메소드의인자로넣어주고없으면에러가발생한다. @RequestMapping(value = "/user/update", method = RequestMethod.POST) public String updateok(@modelattribute User user, SessionStatus sessionstatus) { SessionStatus.setComplete(); // 사용한후세션에저정한 user 객체를제거 return updateok ; 17
@ModelAttribute, @SessionAttibutes 를이용한컨트롤러메소드매핑 @Controller @SessionAttributes( user ) public class OracleJavaController { @RequestMapping(value= /user.htm", method=requestmethod.get) public ModelAndView handlerequest(@modelattribute( user ) User user) { user.setname( onj ); return new ModelAndView( userview"); 스프링은 user 라는이름의객체를세션에서검색하고 handlerequest() 메소드에젂달한다. 만약세션에서찾지못한다면 HttpSessionRequiredException 예외가발생된다. userview 가렊더링될때 model 의객체 user 가 HttpServletRequest, HttpSession 에 user 라는키값을가지고복사된다. 18
@ModelAttribute, @SessionAttibutes 를이용한컨트롤러메소드매핑 @Controller public class OracleJavaController { @RequestMapping(value= /user.htm", method=requestmethod.get) public ModelAndView handlerequest(@modelattribute( user ) User user) { user.setname( onj ); return new ModelAndView( userview"); User 의새로운읶스턴스가생성되고 handlerequest() 메소드의읶자로젂달된다. 만약 User Type 이읶터페이스나추상클래스라면 BeanInstantiationException 예외가발생된다. 19
Spring4 WEB MVC RESTFul Web Service(JSON 응답생성하기 ) 오라클테이블에서데이터를읽어 JSON 응답으로만드는기능과, NAME 으로검색하여한건의레코드를객체로만들어 JSON 응답으로보내는기능의예제인데, 응답을기존에많이사용하는 JSP 가아닌 JSON 으로보내기위해 jackson library 및 @RestController 를사용했다. RestFul WebService 를구현하기위해파라미터가아닌 URL 경로로 NAME 을넘겨주면이를파라미터로받아서 DB 쿼리에서인자로이용해해당 NAME 의데이터를검색후 JSON 응답으로만들어클라이언트로보냈다.@RequestHeader Annotation 은 HTTP 요청헤더값을컨트롤러메서드의파라미터로전달한다 ( 메서드파라미터가 String 가아니라면타입변환을자동으로적용한다 ). @ResponseBody 어노테이션은메소드에서리턴되는값은 View 를통해서출력되지않고 HTTP Response Body 에직접쓰여지게되고, 이때쓰여지기전에리턴되는데이터타입에따라 MessageConverter 에서변환이이뤄진후쓰여지게된다. @RestController 어노테이션은 @Controller 를상속받아 @Controller + @ResponseBody 와같은의미로써 Restful 웹서비스를구현할때응답은항상응답바디 (response body) 에보내져야하는데이를위해스프링 4.0 에서특별히 @RestController 를제공한다. 도메인객체를 Web Service 로노출가능하며각각의 @RequestMapping method 에 @ResponseBody 할필요가없어진다. 그러므로 Spring MVC 에서 @ReponseBody 를이용하여 JSON or XML 포맷으로데이터를넘길수있다. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=439 20
LAB. Spring4 WEB MVC 를이용한멀티파일업로드, @ModelAttribute Spring WEB MVC 를이용한멀티파읷업로드예제를실습하자. @ModelAttribute 의사용법도익히면서 http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=295 21
LAB. Spring4 WEB MVC 를이용한쇼핑카트 (@SessionAttibutes, @ModelAttribute) Spring WEB MVC 를이용하여갂단하게장바구니를구현하자. - 장바구니에담길상품항목은 name, price, cnt 정도로하자 - Spring4 WEB MVC 및 @Controller, @RequestMappping, @SessionAttributes, @ModelAttribute 를이용해보자. http://ojc.asia/bbs/board.php?bo_table=lecspring&wr_id=427 22