ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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

    댓글

Designed by Tistory.