어떻게 스프링이 등장하게 되었는지
그 내용을 순차적으로 한페이지로 정리해보려고 한다.
Web Application Server가 무엇인가
Web Server는 무엇인가
둘을 구분짓자면 Web Application Server는 동적인 페이지의 구현을 담당한다. Web Server는 정적인 페이지의 구현을 담당한다.
페이지를 담당한다라는 이 말을 서버에 저장된 html파일을 클라이언트에게 보낸다는 것이다.
정적인 페이지라는 것은 html 파일 그 자체를 가져와서 그대로 클라이언트에게 전달하는 것을 말한다. 예를 들어 회사의 비전처럼 잘 바뀌지 않는 페이지를 말한다.
동적인 페이지라는 것은 html 파일에 뭔가 동적인 비즈니스 로직이 섞여있는 페이지라고 볼 수 있다. 예를 들어 시간마다 달라지는 날씨, 내가 작성하면 바로바로 update되는 블로그 글처럼 html 파일 자체만으로는 구현될 수 없고 java를 통해서 결과를 도출하고 이 결과를 html파일에 함께 실어서 클라이언트에게 보여줘야 하는 페이지를 의미한다.
이 동적인 페이지를 서버에서 구현하는 여러가지 방법이 있는데
어떻게 발전되어 왔는지 그 순서대로 살펴보자.
Servlet : "자바 서블릿은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말하며, 흔히 "서블릿"이라 불린다. 자바 서블릿은 웹 서버의 성능을 향상하기 위해 사용되는 자바 클래스의 일종이다."
간단하게 설명하면 웹으로부터 요청을 받거나 응답을 보내는 것을 개발자 쉽게 구현할 수 있도록 도와주는, 관리해주는 역할을 하는 자바 웹 프로그래밍 기술이다.
@WebServlet(name="frontControllerServletV4", urlPatterns = "/front-controller")
public class FrontControllerServletV4 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
클라이언트가 "http://기본도메인/front-controller"를 입력하며
컨트롤러 : Http 요청을 받아서 파라미터 검증하고, 비즈니스 로직을 실행 + 뷰에 전달할 결과 데이터를 조회해서 모델에 담는다.
모델
뷰
한계점 : viewPath 중복 , 포워드 중복, 사용하지 않는 코드 존재 (HttpServletResponse의 경우 사용되지 않는데 계속 존재)
또한 HttpServletResponse 및 HttpServletRequest를 사용하는 코드는 테스트케이스 작성이 어렵다 왜냐하면 Http에 대한 요청과 응답은 웹브라우저를 통해서 데이터를 주고 받는 환경이 구축되어야 가능하기 때문이다.
파라미터 자체에 model을 담아 버린다.
컨트롤러가 달라질 때마다 포스트 컨트롤러 또한 수정해야 한다.
이를 해결하기 위한 어댑터 패턴이 존재한다.
어댑터 패턴에는 두가지가 등장한다.
스프링 MVC도 프론트 컨트롤러 패턴으로 구현된다.
DispatcherServlet= 스프링의 프런트 컨트롤러
스프링은 핸들러 어댑터와 핸들러 매핑을 대부분 구현
개발자는 이미 구현된 핸들러 어댑터와 핸들러 매핑을 사용한다.
뷰리졸버: 뷰페이지의 이름을 물리적 주소로 변환해주는 역할을 담당하는데 스프링의 뷰리졸버는 InternalResourceViewResolver라는 뷰 리졸버를 자동으로 등록한다.
이때 application.properties에 있는 설정 정보를 사용해서 등록
@RestController
public class MappingController {
private Logger log = LoggerFactory.getLogger(getClass());
@GetMapping("/mapping/{userId}")
public String helloBasic(@PathVariable("userId") String data) {
log.info("mappingPath userId={}",data);
return "ok";
}
}
@RestController
....
@GetMapping(value="/mapping-param",params="mode=debug" )
public String helloBasic() {
log.info("mappingParam");
return "ok";
}
@RestController
...
@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){
log.info("request={}",request);
log.info("response={}",response);
log.info("httpMethod={}",httpMethod);
log.info("locale={}",locale);
log.info("headerMap={}",headerMap);
log.info("header host={}",host);
log.info("myCookie={}",cookie);
return "ok";
}
http://localhost:8080/request-param-required?username=
를 입력했다고 하자. 그려면 username은 null이 아니라 빈문자열이 된다.http://localhost:8080/request-param-default?username=
이와 같이 빈문자열로 get요청을 하면http://localhost:8080/request-param-map?username=kined&username=lim&age=14&age=25
이런 식으로 key에 대한 value값이 많을 때는 @RequestParam MultiValueMap
HelloData라는 클래스가 있을 때 @ModelAttribute는 HelloData 객체를 생성하고 요청 파라미터의 이름(username, age)을 파라미터로 가지고 있는 setter(setUsername(), setAge())를 호출해서 값을 저장한다.
파라미터가 아니다!
InputStream을 이용해서 읽음
텍스트와 마찬가지로
InputStream을 이용해서 메시지 바디에 있는 Json형태의 데이터를 읽어온다.
또한 Json-> java객체로 바꾸는 작업은 ObjectMapper의 readValue()메서드를 이용한다.
@RequestBody를 통해서 message body에 있는 내용 직접 조회하고 @ResponseBody로 내용 실어서 보내기
@RequestBody + 메세지 컨버터를 이용해서 message body에 있는 내용을 원하는 모양의 객체로 바로 넣어버리기
HttpEntity + 메세지 컨버터를 이용해서 message body에 있는 내용을 원하는 모양의 객체로 바로 넣어버리기
@ResponseBody + 메세지 컨버터를 이용해서 객체 데이터를 Json형태로 변환 없이 바로 message body에 넣어버리기 (객체->메서지 컨버터 -> Json)
정적 리소스는 그냥 html 파일 그대로 보내는 것
스프링 부트는 /static,/resources,/public,/META-INF/resources
에 정적 리소스를 저장한다.
뷰템플릿은 동적인 리소스로 HTML을 동적으로 만들어서 클라어인트에게 전달한다.
HTTP 메세지는 HTML이 아닌 데이터를 전달하는 것, HTML 페이지를 클라이언트가 가지고 있다.
저기 형광펜으로 칠해진 파일을 호출한다고 가정한다.
위와 같이 사용하기 위해서는 application.properties에 아래와 같은 설정이 되어 있어야 한다.
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
class에 @Controller가 있지만 반환값이 없기 때문에 view를 호출하지 않는다. 또한 HttpServletResponse 객체를 통해서 HTTP 메시지 바디에 "ok" 직접 입력