인프런 김영한님의 스프링 MVC 1편을 듣고, 정리 겸 복습한 내용입니다.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {}
서블릿은 HTTP 요청 메시지를 개발자 대신 파싱한다.
그 결과를 HttpServletRequest 객체에 담아 제공한다.
httpServletRequest.getMethod();
httpServletRequest.getProtocol();
httpServletRequest.getRequestURL();
httpServletRequest.isSecure();
httpServletRequest.getHeaderNames();
httpServletRequest.getCookies();
httpServletRequest.getContentType();
...
//요청 메시지를 확인할 수 있는 여러 메서드 제공
/url?query=value
메시지 바디없이, URL의 쿼리 파라미터에 데이터 전달
서버에서 조회방법
//단일
request.getParameter(name);
//복수
request.getParameterValues();
reqeust.getParameterNames();
JSON, XML, TEXT 등
주로 JSON 사용
서버에서 조회방법: InputSteam을 사용해서 직접 읽을 수 있다.
import com.fasterxml.jackson.databind.ObjectMapper;
ServletInputStream inputStream = request.getInputStream();
//인코딩 방식을 utf-8로
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF-8);
//messageBody가 JSON형식일 경우 jackson 라이브러리의 ObjectMapper클래스를 활용하여 객체로 받을 수 있다.
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
HTTP 응답메시지 생성: 응답코드, 헤더, 바디
기본 사용법
response.setStatus(HttpServletResponse.SC_OK);
response.setHeader("Content-Type", "text/plain;charset=utf-8");
...
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
...
Cookie cookie = new Cookie("name","value");
cookie.setMaxAge(600);
response.addCookie(cookie);
...
response.sendRedirect("/.../...");
content-type을 application/json로 지정해줘야 한다.
Jackson 라이브러리 사용 객체 → 문자(JSON)
HelloData helloData = new HelloData();
String result = objectMapper.writeValueAsString(helloData);
컨트롤러: HTTP 요청 검증, 비즈니스 로직 실행, 뷰에 데이터 전달
뷰: 전달받은 데이터 렌더링에 집중
모델: 뷰에 출력할 데이터를 담아둠
컨트롤러가 너무 많은 일을 담당하기에 service, resository 등 별도의 계층을 만듬
서버 소스
Member member = new Member(username, age);
//Model에 데이터를 보관한다.
//컨트롤러: request.setAttribute로 데이터 보관
//뷰 : request.getAttribute로 데이터 조회
request.setAttribute("member", member);
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
//다른 서블릿이나 JSP로 이동할 수 있는 기능, 서버 내부에서 다시 호출이 발생
dispatcher.forward(request, response);
컨트롤러 역할과 뷰를 렌더링하는 역할이 구분 되어짐
하지만 중복코드가 많이 발생
//포워드 중복
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
//뷰패스 중복
String viewPath = "/WEB-INF/views/new-form.jsp";
사용하지 않는 코드
공통 처리가 어렵다
스프링 부트는 InternalResourceViewResolver라는 뷰 리졸버를 자동으로 등록
application.properties에 등록한 정보 사용
spirng.mvc.view.prefix=/WEB/INF/views
spring.mvc.view.suffix=.jsp
consume
@PostMapping(value = "/mapping-consume", consumes = "application/json")
//HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑
//만약 맞지않으면 HTTP 415(Unsupported Media Type)을 반환
produces
@PostMapping(value = "/mapping-produce", produces = "text/html")
//HTTP요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑
//만약 맞지않으면 HTTP 406(Not Acceptable)을 반환
@RequestMapping("/headers")
public String headers(
HttpServletRequest request,
HttpServletResponse response,
HttpMethod httpMethod,
Locale locale,
@RequestHeader MultiValueMap<String, String> headerMap
@RequestHeader("host") String host,
@CookieValue(value = "myCookie", required = false) String cookie
){}
스프링이 제공하는 ModelAndView
Model데이터를 추가할때 addObject()사용
ModelAndView mv = new ModelAndView("save-result");
mv.addObject("member", member);
request.getParameter() 같은효과
public String save(@RequestParam("username") String name){}
//변수명과 HTTP파라미터 이름이 같으면 생략가능
public String save(@RequestParam String username){}
//String, int 등 단순 타입이면 다 생략가능
public String save(String username){}
RequestParam(required = true, false , defaultValue = “”)
Map 사용
public String paramMap(@RequestParam Map<String, Object> paramMap) {}
SLF4J(통합인터페이스) - http://www.slf4j.org
Logback(구현라이브러리) - http://logback.qos.ch
로그 레벨 설정
#전체 로그 레벨 설정(기본 info)
logging.level.root=info
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug
올바른 로그 사용법
스프링부트가 제공하는 로그 기능
URL경로에 매칭되는 부분을 조회
사용
@GetMapping("/mapping/{userId}")
public String mapping(@PathVariable("userId") String id){}
//변수명과 이름이 같을경우 생략가능
public String mapping(@PathVariable String userId){}
요청 파라미터를 객체에 바로 바인딩 해준다.
사용
public String modelAttribute(@ModelAttribute HelloData helloData) {}
//생략 가능
public String modelAttribute(HelloData helloData) {}
요청 파라미터의 이름으로 객체의 프로퍼티를 찾는다
그리고 해당 프로퍼티의 setter를 호출해서 값을 바인딩 한다.
BindException
메시지 바디 정보를 직접 조회, 반환 할 수 있다.
HttpMessageConverter 사용 → StringHttpMessageConverter 적용
사용
public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity) {
String messageBody = httpEntity.getBody();
return new HttpEntity<>("ok");
}
HttpEntity를 상속받은 객체
객체 반환 사용
public String requestBodyJson(HttpEntity<HelloData> httpEntity) {
HelloData data = httpEntity.getBody();
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
사용
public String requestBodyString(@RequestBody String messageBody) {
log.info("messageBody={}", messageBody);
return "ok";
}
편리하게 HTTP 메시지 바디 정보를 조회할 수 있다.
헤더 정보가 필요하면 HttpEntity 또는 @RequestHeader를 사용하면 된다.
객체 변환 사용
//@RequestBody 생략 불가능
//생략할경우 @ModelAttribute가 되버림
//HttpMessageConverter 사용
//->MappingJackson2HttpMessageConverter 적용(content-type=application/json일때)
public String requestBodyJson(@RequestBody HelloData data) {
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
응답결과를 HTTP 메시지 바디에 직접 담아서 전달
객체 반환 사용
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
log.info("username={}, age={}", data.getUsername(), data.getAge());
return data;
}
logging.level.org.apache.coyote.http11=debug
build.gradle
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'
출처 : 인프런 김영한 스프링MVC1편 - 백엔드 웹개발 핵심 기술