











⇒ 학생별수강과목성적 = 해소 테이블
⇒ 중간에 해소 테이블을 추가함으로써 M:N 관계를 1:N 관계로 바꿔준다
⇒ 나의 데이터 베이스에 이상한 데이터가 들어오지 못하게 완전무결한 상태를 만드는 것




정규형 정리
정규화의 목적

⇒ domain 빼고 다 선택


⇒ 왼쪽은 식별할 수 있는 이름, 오른쪽은 실제 테이블명




Interceptor : 요청/응답/뷰 완성 후 이때, 무언가(요청, 응답, 뷰)를 가로채는 객체 (Spring에서 지원)
*
* * HandlerInterceptor 인터페이스를 상속받아서 구현해야 한다
* - preHandle(전처리) 3번 : pre는 previous, DispatcherServlet -> Controller 사이 수행
* - postHandle(후처리) 5번 : Controller -> DispatcherServlet 사이에서 수행
* - afterCompletion (뷰 완성후) 6번: ViewResolver -> DispatcherServlet에게
* "이런 화면으로 응답해줘!" 라고 할 때 수행되는 것
BoardTypeInterceptor.java
package edu.kh.project.common.interceptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import edu.kh.project.board.model.service.BoardService;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* Interceptor : 요청/응답/뷰 완성 후 이때, 무언가(요청, 응답, 뷰)를 가로채는 객체 (Spring에서 지원)
*
* * HandlerInterceptor 인터페이스를 상속받아서 구현해야 한다 - preHandle(전처리) 3번 : pre는
* previous, DispatcherServlet -> Controller 사이 수행 - postHandle(후처리) 5번 :
* Controller -> DispatcherServlet 사이에서 수행 - afterCompletion (뷰 완성후) 6번:
* ViewResolver -> DispatcherServlet에게 이런 화면으로 응답해줘 라고 할 때 수행되는 것
*
*/
public class BoardTypeInterceptor implements HandlerInterceptor {
// HandlerInterceptor를 상속받았는데 왜 빨간줄이 안뜨는지
// => 내부적으로 보면 추상메소드처럼 안보임
// => default를 붙이면 정의를 할 수도 있음
// => 인터셉트에서 빨간줄이 안뜨는 것, 즉 추상메소드 형태가 아니기 때문
// 전처리 : 요청이 Controller로 들어오기 전 실행되는 메서드
@Autowired // 의존성 주입(DI) -> BoardService타입과 일치하거나, 상속관계인 객체(Bean)을 주입받음
private BoardService service;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// DB에 접근해서 board_type을 가져와서 화면에 뿌려줄 것
// boardType을 DB에서 얻어오기
// boardTypeList 형태로 가져오기
// 모든 페이지를 돌아다니면서 화면상에 boardType이 뿌려져야 함
// 서버가 켜지자마자 db에서 데이터를 가져와서 뿌려줘야하므로, application scope에 저장
// application scope :
// - 서버 시작 ~ 종료 시 까지 유지되는 Servlet 내장 객체
// - 서너 배에 딱 한개만 존재하는 객체다 --> 모든 클라이언트가 공용으로 사용
// application scope 객체 얻어오기
ServletContext application = request.getServletContext();
// application scope에 "boardTypeList"가 없을 경우
if (application.getAttribute("boardTypeList") == null) {
// boardTypeList 조회 서비스 호출
List<Map<String, Object>> boardTypeList = service.selectBoardTypeList();
// 첫 요청이 들어와서 application에 실어두면, 두번 째부터는 실행을 안해줘도 됌
// 조회 결과를 application scope에 추가
application.setAttribute("boardTypeList", boardTypeList);
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
// 후처리 : 요청이 처리된 후, 뷰가 렌더링 되기 전에 실행되는 메서드
// 즉, 응답을 가지고 DispatcherServlet에게 돌아가기 전
// 전처리에서 모든 작업이 끝났기 때문에, 후처리에서 할게 없다.
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
// 뷰 완성 후 : 뷰 렌더링이 끝난 후 실행되는 메서드
// 뷰를 다 뿌리고나서 할게 없기 때문에 놔두면 된다.
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
InterceptorConfig
package edu.kh.project.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import edu.kh.project.common.interceptor.BoardTypeInterceptor;
@Configuration // 서버가 켜지면 Bean으로 등록되고, 내부 메서드가 수행
// 인터셉터가 어떤 요청을 가로챌지 설정하는 클래스
public class InterceptorConfig implements WebMvcConfigurer {
// WebMvcConfigurer : registry에서 사용, 즉 어떤 경로에서 사용하겠다는 의미
// => FileConfig에서 사용함
@Bean // 인터셉터 클래스 Bean 등록
// 개발자가 수동으로 만든 객체지만, 관리는 Spring Container가 수행하겠다는 의미
public BoardTypeInterceptor boardTypeInterceptor() {
return new BoardTypeInterceptor();
}
// 동작할 인터셉터 객체를 추가하는 메서드
@Override
public void addInterceptors(InterceptorRegistry registry) {
// Bean으로 등록된 BoardTypeInterceptor를 얻어와서 등록하기위한 절차
registry.addInterceptor(boardTypeInterceptor()).addPathPatterns("/**").excludePathPatterns("/css/**");
// addPathPatterns("/**")
// /** : / 이하 모든 요청을 의미, 모든 요청을 가로채서, boardTypeInterceptor가 돌아가게끔 할 것
// excludePathPatterns("/css/**", "/js/**", "/images/**", "/favicon.ico")
// 가로채고싶지 않은 요청 정의
}
}

⇒ log.debug로 리스트를 가져온 것을 확인할 수 있다.
결과 화면
