目录
- 用户登录权限校验
- 用户登录拦截器
- 排除所有静态资源
- 练习:登录拦截器
- 拦截器实现原理
- 统一异常处理
- 统一数据返回格式
- 为什么需要统⼀数据返回格式?
- 统⼀数据返回格式的实现
用户登录权限校验
用户登录拦截器
1.自定义拦截器
package com.example.demo.config;
import com.example.demo.common.AppVar;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 自定义拦截器
*/
@Component
public class UserInterceptor implements HandlerInterceptor {
/**
* 返回 true -> 拦截器验证成功,继续执行后续方法
* false -> 拦截器验证失败,不会执行后续的目标方法
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 业务方法
HttpSession session = request.getSession(false);
if (session != null &&
session.getAttribute(AppVar.SESSION_KEY) != null) {
// 用户已经登录
return true;
}
return false;
}
}
2.将自定义拦截器配置到系统设置中,并设置拦截规则
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(userInterceptor)
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/user/reg")
.excludePathPatterns("/user/login");
}
}
排除所有静态资源
// 拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 拦截所有接⼝
.excludePathPatterns("/**/*.js")
.excludePathPatterns("/**/*.css")
.excludePathPatterns("/**/*.jpg")
.excludePathPatterns("/login.html")
.excludePathPatterns("/**/login"); // 排除接⼝
}
练习:登录拦截器
- 登录、注册⻚⾯不拦截,其他⻚⾯都拦截。
- 当登录成功写⼊ session 之后,拦截的⻚⾯可正常访问。
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(userInterceptor)
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/user/reg")
.excludePathPatterns("/reg.html")
.excludePathPatterns("/login.html")
.excludePathPatterns("/css/**")
.excludePathPatterns("/editor.md/**")
.excludePathPatterns("/img/**")
.excludePathPatterns("/js/**")
;
}
}
package com.example.demo.config;
import com.example.demo.common.AppVar;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 自定义拦截器
*/
@Component
public class UserInterceptor implements HandlerInterceptor {
/**
* 返回 true -> 拦截器验证成功,继续执行后续方法
* false -> 拦截器验证失败,不会执行后续的目标方法
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("do UserInterceptor");
// 业务方法
HttpSession session = request.getSession(false);
if (session != null &&
session.getAttribute(AppVar.SESSION_KEY) != null) {
// 用户已经登录
return true;
}
response.sendRedirect("https://www.baidu.com");
return false;
}
}
拦截器实现原理
然⽽有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图所示:
统一异常处理
统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件。
1.@ControllerAdvice/@RestControllerAdvice
2.@ExceptionHandler(Exception.class)统一返回的对象
package com.example.demo.config;
import com.example.demo.common.ResultAjax;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(NullPointerException.class)
public ResultAjax doNullPointerException(NullPointerException e) {
ResultAjax resultAjax = new ResultAjax();
resultAjax.setCode(-1);
resultAjax.setMsg("空指针异常:"+ e.getMessage());
resultAjax.setData(null);
return resultAjax;
}
@ExceptionHandler(Exception.class)
public ResultAjax doException(Exception e) {
ResultAjax resultAjax = new ResultAjax();
resultAjax.setCode(-1);
resultAjax.setMsg("异常:"+ e.getMessage());
resultAjax.setData(null);
return resultAjax;
}
}
统一数据返回格式
为什么需要统⼀数据返回格式?
统⼀数据返回格式的优点有很多,⽐如以下⼏个:
- ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。
- 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回
的。 - 有利于项⽬统⼀数据的维护和修改。
- 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。
统⼀数据返回格式的实现
统⼀的数据返回格式可以使⽤ @ControllerAdvice + ResponseBodyAdvice 的⽅式实现。
- @ControllerAdvice
- 实现ResponseBodyAdvice接口,并重写它的两个方法:supports方法必须返回true,beforeBodyWrit方法中进行重新判断和重写操作。
package com.example.demo.config;
import com.example.demo.common.ResultAjax;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 统一返回值的保底实现类
*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
/**
* true -> 才会调用 beforeBodyWrite 方法,
* 反之则永远不会调用
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 已经包装好的对象
if (body instanceof ResultAjax) {
return body;
}
return ResultAjax.succ(body);
}
}