ArgumentResolver란?
- 특정 요청이 Controller로 들어왔을때, 넘어온 값을 미리 가공하여 넘겨주는 작업을 해주는것.
- Controller단에서 중복되는 작업을 방지할 수 있다. ex)@Sign Annotation으로 User객체가 넘어온다면 세션에서 읽어서 가져오는 작업.
나는 ArgumentResolver를 사용해서, Home화면에 갔을때 로그인한 사용자라면 로그인전용 Home화면을, 로그인하지 않은 사용자라면 기본Home화면으로 보낼 생각이다.
순서는 다음과 같다.
1.@Sign Annotation 생성
경로(\src\main\java\com\project\domain\sign\Sign.java)
package com.project.domain.sign;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER) //파라미터에서 사용되는 Annotation임을 명시.
@Retention(RetentionPolicy.RUNTIME) //어노테이션을 런타임시에까지 사용할 수 있음. JVM이 자바 바이트코드가 담긴 class 파일에서 런타임환경을 구성하고 런타임을 종료할 때까지 메모리는 살아있음을 명시.
public @interface Sign {
}
2.SignInArgumentResolver.java 파일 생성
경로(\src\main\java\com\project\web\session\SignInArgumentResolver.java)
package com.project.web.session;
import com.project.domain.sign.Sign;
import com.project.domain.sign.SignInForm;
import com.project.domain.user.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.hibernate.Session;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class SignInArgumentResolver implements HandlerMethodArgumentResolver {
//해당 Resolver가 동작해야하는지 여부를 return한다.
@Override
public boolean supportsParameter(MethodParameter parameter) {
//@Sign이라는 Annotation이 넘어왔는지 여부
boolean hasSignInAnnotation = parameter.hasParameterAnnotation(Sign.class);
//넘어온 파라미터가 User.class인지 여부
boolean hasSignInType = User.class.isAssignableFrom(parameter.getParameterType());
return hasSignInAnnotation && hasSignInType;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//세션에서 로그인정보를 읽어 return해준다.
HttpServletRequest httpRequest = (HttpServletRequest) webRequest.getNativeRequest();
HttpSession session = httpRequest.getSession(false);
if (session == null) {
return null;
}
return session.getAttribute(SessionConst.SESSION_NAME);
}
}
3.WebConfig.java에 SignInArgumentResolver을 등록해준다.
package com.project.config;
import com.project.web.session.SessionFilter;
import com.project.web.session.SessionInterceptor;
import com.project.web.session.SignInArgumentResolver;
import jakarta.servlet.Filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new SignInArgumentResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SessionInterceptor())
.order(0) //interceptor의 순서를 정한다.
.addPathPatterns("/**") // [/**]는 전부 Interceptor의 범위에 있다는 뜻이다.
.excludePathPatterns("/", "/sign/**", "/assets/**", "/images/**"); //다음과 같은 url은 interceptor에서 제외한다.
}
// @Bean
public FilterRegistrationBean sessionFilter() {
FilterRegistrationBean<Filter> sessionFilterRegistrationBean = new FilterRegistrationBean<Filter>();
sessionFilterRegistrationBean.setFilter(new SessionFilter()); //SessionFilter 객체를 등록한다.
sessionFilterRegistrationBean.setOrder(0); //Filter의 순서를 정한다. 순서가 작을수록 chain에 먼저 걸림
sessionFilterRegistrationBean.addUrlPatterns("/*"); //해당 필터가 적용될 URL 패턴을 지정한다.
return sessionFilterRegistrationBean;
}
}
4.홈화면으로 이동하는 RequestMapping에서, ArgumentResolver가 반환한 Session여부에 따라 분기한다.
package com.project.web;
import com.project.domain.sign.Sign;
import com.project.domain.sign.SignInForm;
import com.project.domain.user.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class IndexController {
@GetMapping("/")
public String index(@Sign User user, Model model) {
//세션이 없다면 그냥 Home화면으로 이동
if (user == null) {
return "/index";
}
//세션이 있다면 model에 담아 로그인사용자 전용 Home화면으로 이동
model.addAttribute("user", user);
return "/login";
}
@GetMapping("/elements")
public String element(){
return "/elements";
}
@GetMapping("/generic")
public String generic(){
return "/generic";
}
}
5. login.html을 만들고, 로그인한 사용자가 넘어왔을시에는 로그아웃버튼을 출력한다.
이전에 사용했던 fragment를 이용해 로그인사용자 전용 버튼들의 영역을 추가.
경로(\src\main\resources\templates\fragment\loginUser-fragment.html)
<header id="header" th:fragment="loginUser">
<div class="inner">
<a href="/" class="logo">
<span class="symbol"><img src="/images/logo.svg" alt="" /></span><span class="title" th:text="#{index.title}">금융권 데이터 서비스</span>
</a>
<nav>
<ul>
<li>
<a href="#" class="button" th:onclick="|location.href='@{/sign/signUp}'|" th:text="#{signUp}" data-toggle="modal" data-target="#signUp">Sign Up</a>
</li>
<li><a href="#" class="button" th:onclick="|location.href='@{/sign/signOut}'|" th:text="#{signOut}">Sign Out</a></li>
<li><a href="#menu">Menu</a></li>
</ul>
</nav>
</div>
</header>
6. SignController에 로그아웃 RequestMapping을 추가한다.
//로그아웃 start
@GetMapping("/signOut")
public String getSignOut(@Sign User user, HttpServletRequest request) {
HttpSession session = request.getSession();
User loginUser = (User)session.getAttribute(SessionConst.SESSION_NAME);
if (loginUser != null) {
session.invalidate();
return "redirect:/";
}
return "/";
}
//로그아웃 end
7.서버를 재기동한다.
근데 문제가 있다. 홈화면은 로그아웃, 로그인버튼이 잘 나오는데
/generic이라던지, /element같은 게시글 조회화면은 로그인한 사용자임에도 불구하고 아래와 같이 나온다.
모든 페이지에서 특정영역을 Session여부에 맞게 동적으로 변경하려면 어떻게 해야할까? 고민을 좀더 해봐야겠다..
'프로젝트[종료]' 카테고리의 다른 글
17. Spring Boot 오류 처리하기 (0) | 2023.06.01 |
---|---|
15. Spring Interceptor 적용하기 (0) | 2023.05.04 |
14. Servlet Filter 적용하기 (0) | 2023.05.04 |
13. 로그인 사용자 Session 처리하기 (0) | 2023.04.28 |
12.회원가입 기능 만들기(2) (2) | 2023.04.27 |