Spring boot camp #2
JSP & Servlet
- Spring MVC
- 내부적으로는 Servlet, JSP를 사용
- 따라서 Spring을 사용하기 위해서는 Servlet, JSP에 대한 이해를 해야 함
- 응집도의 개념이란 관련된 기능을 하나의 class가 모아 지니고 있는 것
- Spring Framework를 이용하는 spring boot
- 따라서 Spring에 대한 이해를 하는 것이 좋음
- Spring boot를 사용하면 설정해주지 않아도 되는 부분드리 많지만, 현업에서 이미 Spring으로 작성된 프로젝트를 관리해야 할 일들도 많이 있기 때문
Java 웹프로그래밍의 시작, Servlet & JSP
- Servlet 3.0 이전에는 web.xml 설정을 해주어야 함
- 하나의 path 설정하는 것이 하나의 servlet
- 결국, 응집도가 떨어지는 결과 -> 문제
- 3.0 이후부터는 annotation을 이용해서 path 설정
- JSP는 HTML code와 Java code를 섞어서 작성하는 것
- 서버에서 JSP가 java code로 바뀜
- <h1>hello</h1>이라는 HTML line이 out.write("<h1>hello</h1>")로 변환되는 것
- 즉, out이라는 Java 변수가 위에 선언되어야 하는 것 -> JSP 내장 객체
- 근래에는 Java code 잘 사용 안하려고 함
- JSTL과 EL로 결과값만 출력하자! 는 것이 대세
Servlet의 구성
class 'servlet_name' extends HttpServlet{
doGet()
doPost()
Service
...
}
After JEE Pattern
- Java로 기업급에서 프로그래밍을 할 때는 이러한 패턴을 사용하자!
Front controller도 그 JEE Pattern 하나
- browser가 하는 모든 요청을 이 놈이 받도록 함
- Servlet으로 작성할 수도, JSP로 작성할 수도, ServletFilter로 작성할 수도 있음
Spring MVC는 Servlet으로 Front Controller 만듬
- Spring MVC의 DispatcherServlet이 Front Controller의 역할 수행
- 즉, Spring MVC의 life cycle이 궁금하다면 DispatcherServlet을 공부해야 함!
- WAS가 DispatcherServlet을 메모리에 올려주는 역할 수행
- 1) web.xml에 등록(143.p)
- 배포를 1초라도 빨리하려면 web.xml에 DispatcherServlet 등록해주는 것이 좋음
- 명시적인게 빠르기 때문
- 2) 서블릿 3.0 이상에서는 ServletContainerInitializer 인터페이스 사용 -> WAS용 Java config
- 3) but, Spring 쪽에서는 모든 객체를 Spring 쪽에서 관리해주고 싶어함
- WebApplicationInitializer 인터페이스 구현해서 사용 -> Spring용 Java config
- Servlet 인터페이스를 보고 Spring interface를 확인하기 때문에 배포 속도가 가장 느림
- DispatcherServlet은 내부적으로 WebApplicationContext(Bean Container)를 지님
Front Controller는 관련된 url 요청들을 분배하는 역할을 수행하게 됨
- 관련된 url을 처리하는 객체를 Spring MVC에서는 'xxx'Controller라고 부름
- cf.명령을 처리한다는 개념에서 Command Pattern이라고 부르기도 함
- 프로그래머가 만들고 Spring이 관리해주는 객체
- @Controller 혹은 @RestController 라는 annotaion이 붙어있어야 함
- Web에 종속적인 기술
- Spring containter가 Component scan을 통해 annotation 붙어있는 객체들 찾음
- 다 Bean으로 등록해줌
- Bean이란 Spring이 관리해주는 객체
- 공통적으로 처리되는 부분들은 객체 하나를 사용해서 중복되게 사용되도록 사용할 수 있음
- 'xxx'Service라 불리우는 객체 !
- 즉, 하나의 Controller가 여러 개의 Service를 사용하도록 하는 것 ! (중복된 기능을 제공하기 위해서)
- @Service annotation 사용
- Service 안에서 또 중복된 기능을 사용
- 대개, CRUD 기능이 중복된 코드일 가능성이 높음
- 이러한 기능을 Repository 혹은 DAO라고 부름
- @Repository annotation 사용
이처럼 FrontController-'xxx'Controller-'xxx'Service의 계층으로 나뉘어져 구성되기 때문에 'Layered Architecter' 라고 부름
Service와 Repository는 별도의 ApplicationContext 필요 (Business Logic 관리하기 위해)
- Service와 Repository에 해당하는 객체만 관리해줌
- WebApplicationContext은 Service와 Repository 객체를 사용하기 위해 ApplicationContext를 부모로 가짐(141.p)
- 자식 container는 부모 container로 부터 객체 먼저 찾음
- 부모가 가지고 있는 Service를 자식의 Controller에 넣어주게 됨
- 중요한 것은 Context 간에 부모-자식 관계가 있을 수 있다는 것
경우에 따라서 DispatcherServlet을 여러 개 선언할 수도 있음
- /board를 1번 Dispatcher가,
- /users를 2번 Dispatcher가 관리하도록 함
- 따라서 WebApplicationContext도 2개 생성됨
- Container를 따로 사용하기 때문에 1번 Dispatcher에서의 객체를 2번 Dispatcher에서 사용 불가
- 마치 한 서버에 있지만, 두 서버에 있는 듯한 느낌
- 나중에 Micro service 단위로 분할하기 편하게 하기 위해 사용하는 경우가 있긴 하나 잘 사용되지는 않는 기법
Controller
@Controller
@RequsetMapping("/board")
class test{
@RequsetMapping("/list")
static void testmethod(){
...
}
}
- Spring 4.3 버전 이후부터 RequestMapping 외 GetMapping, PostMapping, PutMapping 등도 등장
- class의 mapping 정보와 method의 mapping 정보가 결합된 것이 실제 url 주소
- Controller를 url을 처리해준다하여 Handler라고도 부름
- HandlerMapping이라는 객체가 존재하여, url 관리
- 어떤 Controller의 method와 관련이 있다는 정보들을 저장
- 즉, 내부적으로 DispatcherServlet의 관리해주는 것
- 유효한 요청을 받았을 시, HandlerAdapter로 보내 실행
- Controller method는 보통 View 이름 return
- ModelAndView 혹은 String 객체로 return
- HTTP header에는 accept 정보 존재
- browser가 원하는 data format(ex. html, json, xml...)
- ViewResolver는 어떤 view를 보여줄지에 대한 전략을 세워줌
- 경로 작성해주고, data format 찍어주어 view 생성하여 return
- ex) WEB-IMF/views... + /list + .jsp
- ViewResolver도 여러 개 존재해서, 요청한 data format에 따라 다르게 처리 가능
- Java config에서 default 값들 설정해주면 됨
- DispatcherServlet과 Controller 사이에 Interceptor 여러 개 존재할 수 있음
- 모든 요청에 대해 공통으로 처리해줄 수 있음
- Dispatcher 앞에 존재할 수 있는 ServletFilter와 유사한 역할 수행
실습
- Lombok 적용: Preference -> Compiler -> annotation processor -> enable annotation processing
- @Configuration 붙어있는 class들은 Java config
- @ConditionalOn이 붙어있는 annotation은 중요한 annotation
- ex) ConditionalOnMissingBean
- 사용자가 AutoConfig 사용하지 않고 Bean 직접 생성했을 때 자동 설정을 사용하지 않겠다는 설정
- spring.factories에서 기본 설정 확인 가능
- dispathcer servlet 생성해줌
- MultipartResolver는 file upload용
- Spring 구버전의 @RequestMapping(method = RequestMethod.GET)가 GetMapping이 됨
- Spring에서 JSP로 결과 출력하려면 JSTL 의존성 추가해주어야 함
- tomcat에 기본적으로 포함된 것이 아니기 때문
- pom.xml과 application.properties에 다음 설정 추가
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp
- http://www.inven.co.kr/board/{game name}/{board id}
- 위 예에서 'game name'과 'board id'는 Path variable
http://www.inven.co.kr/board/{game name}/{board id}/?sort=PID&p=1
- 위 예에서 ? 이하의 값은 Request Parameter
- 이름=값&이름=값 의 형태로 전달
내가 입력한 값들을 저장해야 하는 서버
- 이전 입력 값들에 대한 parameter를 계속 가지고 다녀야 함
form 도 requestParam으로 읽어올 수 있음
redirect?
- 요청을 하는 WebClient와 요청을 받는 WAS의 존재를 가정
- form을 POST 방식으로 입력
- HTTP message에는 POST /boards 방식 명시되고, header 정보 이후 body 부분에 user가 입력한 값이 실림
- 1) @RequestParam으로 입력 값 읽어드릴 수 있고,
- 2) form의 입력 값이 너무 많을 시, @ModelAttribute 사용
- @ModelAttribute Board board와 같이 정의
- set으로 값 채워넣음
- +) 값을 validate하는 기능 필요
- 값이 잘못되어있으면 다시 입력하라는 메시지와 함께 이전 정보들 재전송
- hibernate에 검증 기능 구현
- Forward vs. Redirect
- viewname을 return하는 방식은 다 forward
- forward와 밀접한 관련이 있는 것이 RequestScope
- 요청 정보는 해당 정보와 관련있는 JSP까지 전달됨
- SetAttribute로 Request에 값을 담고, GetAttribute로 값을 꺼냄
- JSP는 RequestScope에서 정보를 꺼내서 결과 출력
- redirect는 view를 생성하지 않고, browser에게 redirect하라는 명령 (status code: 302)
- browser는 redirect하라는 주소로 다시 요청보냄
- 최종적으로 redirect 주소 정보를 받아와 읽게 됨
- redirect를 할 때도 정보 전달 가능 -> RequestParam을 통해
- 그러나, header 길이의 한계로 큰 data는 redirect로 전송이 불가능함
- Spring MVC의 FlashMap 객체 이용해 정보 저장 가능
- 이후, distpatcherServlet이 FlashMap의 정보를 꺼내서 browser에 제공
- 해당 FlashMap 정보는 1회용 !
@RequestBody와 @ModelAttribute 혼동하지 말자!
- @RequestBody는 body에 JSON과 같은 데이터 넘어올 때 사용
- body가 form data 형식으로 넘어오면 @ModelAttribute 사용
반환할 객체에 값을 자동으로 채워넣어주는 ArgumentResolver
- 먼저, 내가 지원하는 type인지를 검사
- Controller method에 객체를 반환해줌
- Interceptor를 구현하여 값을 검사하거나, 삭제하거나, 검증하는 등의 기능을 구현할 수도 있음
- 작성한 ArgumentResolver와 Interceptor는 Java config에 등록을 해주어야 사용 가능
- Spring MVC가 읽어들이는 설정에 ArgumentResolver와 Interceptor를 등록해주어야 함
- ex) WebMvcConfigurer를 구현한 Config class에 두 객체를 모두 등록하여 사용
etc
- 잘 만들어진 객체는 보는 것만으로도 공부가 됨
- 기술면접에서 화이트보드 면접이 잦아짐
- 모든 Web의 기본은 게시판!
- 프로젝트 주제를 신중하게 정하자
- 본인이 계속 운영하고 싶은 페이지를 만들어라!
- open source로 만들어 계속 version up
- 이후, 이직 과정에서 포트폴리오로 사용할 수 있음
- Why? 내가 사용하지 않는 코드는 version up이 되지 않음
- 또한 개발이 50%라면, 운영 역시 50% 만큼의 능력을 요함
- Paper Prototyping을 하자!
- 웹 페이지 어떻게 구성될 것인지 detail하게 그려가며 구상
- 디자인에 신경을 쓰지 않더라도, 최소 bootstrap 정도는 이용하는 것이 좋음
- 앞으로는 Java 8을 공부해야 함
- Stream, lambda 등의 신규 문법 숙지!
- 절대로 운영중인 서버에는 sysout 사용하지 마라
- 성능이 엄청 떨어짐
- 대신, logger 객체를 이용해야 함
- 어느 한 interface가 있고, 다른 class에서 해당 interface를 구현해야 함
- 이전에는 이러한 불편함 해결하기 위해 Myinterface를 구현한 MyAdapter라는 default 클래스 제공
- 해당 interface의 method들을 구현하고 있지만, 내용은 없음
class MyAdapter implements Myinterface{
...
...
}
class MyBean extends MyAdapter{
필요한 것만 Override해서 사용!
}
- jdk 8부터는 default method 기능 추가됨
- 이제 interface도 method 구현이 가능해짐!
- Why? Framework 측에서 제공하는 interface에 method 추가하고 싶은데,
- 이미 framework를 사용하고 있는 수 많은 프로젝트들 때문에 함부로 추가하지 못함
- 함부로 method의 갯수를 늘리면 모든 프로젝트가 에러나게 생김
- default로 구현된 method를 추가하여 배포하면 문제없이 사용할 수 있게 될 것이라는 개념에서 비롯됨