-
Spring:interceptor,3Tier(Presentation,Business,Dataservice)JAVA 2021. 7. 27. 17:03
인터셉터(Interceptor)
(전, 후처리기 역할을 수행한다.)
위의 사진을 보면 차이점을 쉽게 알 수 있는데, 둘다 컨트롤러 전에 작업을 처리하는 용도로 사용되지만 호출되는 시점이 다르다.
필터(Filter)는 dispatcherServlet으로 요청이 가기전에 실행되고
인터셉터(Interceptor)는 Controller로 요청이 가기전에 실행이된다.
Filter
- DispatcherServlet 앞단에서 정보 처리
- J2EE 표준스펙에 정의되어 있는 기능 ( web.xml 에서 설정 )
Interceptor
- DispatcherServlet에서 Handler(Controller)로 가기전에 정보 처리
- SpringFramework에서 자체적으로 제공하는 기능 ( MVC 에서 설정 )
출처: https://cornswrold.tistory.com/56 [평범한개발자노트]
1. 인터셉터 생성
클래스 생성시 object 칸에 옆 brower 버튼 누르고 HandlerInterceptorAdapter 검색, 추가
>> LoginInterceptor
package com.stone.mvc.env; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class LoginIntercepter extends HandlerInterceptorAdapter { //preHandle 은 컨트롤러 전에 실행되는 메서드 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(false); boolean 로그인 = false; if (session != null && session.getAttribute("no") != null) { 로그인 = true; }; if(!로그인) { response.sendRedirect("/login"); return false;//컨트롤 넘어가지 않기 } return true;//컨트롤 넘어가기 } }
preHandle() : 컨트롤러 전에 postHandle() : 컨트롤러 후, 뷰 전에 afterCompletion() : 뷰 후에 2. 인터셉터 등록
dispatcherConfig와 관련
@Configuration 을 선언한 클래스중 WebMvcConfigurer 클래스를 상속받아 뷰경로와 소스경로를 지정하도록 직접 만든
config 클래스에 WebMvcConfigurer의 메서드인 addInterceptors() 메서드로 인터셉터를 지정한다.
@Import(value={MyBatisConfig.class}) @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.stone") public class MvcConfig implements WebMvcConfigurer { //중략... @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginIntercepter()) .addPathPatterns("/*") .excludePathPatterns("/contents") .excludePathPatterns("/boards") .excludePathPatterns("/board") .excludePathPatterns("/login"); //.excludePathPatterns("/member"); } }
인터셉터관련 메서드들은 전부 return this 를 하기 때문에 chaining(체이닝) 기법이 가능하다. addInterceptors() : 인터셉터 구현한 객체받아서 인터셉터로 올려줌 addPathPatterns() : 어떤 요청명에서 인터셉할건지.
/* : 모두다excludePathPatterns() : 어떤 요청명을 인터셉안할건지.
3 Tier
3 Tier 개요는 아래에 전에 정리한 내용 확인하기
2021.07.25 - [JAVA] - MVC 3 Tier,인터페이스정의서,AJAX-JSON사용,BLOB(image)_210603(목)
MVC 3 Tier,인터페이스정의서,AJAX-JSON사용,BLOB(image)_210603(목)
MVC - 3 Tier 3 Tier ( 3 layer architecture ) presentation : control, view business(logic) : service(인터페이스통신) dataservice : DAO common : VO 위 3개 항목이 common 소스들을 공통적으로 사용한다. b..
docc-storage.tistory.com
1. Dataservice - DAO
1) DAO 가 Mapper 를 통해 DB 업무
2) 그 외에 파일 저장등의 업무
2. Business - service
1) 요청, 업무
2) DAO 를 가져와 업무시키기
3) try-catch 등으로 예외 처리하기
3. Presentation - control
1) Business 가져와 업무시키기
2) 경로지정Business(Service) 에 Dataservice(DAO) 를 사용한 업무를 담당하게 하여
이 Business(Service)단을 Presentaion(Control)에서 사용하는것이다.~~manage 패키지에 @Service 를 달아 DAO 로 업무할 클래스를 만들어준다. Presentation 의 Control 1. RestController < - > 업무 < -> dataservice( 현재 DAO로 사용해 접근중 => HD,DB,외부시스템 ( DAO 로 접근가능한 시스템들 ))
=> view 가 아닌 데이터를 반환
: RestController 에서 업무를 진행하는데 DAO 를 사용해 HD 또는 DB 또는 외부시스템에 접근 중이다.2. Controller < - > 업무 < -> dataservice( 현재 DAO로 사용해 접근중 )
=> view 를 반환1. Business 단 ( + Dataservice 단)
1) 부속품
>> BusinessResult.java
public class BusinessResult { int code = 0;//0이 default 이며 성공인지 실패인지 구분하기 위한 멤버.(0이면 성공) String message = null;//던져줄 메시지 Object value = null;//DB에서 요청오는 모든 것들은 여기에 담기. public BusinessResult() {//값은 없는 성공 code=0; message=null; value=null; } public BusinessResult(Object value) {//값이 있는 성공 code=0; message=null; this.value=value; } public BusinessResult(int code, String message) {//값이 있는 성공 this.code=code; this.message=message; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } }
컨트롤러들이 비지니스 업무를 볼 때 이 클래스를 반환값으로 다 통일할 수 있다. 생성자에 매개를 넣어 메서드 생략해도 바로 값이 들어갈 수 있게 해놓았다. value(Object) : DAO 의 리턴값을 주로 받는다.
code : 정상으로 DAO 에게 값을 받으면 0 ( default) 아니면 음수 반환
message : 결과에 따른 메시지 작성message는 나중에 code 에 따라서 나오는 값이 고정되도록 HashMap<int,String>
put.(code,message) 이런식으로 넣어주면 좋다.2) @Service ( 실제 Business 단에서 업무를 하는 얘 )
>> I게시물관리.java ( 인터페이스를 꼭 해줘야한다.)
public interface I게시물관리 { BusinessResult 게시물등록준비하다(); BusinessResult 게시물등록하다(Board board); BusinessResult 모든게시물들을수집하다(); BusinessResult 게시물을수집하다(int no, boolean addView); }
>> 게시물관리.java
@Service public class 게시물관리 implements I게시물관리{ @Autowired IBoardDAO boardDAO; @Override public BusinessResult 게시물등록준비하다() { return new BusinessResult(); } @Override @Transactional public BusinessResult 게시물등록하다(Board board) { //업무규칙검사 try { boardDAO.save(board); }catch (Exception e) { //예외의 종류에 따른 조치 } return new BusinessResult(board);//code = 0, value = 등록된 board } @Override @Transactional public BusinessResult 모든게시물들을수집하다() { List<Board> boards = boardDAO.selectAll(); return new BusinessResult(boards);//code = 0, value = 수집된 boards } @Override @Transactional public BusinessResult 게시물을수집하다(int 게시물번호, boolean 조회수증가) { Board board = boardDAO.findByNo(게시물번호, 조회수증가); return new BusinessResult(board);//code = 0, value = 수집된 board } }
Business Service 에서 @Transaction Dataservice의 Transaction : DAO 의 메서드들을 여러 번 사용할 수도 있으니, 그때를 위해 @Transactional 를 걸어준다. Business 의 Transaction : DAO 의 메서드를 사용한 service 가
다른 service의(ex. 판매서비스-재고서비스) 메서드도 있어야 업무가 진행되는 경우 @Transaction 를 걸어준다.
>> I댓글관리.java
public interface I댓글관리 { //value = null BusinessResult 댓글을등록하다(Comment comment); //value = {수집된댓글들 , 게시물에대한총댓글수} BusinessResult 게시물에대한댓글을크기만큼수집하다(int 게시물번호,int size); }
>> 댓글관리.java
public class 댓글관리 implements I댓글관리{ @Autowired ICommentDAO commentDAO; @Override @Transactional public BusinessResult 댓글을등록하다(Comment comment) { //업무규칙검사 commentDAO.save(comment); return new BusinessResult(comment); } @Override public BusinessResult 게시물에대한댓글을크기만큼수집하다(int 게시물번호,int size) { // 업무규칙검사 // RefInteger 게시물에대한총댓글수 = new RefInteger(); List<Comment> comments = commentDAO.selectByBoardNo(게시물번호, size, 게시물에대한총댓글수); // 두개 가야하니까 Object 배열로 두개를 다 보낸다. return new BusinessResult(new Object[] {comments,(Integer)게시물에대한총댓글수.value}); } }
2. Presentation 단
>> 게시물컨트롤.java ( 게시물, 댓글 )
class DataSize{ int size; public int getSize() { return size; } public void setSize(int size) { this.size = size; } } @Controller public class 게시물컨트롤{ @Autowired I게시물관리 게시물관리; @Autowired I댓글관리 댓글관리; @GetMapping("board") public String 게시물등록준비하다() { // 요청 // 업무 BusinessResult br = 게시물관리.게시물등록준비하다();//업무결과 if(br.getCode()!=0) {}//비정상시 처리 // 경로 지정 return "board/게시물등록창"; } @RequestMapping(value="board", method=RequestMethod.POST) public ModelAndView 게시물등록하다(@ModelAttribute Board board, HttpSession session) {//세션필요하면 그냥 매개값으로 Spring 이 알아서 준다. Member writer = new Member(); writer.setNo((int)session.getAttribute("no")); board.setWriter(writer); BusinessResult br = 게시물관리.게시물등록하다(board); if(br.getCode()!=0) {}//비정상시 처리 //원래 이 파일 등록 부분도 Control 이 아니라 , DAO 에서 다 끝내야 했다. Board 등록된게시물 = (Board)br.getValue(); // 첨부파일이 있을 때 저장하기. if(board.getAttachFiles() != null) { System.out.println(session.getServletContext().getRealPath("/upload/board")); String boardPath = session.getServletContext().getRealPath("/upload/board"); String 새게시물번호경로 = boardPath + "//" + 등록된게시물.getNo(); File folder = new File(새게시물번호경로); folder.mkdir(); for(MultipartFile multipartFile: board.getAttachFiles()) { // File file = new File(새게시물번호경로 + "//" + multipartFile.getOriginalFilename()); try { multipartFile.transferTo(file); } catch (Exception e) { e.printStackTrace(); } } } //요청 //경로지정 ModelAndView mv=new ModelAndView(); mv.addObject("title", board.getTitle()); mv.setViewName("board/게시물등록결과통보"); return mv; } @GetMapping("boards") public ModelAndView 게시물목록을출력하다() { BusinessResult br = 게시물관리.모든게시물들을수집하다(); if(br.getCode()!=0) {}//비정상시 처리 //정상처리 List<Board> boards = (List<Board>)br.getValue(); ModelAndView mv = new ModelAndView(); mv.addObject("boards", boards); mv.setViewName("board/게시물목록창"); return mv; } @GetMapping("board/{no}") public ModelAndView 게시물상세를출력하다(@PathVariable int no, HttpSession session) { BusinessResult br = 게시물관리.게시물을수집하다(no, true); if(br.getCode() != 0) {}//비정상시 처리 //정상처리 Board board = (Board)br.getValue(); ModelAndView mv = new ModelAndView(); mv.addObject("board",board); mv.addObject("writer_no",session.getAttribute("no")); mv.setViewName("/board/게시물상세창"); return mv; } @RequestMapping(value = "board/comment", method= {RequestMethod.POST}) @ResponseBody public String 게시물댓글을등록하다(@RequestBody Comment comment) { BusinessResult br = 댓글관리.댓글을등록하다(comment); if(br.getCode() != 0) {}//비정상시 처리 return "ok"; } @RequestMapping(value="board/comments/{no}", method = RequestMethod.POST, produces = "text/plain;charset=UTF-8") @ResponseBody //{size:3} public String 게시물댓글을출력하다(@PathVariable int no, @RequestBody DataSize dSize, HttpSession session) { BusinessResult br = 댓글관리.게시물에대한댓글을크기만큼수집하다(no, dSize.size); if(br.getCode()!=0) {}//비정상시 처리 //원래 그냥 Object 형이였으니 먼저 (Object[]) 로 형변환후 [0]지정하고, 그 값이 List<Comment> 이니 또 형변환 List<Comment> comments = (List<Comment>)((Object[])br.getValue())[0]; int totalSize = (Integer)((Object[])br.getValue())[1]; if(comments == null) {return "<p> 댓글이 없어요 </p>";} String html=""; html+="<p>댓글수는 "+totalSize +"</p>"; html+="<ul>"; for(Comment comment : comments) { html += "<li>"; html += String.format("<p>%s</p>", comment.getWriter().getName()); html += String.format("<p>%s</p>", comment.getWdate().toString()); html += String.format("<textarea cols=20 rows=5 readonly>%s</textarea><br>", comment.getContents()); html += "<button>좋아요</button><button>싫어요</button>"; html += "</li>"; } html+="</ul>"; return html; } }
'JAVA' 카테고리의 다른 글
websocket:채팅 (0) 2021.07.27 3Tier: 예외처리,@Qualifier (0) 2021.07.27 Mybatis:설정하기 (0) 2021.07.27 BLOB 이미지파일업로드 (0) 2021.07.27 Spring:댓글더보기(ajax.ver) (0) 2021.07.26