SpringBoot Part3 (2)
DispatchServlet
Front Controller Pattern
: 하나의 servlet
: Front contoller가 모든 요청을 받아 다른 컨트롤러를 호출하고 로직을 위임한다.
→ Spring은 Front Controller Pattern을 사용한 DispatchServlet을 제공
Spring MVC 처리 흐름
- DispatcherServlet의 HTTP 요청 접수
- DispatcherServlet에서 컨트롤러로 HTTP 요청 위임
- 컨트롤러의 모델 생성과 정보 등록
- 컨트롤러의 결과 리턴: 모델과 뷰
- DispatcherServlet의 뷰 호출과 (6) 모델 참조
- HTTP 응답 돌려주기
DispatchServlet 만들기 (HTTP 요청 접수)
- WebApplicationInitializer
- web.xml
DispatchServlet에서 HTTP 요청 위임
: 스프링에서는 컨트롤러를 핸들러라고도 부름
: 사용자 요청을 기준으로 어떤 핸들러에게 작업을 위임할지응 결정해주는 것 → 핸들러 매핑 전략
(RequestMappingHandlerMapping을 가장 많이 사용함)
: 제각기 다른 메소드 포맷을 가진 컨트롤러를 DispatcherServlet이 어떻게 알아서 호출 할까? →HandlerAdapter 전략
DispatchServlet의 뷰 호출 → ViewResolver
전체 흐름
https://terasolunaorg.github.io/guideline/public_review/Overview/SpringMVCOverview.html
KdtWebApplicationInitializer로 Spring MVC initalizer하기
직접 application context만들기
실습 - JSP
https://www.baeldung.com/spring-boot-jsp
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
: 렌더링 엔진?
: jstl → 태크 라이브러리. 반복문등을 쉽게 사용할 수 있다.
: 현업에서 jsp 많이 안쓴다. 가볍게 보기
public class KdtWebApplicationInitializer implements WebApplicationInitializer {
private static final Logger logger = LoggerFactory.getLogger(KdtWebApplicationInitializer.class);
@EnableWebMvc // spring api에 필요한 bean들이 자동으로 등록
@Configuration
@ComponentScan(basePackages = "org.prgrms.kdt.customer")
@EnableTransactionManagement
static class AppConfig {
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = DataSourceBuilder.create()
.url("jdbc:mysql://localhost:2215/order_mgmt") //실제 db
.username(id)
.password(pw)
.type(HikariDataSource.class) // datasource 만들 구현체 타입 지정
.build();
return dataSource;
}
@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
@Override
public void onStartup(ServletContext servletContext) {
// dispatcherServlet
var applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(AppConfig.class);
var dispatcherServlet = new DispatcherServlet(applicationContext);
logger.info("starting server...");
var servletRegistration = servletContext.addServlet("test", dispatcherServlet);
servletRegistration.addMapping("/");
servletRegistration.setLoadOnStartup(-1);
}
}
--
// 컨트롤러 만들기
@Controller
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@RequestMapping(value = "/customers", method = RequestMethod.GET)
public ModelAndView findCustomers(){
var allCustomers = customerService.getAllCustomers();
// 이름에 해당하는 veiw를 찾고 해당 view가 랜더링 된다. -> 해당 view customers.jsp가 WEB-INF안에 존재해야한다.
return new ModelAndView("customers",
Map.of("serverTime", LocalDateTime.now(),
"customers",allCustomers));
}
}
jsp 파일
https://daesuni.github.io/jstl/
static resource 처리하기
: WebMvcConfigurer를 상속받아 다양한 설정을 변경할 수 있다.
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "org.prgrms.kdt.customer")
@EnableTransactionManagement
static class AppConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources")
.setCachePeriod(60) // 캐시보관 시간
.resourceChain(true)
.addResolver(new EncodedResourceResolver()); // 알아서 압축해줌
}
....
}
실습 - Thymeleaf
Thymeleaf
: java template engin
: html 파일로 작성
: 컴파일하지 않고 탬플릿을 파싱해서 응답으로 보내질 contents를 만들어준다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
--
@EnableWebMvc // spring api에 필요한 bean들이 자동으로 등록
@Configuration
@ComponentScan(basePackages = "org.prgrms.kdt.customer")
@EnableTransactionManagement
static class AppConfig implements WebMvcConfigurer, ApplicationContextAware {
ApplicationContext applicationContext;
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
var springResourceTemplateResolver = new SpringResourceTemplateResolver();
springResourceTemplateResolver.setApplicationContext(applicationContext);
springResourceTemplateResolver.setPrefix("/WEB-INF/");
springResourceTemplateResolver.setSuffix(".html");
var springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setTemplateResolver(springResourceTemplateResolver);
var thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(springTemplateEngine);
thymeleafViewResolver.setOrder(1);
registry.viewResolver(thymeleafViewResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources");
}
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = DataSourceBuilder.create()
.url("jdbc:mysql://localhost:2215/order_mgmt")
.username(id)
.password(pw)
.type(HikariDataSource.class) // datasource 만들 구현체 타입 지정
.build();
return dataSource;
}
@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
--
@Controller
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
//@RequestMapping(value = "/customers", method = RequestMethod.GET)
@GetMapping( "/customers")
public String findCustomers(Model model){
var allCustomers = customerService.getAllCustomers();
model.addAttribute("serverTime", LocalDateTime.now());
model.addAttribute("customers",allCustomers);
return "view/customers";
}
}
표현식
th 확장자 추가 : <html xmlns:th="http://www.thymeleaf.org">
- 변수 식 : ${ 객체의 key값 }
- 링크 식 : @{ 링크 }
- 선택 변수 식 : *{ }
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Hello</h1>
<p th:text="'the time on the server is '+${serverTime}">
------
</p>
<img th:src="@{/resources/bg.png}">
<table border="1">
<tr th:each="customer: ${customers}" th:object="${customer}" >
<td th:text="${customer.customerId}"></td>
<td th:text="*{name}"></td>
<td th:text="*{email}"></td>
<td th:text="*{createAt}"></td>
<td th:text="*{lastLoginAt}"></td>
</tr>
</table>
</body>
</html>
jsp나 thymelef같은 view 기술을 사용하기보단 퓨어하게 API는 JSON만(resource만) 리턴하고 view 렌더링은 하지않는 추세이다.
dispather servlet이 어떻게 controller를 select해서 메소드를 mapping해서 invoke되고 parameter가 어떻게 값을 전달하고 return된것으로 어떻게 view resolve가 만들어지는지 흐름을 익혀야한다.
출처 - 해리 : SpringBoot Part3
'Back-end 데브코스 > week 03 - 05 TIL (Spring)' 카테고리의 다른 글
[TIL] 221117 - SpringBoot Part3 : 단일 페이지 웹 어플리케이션, CORS (0) | 2022.11.24 |
---|---|
[TIL] 221116 - SpringBoot Part3 : WebApplicationContext, REST API (0) | 2022.11.24 |
[TIL] 221114 - SpringBoot Part3 : 웹 기술 Overview, Servelt (0) | 2022.11.22 |
[TIL] 221111 - SpringBoot Part2 : 트랜잭션과 AoP (1) | 2022.11.22 |
[TIL] 221110 - SpringBoot Part2 : Embedded DB, Named Parameter Template, 트랜잭션 (0) | 2022.11.11 |
댓글