Spring Boot

230223 Spring Boot 인터셉터-메뉴핸들러

주영재 2023. 2. 23. 21:01

메뉴핸들러

핸들러에서 mapper(db)와 연결이 가능.
로그인된 정보에 따라 맞는 메뉴를 들고 나간다.

작동원리를 db연결이 아니라 uri 보내기로 확인. 이해를 위해.
uri가 있으면 해당 메뉴가 활성화된 상태로 그대로 두도록. (메뉴하이라이트)


$()를 하면 얻어온 순수한태그를 제이쿼리적용가능하게 바뀐다.
제이쿼리 반복은 .each()
제이쿼리는 contains() 대신 includes().


UserAuthHandler.java

package com.codehistory.myweb.util.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;

public class UserAuthHandler implements HandlerInterceptor{

	/*
	 * 1. HandlerInterceptor를 상속받습니다.
	 * 
	 * preHandle()-컨트롤러 진입전에 실행
	 * postHandle()-컨트롤러 수행 후에 실행
	 * afterCompletion()-화면으로 가기 직전에 수행
	 * 
	 * 2. 인터셉터클래스를 bean으로 등록
	 */

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("인터셉터실행");
		//현재세션을 얻음
		HttpSession session=request.getSession();
		String user_id=(String)session.getAttribute("user_id");
		
		if(user_id==null) {//로그인이 안됨
			response.sendRedirect(request.getContextPath()+"/user/login"); //로그인페이지로 리다이렉션. 절대경로로 적는다.
			return false;//컨트롤러를 실행하지 않음
		}
		
		return true; //컨트롤러가 그대로 실행
	}
	
}

 


WebConfig.java

package com.codehistory.myweb.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 com.codehistory.myweb.util.interceptor.MenuHandler;
import com.codehistory.myweb.util.interceptor.UserAuthHandler;

@Configuration//스프링 설정파일
public class WebConfig implements WebMvcConfigurer{

	//프리핸들러
	@Bean
	public UserAuthHandler userAuthHandler() {
		return new UserAuthHandler();
	}
	
	//포스트핸들러
	@Bean
	public MenuHandler menuHandler() {
		return new MenuHandler();
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		
		registry.addInterceptor(userAuthHandler())
			.addPathPatterns("/main")
			.addPathPatterns("/product/*")
			.addPathPatterns("/user/*")
			.excludePathPatterns("/user/login")
			.excludePathPatterns("/user/join");
		
//		.addPathPatterns("/**")
//		.excludePathPatterns("/user/login")
//		.excludePathPatterns("/user/join")
//		.excludePathPatterns("/js/*")
//		.excludePathPatterns("/css/*").excludePathPatterns("/img/*");
//		REST API 패스에서 제외..?
		// 경로를 ("/**")로 하면 js, css, img, rest api패스까지 다 설정해줘야 한다. 따라서 /**로 하지 말고 필요한 페이지를 지정하기.
		
		registry.addInterceptor(menuHandler())
			.addPathPatterns("/main")
			.addPathPatterns("/product/*")
			.addPathPatterns("/user/*");
	}

	
}

addpathPatterns를 사용할 때, 경로를 /**로 하면 전부 인터셉터를 탄다.

문제는 js, css, img, rest api패스까지 다 exludePathPatterns로 설정해줘야 함.

따라서 /**가 아닌 필요한 페이지들을 각각 지정하기.

 

프리핸들러에서 로그인한 아이디를 세션을 통해 받아 컨트롤러를 실행할지 안할지를 결정한다.


 

MenuHandler.java

package com.codehistory.myweb.util.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.codehistory.myweb.product.service.ProductMapper;

public class MenuHandler implements HandlerInterceptor{

	@Autowired
	private ProductMapper productMapper;
	
	//메뉴핸들러
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		String uri = request.getRequestURI();
		request.setAttribute("uri", uri);
		
	}

}

 

원래는 가져온 prouctMapper를 통해 db와 연결한다.

포스트핸들러에서 request객체를 통해 받은 uri를 setAttribute로 담는다.


basicLayout.html에서

<script th:inline="javascript">
console.log(JSON.parse('[[${uri}]]'));

/*
메뉴선택유지-메뉴하이라이트

sub_menu에 display:block.
sub_menu->a링크에 on클래스.
sub_menu_toggle>a에 sub_menu_select클래스.
*/
 var menu=JSON.parse('[[${uri}]]'); //postHandler에서 보내주는 uri
$(".sub_menu a").each(function(index,item){
	//item - a태그임
	//jquery적용
	
	//href에 uri값이 들어있는지 확인
	if($(item).attr("href").includes(menu)){
		$(item).addClass("on");
		$(item).closest(".sub_menu").css("display","block");
		$(item).closest(".sub_menu").prev().addClass("sub_menu_select");
	}
}); 

//반복문을 안돌리고 $('a[href*='+'[[${uri}]]'+']').addClass() 로 처리할 수도 있다.
//*로 조건을 만족하는 모든 a태그 가져옴.
/* 	
 $('a[href*='+'[[${uri}]]'+']').addClass("on");
$('a[href*='+'[[${uri}]]'+']').closest(".sub_menu").css("display","block");
$('a[href*='+'[[${uri}]]'+']').closest(".sub_menu").prev().addClass("sub_menu_select");
*/


</script>
</th:block>
</html>

각주의 세가지 과정을 해줘야 한다.

each()문을 통해 반복을 돌려 a태그를 찾아내고 속성값에 넘어온 [[${uri}]]가 포함되어 있는지 include를 통해 검사해서 과정을 처리했는데, 

선택자로 원하는 태그를 찾아서 처리해도 된다.

 

 

 

넘어온 uri와 같은 href를 가진 a태그, 해당 태그가 있는 ul, 그걸 담고 있는 li가 현재 있는 페이지에 따라 활성화된다.

postHandler로 메뉴활성화를 한다. 컨트롤러를 타고 나서 uri를 페이지에 보내고 페이지에서 활성화가 이루어진다.