요청 핸들러 request handler
: 요청이 들어왔을 때 호출되는 메서드
예) add(), list(), detail() 등
요청이들어오면 DispatcherServlet(Front Controller)가 받는다.
DispatcherServlet가 하는 일
1) 요청 URL을 처리할 페이지 컨트롤러의 핸들러를 찾는다.
2) 핸들러의 파라미터를 알아낸다.
3) 핸들러에게 넘겨줄 파라미터 값을 준비한다.
4) 준비한 파라미터 값을 가지고 핸들러를 호출한다.
5) 핸들러가 리턴한 값을 리턴한다.
6) ServletRequest 보관소에 담아야 할 값은 담고, 뷰컴포넌트 URL은 해당 뷰 컴포넌트를 실행
7) 클라이언트에 응답
Model, View, Controller
Model
: Service, DAO
Page Controller
: Controller
View
: View
Front Controller
가 요청을 받고, Front Controller
는 파라미터에 전달된 값(argument)을 준비하고Front Controller
는 Page Controller
에게 핸들러를 호출한다.Page Controller
는 서블릿, DAO, DBMS를 통해서 리턴된값을 다시 Front Controller
에게 리턴한다.Front Controller
는 리턴받은 값을 이용해서 ServletRequest
보관소에 작업결과를 저장한다.Front Controller
는 View
를 호출하는데 View
는 ServletRequest
보관소에 저장된 값을 사용Front Controller
에게 다시 리턴한다.Front Controller
를 통해 Client에게 응답한다. // public String form(HttpServletResponse response, HttpServletRequest request) throws Exception {
public String form(HttpServletResponse response) throws Exception {
@RequestParam
// 변경 전
@PostMapping("/board/add")
public String add(HttpServletRequest request, HttpServletResponse response) throws Exception {
Board board = new Board();
board.setTitle(request.getParameter("title"));
board.setContent(request.getParameter("content"));
board.setAttachedFiles(saveAttachedFiles(request));
board.setWriter((Member) request.getSession().getAttribute("loginMember"));
boardService.add(board);
return "redirect:list";
}
// 변경 후
@PostMapping("add")
public String add(@RequestParam("title") String title, @RequestParam("content") String content,
HttpServletRequest request, HttpSession session) throws Exception {
Board board = new Board();
board.setTitle(title);
board.setContent(content);
board.setAttachedFiles(saveAttachedFiles(request));
board.setWriter((Member) session.getAttribute("loginMember"));
boardService.add(board);
return "redirect:list";
}
@RequestParam
생략할 수 있는 경우클라이언트에서 보내는 파라미터 변수이름과 값을 받을 변수의 이름이 같을경우 @RequestParam
을 생략할 수 있다.
// 변경전
@PostMapping("add")
public String add(@RequestParam("title") String title, @RequestParam("content") String content,
HttpServletRequest request, HttpSession session) throws Exception {
// 변경후
@PostMapping("add")
public String add(String title, String content, HttpServletRequest request, HttpSession session)
throws Exception {
public class BoardController {
ServletContext sc;
BoardService boardService;
public BoardController(BoardService boardService, ServletContext sc) {
this.boardService = boardService;
this.sc = sc;
}
@PostMapping("add")
public String add(String title, String content, Part[] files, HttpServletRequest request,
HttpSession session) throws Exception {
Board board = new Board();
board.setTitle(title);
board.setContent(content);
board.setAttachedFiles(saveAttachedFiles(files));
board.setWriter((Member) session.getAttribute("loginMember"));
boardService.add(board);
return "redirect:list";
}
private List<AttachedFile> saveAttachedFiles(Part[] files) throws IOException, ServletException {
List<AttachedFile> attachedFiles = new ArrayList<>();
String dirPath = sc.getRealPath("/board/files");
//Collection<Part> parts = request.getParts();
for (Part part : files) {
if (!part.getName().equals("files") || part.getSize() == 0) {
continue;
}
String filename = UUID.randomUUID().toString();
part.write(dirPath + "/" + filename);
attachedFiles.add(new AttachedFile(filename));
}
return attachedFiles;
}
private List<AttachedFile> saveAttachedFiles(MultipartFile[] files)
throws IOException, ServletException {
List<AttachedFile> attachedFiles = new ArrayList<>();
String dirPath = sc.getRealPath("/board/files");
//Collection<Part> parts = request.getParts();
for (MultipartFile part : files) {
if (part.isEmpty()) { // 비어있다면 continue; 다음꺼로 빈파일 있다면 저장하지 않는다.
continue;
}
String filename = UUID.randomUUID().toString();
part.transferTo(new File(dirPath + "/" + filename));
attachedFiles.add(new AttachedFile(filename));
}
return attachedFiles;
}
multipart/form-data ----> 도메인 객체, 예) Board
multipart/form-data
를 도메인 객체로 변환하기 위해서는 MultipartResolver
가 필요하다
MultipartResolver
를 사용하기 위해서는 별도 설정이 필요하다.
- 단, multipart/form-data 형식으로 전송된 데이터를 처리하려면 MultipartResolver를 설정해야 한다.
public class AppConfig {
// multipart/form-data 형식으로 보내온 요청 데이터를
// 도메인 객체로 받는 일을 할 도우미 객체를 등록한다.
// 이 객체가 등록된 경우 multipart/form-data를 도메인 객체로 받을 수 있다.
@Bean("multipartResolver")
public MultipartResolver createMultipartResolver() {
return new StandardServletMultipartResolver();
}
@GetMapping("list")
public ModelAndView list() throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("boards", boardService.list());
mv.setViewName("/board/list.jsp");
return mv;
}
@GetMapping("list")
public ModelAndView list() throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("boards", boardService.list()); // ServletRquest 보관소에 저장하고
mv.setViewName("/board/list.jsp"); // jsp파일의 주소를 매핑한다.
return mv;
}
@GetMapping("form")
public View form() throws Exception {
return new JstlView("/auth/form.jsp");
} // JSTL에 담아서 리턴해도 된다
Front Controller(DispatcherServlet)는 요청 핸들러의 리턴타입에 따라 적절하게 처리한다.
DispatcherServlet BoardController
1. DispatcherServlet가 BoardController에게 list() 호출
2. BoardController는 BoardService에게 list() 호출하여 리턴받음.
3. BoardController는 ModelAndView객체를 만들고 ModelAndView객체에 List와 JSP주소를 받아서 DispatcherServlet에게 리턴한다.
4. DispatcherServlet은 ModalAndView객체에서 데이터를 꺼내서 ServletRequest 보관소에 담는다.
5. DispatcherServlet가 JSP 주소를 꺼내서 실행하면, JSP는 ServeltRequest보관소에 저장된 데이터를 사용한뒤 DispatcherServlet에게 리턴한다.
DispatcherServlet
list호출 BoardController
에게 list 호출
BoardController
는 DispatcherServlet
에게 "board/list" 리턴
DispatcherServlet
은 "board/list"를 IntenerallResourceViewResolversms
에게 전달하면
"/" + "board/list" + ".jsp" ==> "/board/list.jsp"를 만들어서 JsltView
에 넘긴다.
JstlView
는 JSP를 실행한다.
ViewResolver
를 InternalResourceViewResolver
로 교체한다.InternalResourceViewResolver
JSP를 뷰로 사용할때 사용하며, DispatcherServlet에게 아무런 ViewResolver를 등록하지 않으면, 기본으로 동작하는 ViewResolver이다.// Spring WebMVC의 기본 ViewResolver를 교체한다.
@Bean("viewResolver")
public ViewResolver createViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class); // 주어진 URL을 처리할 객체 => JSP 실행시킨다.
viewResolver.setPrefix("/WEB-INF/jsp/"); //
viewResolver.setSuffix(".jsp");
return viewResolver;
}
// InternalResourceViewResolver 사용 전:
@GetMapping("form")
public String form(HttpServletResponse response) throws Exception {
return "board/form";
}
//
// InternalResourceViewResolver 사용 후:
@GetMapping("form")
public void form() throws Exception {}