Filter - API(인터페이스)
업무에 대한 서블릿 - 업무마다 존재하기에 중복도 있음 → 제거하는데 Filter사용
1. 업무 전처리
2. 처리
3. 업무 후처리
공통된 부분을 모아서 Filter(인터페이스)
1. 전처리
2. 서블릿 호출
3. 후처리 → MdelAndView(이제 사용x), Model, ModelMap
스프링의 경우 Front 서블릿인 DispatcherServlet 호출
→ 각 처리단계로 이어짐(같은처리 혹은 다른 처리), 서블릿계층(스프링에선 컨트롤러와 같음)
context는 저장소
서블릿 컨텍스트 - 필터사용
Servlet Context에 필터거주 - 필터 통해 서블릿 경유
WebApplication Context에 인터셉터 거주
Servlet Context에 사용자가 요청하고 Servlet이 요청받음 → Spring에 WebApplicationContext가 받음
서블릿 컨테이너를 WAS(Tomcat)이 쥐고있다(자세힌 jsp-api.jar와 servlet-api.jar)
Spring 컨테이너(BeanFactory와 ApplicationContext)
Interceptor → Controller
1. 전처리
2. 컨트롤러 메소드
3. 후처리
여러 빈 존재 가능(빈[객체]들에 대한 객체주입을 인터셉트가 받을 수 있다) → 필터와의 차이점
필터와 인터셉터
1. Filter가 발전하여 Interceptor가 됨
2. 서블릿이 발전해서 컨트롤러가 됨
전처리에서는 사용자로부터 입력을 받는다
Filter는 DispatcherServlet과 역할이 비슷하다
JSP와 서블릿이 발전해서 스프링이 되었다
설계방법에서 분리의 기술
1. 관심사 분리
2. 변하는 것과 변하지 않는 것
3. 중복코드
Interceptor는 Filter와 유사한 기능
FIlter와는 달리 WebApplicationContext에 위치하고 빈 주입이 가능하다
이것은 ServletContext(저장소)와 WebApplicationContext 모두 저장소
<필터와 인터셉터로 서비스 수행시간 계산 - Mblog1Application.java>
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@SpringBootApplication
@ServletComponentScan
public class Mblog1Application {
public static void main(String[] args) {
SpringApplication.run(Mblog1Application.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 두 포트번호 모두 서비스를 제공하지만 3000번은 동기화된 서비스 제공, 7000번은 build된 코드까지만 제공된다
// 결과적으로 3000번은 개발 서버로, 7000번은 서비스 서버로 하용하면 될 것이다
registry.addMapping("/**").allowedOrigins("<http://localhost:3000>", "<http://localhost:7000>");
}
};
}
}
<필터와 인터셉터로 서비스 수행시간 계산 - CustomerFilter.java>
package com.example.demo.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@WebFilter(urlPatterns = "/*")
public class CustomerFilter implements Filter {
Logger logger = LogManager.getLogger(CustomerFilter.class);
/****************************************
* @param : 요청객체
* @param : 응답객체
* @param : 서블릿 또는 다음 필터 호출하는데 사용
****************************************/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("doFilter");
// 1. 전처리
long startTime = System.currentTimeMillis();
// 2. 처리
chain.doFilter(request, response);
// 3. 후처리 - 서비스 수행 시간 계산(performance)
long endTime = System.currentTimeMillis();
System.out.print(((HttpServletRequest)request).getRequestURI());
// 수행시간(종료시간 - 시작시간)
System.out.println("수행시간: " + (endTime - startTime) + "ms");
}
}
<필터와 인터셉터로 서비스 수행시간 계산 - CustomerServlet.java>
package com.example.demo.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/custom")
public class CustomerServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// 1. 전처리
long startTime = System.currentTimeMillis();
// 2. 처리
int idx1 = (int)(Math.random()*6)+1;
int idx2 = (int)(Math.random()*6)+1;
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
out.println("<html>"); // ln은 line skip(줄바꿈)이 아니고 여기까지 말했다는 의미
out.println("<head><title>필터실습</title></head>");
out.println("<body>");
out.println("내용입니다.");
out.println("</body>");
out.println("</html>");
// 3. 후처리 - 서비스 수행 시간 계산(performance)
long endTime = System.currentTimeMillis();
System.out.print(((HttpServletRequest)req).getRequestURI());
// 수행시간(종료시간 - 시작시간)
System.out.println("수행시간: " + (endTime - startTime) + "ms");
}
}
<필터와 인터셉터로 서비스 수행시간 계산 - CustomerInterceptor.java>
package com.example.demo.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
// 하나의 메소드는 하나의 책임만 갖는다 - 설계시 주의사항
@Component // 추가해야 CustomerInterceptor가 ApplicationContext가 되도록 해줌
public class CustomerInterceptor implements HandlerInterceptor {
Logger logger = LogManager.getLogger(CustomerInterceptor.class);
/*
필터나 인터셉트나 컨트롤러 같은 것들은 서버 프로그램이기 때문에 싱글톤이라는 것을 명심할 것!
싱글톤이라서 여러 스레드가 하나의 객체를 공유한가는 것이 주의할 점이라는 의미임
다른 스레드가 startTime을 다른 값으로 덮어쓰기하는 경우가 발생할 수 있음
그래서 여기서는 후처리에 필요한 startTime을 요청객체에 setAttribute해서 사용함
*/
// 전처리를 구현하는 메소드
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
logger.info("전처리 구현 메소드");
// 1. 전처리
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
// preHandle의 세번쨰 파라미터 handler는 요청과 연결된 컨트롤러의 메소드임
HandlerMethod method = (HandlerMethod)handler;
logger.info("method.getMethod() => " + method.getMethod()); // URL과 연결된 메소드명
logger.info("method.getBean() => " + method.getBean()); // 메소드가 포함된 컨트롤러 -> 컨트롤클래스 주소번지
return HandlerInterceptor.super.preHandle(request, response, handler);
}
// 후처리를 구현하는 메소드
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
logger.info("후처리 구현 메소드");
long startTime = (long)request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
logger.info(((HttpServletRequest)request).getRequestURI());
// 수행시간(종료시간 - 시작시간)
logger.info("수행시간: " + (endTime - startTime) + "ms");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
}
<필터와 인터셉터로 서비스 수행시간 계산 - WebMvcConfig.java>
package com.example.demo;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.example.demo.servlet.CustomerInterceptor;
// WebMvcConfig의 addInterceptors가 있어야 사용자 정의 인터셉터 사용가능
// 이런 설정들은 반드시 Configuration 어노테이션 붙여야함
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomerInterceptor())
.addPathPatterns("/**"); // 와일드카드 2번 써야함 -> 인터셉터를 적용할 대상을 설정함
}
}
<함수, 컴포넌트 예제 - TentPage.jsx>
import React, { useEffect, useState } from 'react'
import ScheduleHeader from '../include/ScheduleHeader'
import ScheduleFooter from '../include/ScheduleFooter'
import TentSideBar from '../tent/TentSideBar'
import TentMain from '../tent/TentMain'
import styles from './tent.module.css'
import axios from 'axios'
const TentPage = () => {
const [tentList, setTentList] = useState([])
const getTentList = (name, value) => {
console.log(name + "=> " + value)
if("first" === name) {
axios.get("/tent.json").then(res => {
setTentList(res.data)
if(value) {
const tents = tentList.filter(tent => tent.id === 1)
setTentList([...tents])
}
})
} else if("second" === name) {
axios.get("/tent.json").then(res => {
setTentList(res.data)
if(value) {
const tents = tentList.filter(tent => tent.id === 2)
setTentList([...tents])
}
})
} else if("third" === name) {
axios.get("/tent.json").then(res => {
setTentList(res.data)
if(value) {
const tents = tentList.filter(tent => tent.id === 3)
setTentList([...tents])
}
})
} else { // 아무것도 체크하지 않았을 때
axios.get("/tent.json").then(res => {
setTentList(res.data)
})
}
}
useEffect(() => {
getTentList()
}, [])
return (
<>
<ScheduleHeader />
<div styles={styles.container}>
<TentSideBar getTentList={getTentList} />
<TentMain tentList={tentList} />
</div>
<ScheduleFooter />
</>
)
}
export default TentPage
<함수, 컴포넌트 예제 - TentSideBar.jsx>
import React, { useState } from 'react'
import styles from './sidebar.module.css'
import { Form } from 'react-bootstrap'
const TentSideBar = ({getTentList}) => {
const [first, setFirst] = useState(false)
const [second, setSecond] = useState(false)
const [third, setThird] = useState(false)
const handleFirst = () => {
setFirst(!first)
console.log(first)
getTentList('first', !first)
}
const handleSecond = () => {
setSecond(!second)
console.log(second)
getTentList('second', !second)
}
const handleThird = () => {
setThird(!third)
console.log(third)
getTentList('third', !third)
}
return (
<div styles={styles.editor}>
<Form.Check type='checkbox' label='1등급' onClick={handleFirst} />
<Form.Check type='checkbox' label='2등급' onClick={handleSecond} />
<Form.Check type='checkbox' label='3등급' onClick={handleThird} />
</div>
)
}
export default TentSideBar
<함수, 컴포넌트 예제 - TentMain.jsx>
import React from 'react'
import styles from './main.module.css'
const TentMain = ({tentList}) => {
return (
<div styles={styles.preview}>
<ul>
{tentList.map((tent, index) => (
<li key={index}>{`상품명: ${tent.title}, 가격: ${tent.price}`}</li>
))}
</ul>
</div>
)
}
export default TentMain
'국비학원 > 수업기록' 카테고리의 다른 글
국비 지원 개발자 과정_Day101 (0) | 2023.04.25 |
---|---|
국비 지원 개발자 과정_Day100 (0) | 2023.04.21 |
국비 지원 개발자 과정_Day98 (0) | 2023.04.19 |
국비 지원 개발자 과정_Day97 (0) | 2023.04.18 |
국비 지원 개발자 과정_Day96 (0) | 2023.04.17 |
댓글