스프링mvc
스프링 mvc 주요 구성 요소 및 처리 흐름
사용법
1. web.xml에 DispatcherServlet 맵핑
3. controller 작성
2. Spring에 HandMapping,Controller, ViewResolver 등록
4. view 작성
1 2 3 4 5 6 7 8 9 10 11 12 13 | <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/dispatcher-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> | cs |
라이브러리에 있는 DispatcherServlet을 등록후 *.do 모든.do요청에 동작하도록 설정
이용하여 DispatcherServlet 객체에게 초기화 파라미터 정보 알려줌. 이때 파라미터는 contextConfigLocation이며 value는 설정 파일 위치를 지정하면 됨.
만약 정보 안알려 주면 기본적으로 WEB-INF 폴더에 있는 서블릿명-servlet.xml 파일을 인식함. 이 경우 로딩된 설정 파일에 모든 spring MVC 관련 클래스들을 Bean으로 등록해야함.
한글 인코딩을 추가 할 경우 밑의 코드를 포함시키면 됨.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> | cs |
스프링에서 제공하는 Controller 인터페이스를 implements하여 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class LoginController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //1. 사용자 입력정보(id, password)추출 String id = request.getParameter("id"); String pwd = request.getParameter("password"); //2. DB 연동 UserDAO dao = new UserDAO(); UserVO user = dao.getUser(id, pwd); //3. 적절한 화면으로 이동 ModelAndView mav = new ModelAndView(); if(user != null){ mav.addObject("message", "로그인 성공"); mav.addObject("userVo", user); mav.setViewName("loginResult"); }else{ mav.addObject("message", "로그인 실패"); mav.setViewName("login"); } return mav; } | cs |
ModelAndView 객체는 Model 정보와 View 정보를 담고 있음(뷰는 논리적 이름을 디스패쳐서블릿으로 돌려보냄. 디스패쳐서블릿은 뷰 리졸버에게 논리적 뷰 이름을 실제 뷰에 매핑하도록 요청함.)
디스패쳐서블릿
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <!-- HandlerMapping --> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.do">helloController</prop> </props> </property> </bean> <!-- Controller --> <bean id="helloController" class="com.mymall.test.controller.HelloController"></bean> <!-- ViewResolver --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/view/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> | cs |
handlerMapping
hello.do라는 요청에 대해서 hellowController라는 이름의 controller가 요청을 처리하도록 매핑
Controller
윗윗 코드를 Bean으로 등록한 것
handlerMapping과 동일한 이름으로 id 등록해야함.
veiwResolber
jsp를 view로 사용할 경우 InternalResourceViewResolver사용
이것은 접두사와 접미사를 지정하면 이를 이용하여 view 정보를 완성함.
예) 모델뷰에서 뷰 이름을 login으로 설정하면
이것에 의해 "WEB-INF/view/login.jsp가 됨.
어노테이션
xml을 최소화 하기위한 설정 지원
@Controller
1 - Controller 클래스 상속 필요 없음(POJO로 구현 가능하다는 의미)
2 - implements와 handleRequest 안해도 됨.
3 - bean등록 자동으로 해줌
@RequestMapping
1 - 메소드 설정 할때 요청 URI와 적절하게 매핑
2 - handlerMapping을 대신함.
3 - 요청 방식에 따라 메소드 get, post로 설정
4 - 클라이언트의 요청이 동일한 URI면 @controller 다음에 쓰는 것도 가능(중복경로 까지만 지정 가능)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | @Controller public class LoginController { @RequestMapping(value="/login.do", method=RequestMethod.GET) public String loginView(HttpServletRequest request, HttpServletResponse response) { } @RequestMapping(value="/login.do", method=RequestMethod.POST) public String login(HttpServletRequest request, HttpServletResponse response) { } } @Controller @RequestMapping("/login.do") public class LoginController { @RequestMapping(method=RequestMethod.GET) public String loginView(HttpServletRequest request, HttpServletResponse response) { } @RequestMapping(method=RequestMethod.POST) public String login(HttpServletRequest request, HttpServletResponse response) { } } @Controller @RequestMapping("/board") public class DetailController { @RequestMapping("/countUpdate.do") public String countUpdate(@RequestParam(defaultValue = "0") int no, Model model) { } } | cs |
클라이언트 요청 처리
사용자로부터 아이디와 비밀번호 입력 받아서 /login.do로 매핑된 Controller 호출 하는 경우
자바빈을 이용하여 구현 가능
(UserVO의 멤버변수와 파라미터 id속성 값은 동일 해야함)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @Controller public class LoginController { @RequestMapping("/login.do") public String login(HttpServletRequest request) { String id = request.getParameter("id"); String password = request.getParameter("password"); UserVO vo = new UserVO(); vo.setId(id); vo.setPassword(password); int n = userService.insertUser(vo); } } @Controller public class LoginController { @RequestMapping("/login.do") public String login(@RequestParam String id, @RequestParam String password) throws Exception { UserVO vo = new UserVO(); vo.setId(id); vo.setPassword(password); int n = userService.insertUser(vo); } } @Controller public class LoginController { @RequestMapping("/login.do") public String login(@ModelAttribute UserVO vo) throws Exception { int n = userService.insertUser(vo); } } | cs |
반대로 jsp에서 Command객체를 사용하러면 Command 클래스 이름을 첫글자는 소문자로 해서 접근 가능. 만약 다른 이름으로 변경 하고자 한다면
1 2 3 4 | @RequestMapping("/login.do") public String login(@ModelAttribute("myuser") UserVO user) throws Exception { } | cs |
Command 객체에는 없는 파라미터의 경우
@RequestParam 매개변수 이용
(null값 처리 해줘야함. 로직으로 안에서 만들거나 매개변수로 줄때 기본값 부여)
@RequestParam 매개변수의 경우 기본적으로 필수 파라미터로 해당 파라미터가 존재하지 않을 경우 잘못된 요청을 의미하는 400에러를 전송함.
따라서 필수가 아닌 경우 required 속성 값을 false로 지정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | GetUserListController.java] @Controller public class getUserListController { @RequestMapping("/getUserList.do") public String getUserList( @RequestParam("searchCondition") String searchCondition, @RequestParam("searchKeyword") String searchKeyword){ System.out.println("검색 조건 : " + searchCondition); System.out.println("검색 단어 : " + searchKeyword); return null; } } @RequestMapping("/getUserList.do") public String getUserList(@RequestParam String searchCondition, @RequestParam String searchKeyword){ } @RequestMapping("/getUserList.do") public String getUserList(String searchCondition, String searchKeyword){ } @RequestMapping("/getUserList.do") public String getUserList( @RequestParam(value="searchCondition", required=false, defaultValue="NAME") String searchCondition, @RequestParam(value="searchKeyword", defaultValue="") String searchKeyword){ return null; } | cs |
극히 드물게 Command객체나 @RequestParam 보다 서블릿 API를 사용하는 것이 편리 할때가 있다(HttpServletRequest)
1 - HttpSession 의 생성을 직접 제어해야 하는 경우
2 - 컨트롤러에서 쿠키를 생성해야 하는 경우
3 - 서블릿 API 사용을 선호하는 경우
@CookieValue를 이용해 쿠키 값을 파라미터로 받아올수 있다.
(쿠키가 없을 경우 500에러 발생하니 required, defaultValue 이용)
1 2 3 4 5 6 | @RequestMapping("/cookie/view.do") public String view( @CookieValue(value = "auth", defaultValue = "0") String authValue) { System.out.println("auth 쿠키: " + authValue); return "cookie/view"; } | cs |
@RequestHeader을 이용하여 헤더정보(host, user-agent, Accept-Language등)을 파라미터로 받기 가능(이것도 없으면 500)
Controller의 리턴 타입
ModelAndView
1 2 3 4 5 6 7 8 9 10 11 | public ModelAndView login(@ModelAttribute UserVO vo, HttpServletRequest request) { UserDAO dao = new UserDAO(); UserVO user = dao.getUser(vo); ModelAndView mav = new ModelAndView(); if(user != null){ mav.setViewName("getUserList"); }else{ mav.setViewName("login"); } return mav; } | cs |
1 2 3 4 5 6 7 8 9 10 11 | public ModelAndView login(@ModelAttribute UserVO vo, HttpServletRequest request) { UserDAO dao = new UserDAO(); UserVO user = dao.getUser(vo); ModelAndView mav = new ModelAndView(); if(user != null){ mav.setViewName("redirect:/getUserList.do"); }else{ mav.setViewName("login"); } return mav; } | cs |
String
Model
Map
View
void
컨트롤러 클래스 자동 스캔
1 2 | <context:component-scan base-package="mysite.spring.chap06.controller" /> | cs |
1 2 | <bean id="helloController2" class="com.mysite.controller.HelloController2" /> | cs |
DispatcherServlet 설정과 ApplicationContext 관계
web.xml 파일에 한 개 이상의 디스패쳐 설정 가능하며 각 디스패쳐는 한개의 WebApplicationContext를 가짐.
또한 각 디스패쳐가 공유할 수 있는 빈 설정 가능
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <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/main.xml /WEB-INF/bbs.xml </param-value> </init-param> </servlet> <servlet> <servlet-name>front</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/front.xml</param-value> </init-param> </servlet> <servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/rest.xml</param-value> </init-param> </servlet> | cs |
위에서 front와 rest는 각각 별도의 WebApplicationContext를 생성함
(서로 빈 객체 사용 불가능)
서로 공용 빈을 사용하고 싶다면 front와 rest의 컨텍스트가 동일한 부모를 가지면 됨.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!-- 부모 애플리캐이션컨텍스트(root)에서 설정파일을 통한 bean 공유 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/service.xml, /WEB-INF/persistence.xml</param-value> </context-param> <!-- 리스너를 이용하여 설정 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 자식 애플리케이션 컨텍스트 --> <servlet> <servlet-name>front</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <!-- 자식 애플리케이션 컨텍스트 --> <servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> | cs |
위의 소스를 통해 자식 컨텍스트는 루트 컨텍스트가 제공하는 빈을 사용할 수 있다. 이때 루트컨텍스트가 파라미터를 명시하지 않으면 기본적으로 /WEB-INF/applicationContext.xml을 설정 파일로 사용한다.
만약 src/main/resources 위치(클래스패스에)한 파일로부터 설정 정보(파라미터)를 읽어오고 싶다면 classpath:패키지명/.xml을 사용한다.
1 2 3 4 5 6 7 8 | <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:config/service.xml classpath:common.xml /WEB-INF/config/message_conf.xml </param-value> </context-param> | cs |