1. 大体思路
防止用户直接输入:http://localhost:8080/community/user/setting,从而进入某些页面。因此进入某些页面时,需要检查用户的登录状态。
由于众多页面都需要进行登录状态的判定,因此写在拦截器中。
不过一个一个添加要拦截与放行的路径十分麻烦,我们可以自定义注解。让被注解标识的方法,被拦截。
2. 自定义注解
- 常用的元注解:
@Target、@Retention、@Document、@Inherited
- 读取注解:
Method.getDeclaredAnnotations()
Method.getAnnotation(Class<T> annotationClass)
在com.nowcoder.mycommunity目录下新建包:annotation,里面用于存放自定义注解。
在该目录下新建Annotation:LoginRequired
package com.nowcoder.mycommunity.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD}) //表示自己定义的这个注解用于描述方法
@Retention(RetentionPolicy.RUNTIME) //表名程序运行时,自己定义的这个注解才有效
public @interface LoginRequired {
//只起到标识的作用
//被该注解标识的方法,需要进行登录验证
}
3. 控制器方法上添加注解
UserService中有三个方法:
进入账号设置: getSettingPage()
上传头像:getSettingPage()
获取头像:getHeader()
其中前两个方法需要添加自定义的注解LoginRequired,来接受拦截,进行登录检查。
获取头像的方法则不需要,因为用户在不登录时,依然能查看他人的头像。
4. 拦截器
在controller.interceptor下新建类:LoginRequiredInterceptor
该拦截器拦截了所有带LoginRequired注解的方法。
package com.nowcoder.mycommunity.controller.interceptor;
import com.nowcoder.mycommunity.annotation.LoginRequired;
import com.nowcoder.mycommunity.util.HostHolder;
import org.springframework.beans.Mergeable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
@Autowired
private HostHolder hostHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
//如果拦截器拦截到的是一个方法
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//尝试获取咱们自定义的登录验证注解
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
if(loginRequired != null && hostHolder.getUser() == null){
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
return true;
}
}
5. 配置拦截器
在WebMvcConfig类下,配置登陆检查拦截器LoginRequiredInterceptor跳过静态资源。
这样使得在访问静态资源以为的路径时,都会通过该拦截器。该拦截器判断方法是否携带注解LoginRequired,如果带、且为未登录状态,就进行拦截。
@Autowired
private LoginRequiredInterceptor loginRequiredInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginTicketInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
// /**:static目录下的所有目录
// /**/.css:static目录下所有的.css文件都排除掉
//登陆检查拦截器,跳过所有的静态资源
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
}