一、拦截器
- return true:表示放行请求;
- return false:表示拦截;
- 配置类:实现
WebMvcConfigurer
接口的addInterceptors
方法,向springboot中添加具体的拦截器
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/user/code",
"/user/login"); //不拦截这两个请求
}
}
- 拦截器具体实现:重写
handlerInterceptor
接口中的preHandle
、afterCompletion
等方法
public class LoginInterceptor implements HandlerInterceptor {
//前置拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取session
HttpSession session = request.getSession();
//获取session中的用户
Object user = session.getAttribute("user");
//如果用户存在不存在拦截
if(user==null) {
response.sendError(401,"用户为登录");
return false; //false就表示拦截
}
//将每个用户的信息存到ThreadLocal中
UserHolder.saveUser((UserDTO) user);
return true; //表示放行
}
//后置拦截,注销后清楚session
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
public class UserHolder {
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
public static void saveUser(UserDTO user){
tl.set(user);
}
public static UserDTO getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}
二、过滤器
- filterChain.doFilter(request,response): 表示放行;
- 如果请求被阻止,
doFilter
方法的返回值是void,因此respone可以通过输出流像前端返回json数据,即,如:response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
- 过滤器实现:实现
Filter
接口的doFilter
方法
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
public static final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1. 获取本次请求的URI
String requestURI=request.getRequestURI();
log.info("拦截到请求:{}",requestURI);
//2. 定义直接放行的请求
String[] urls=new String[]{
"/employee/login", //动态资源
"/employee/logout",//动态资源
"/backend/**", //静态资源
"/front/**", //静态资源
"/common/**"//动态资源
};
boolean isCheck=check(urls,requestURI);
//3. 上面的这些请求都可以放行
if(isCheck){
log.info("本次请求{}不需要处理",requestURI);
filterChain.doFilter(request,response); //这就是放行
return;
}
//4. 不是直接放行的请求,首先需要判断是否登录,登录成功则放行,因为第一次登录成功后会分配一个sessionID
if(request.getSession().getAttribute("employee")!=null){
log.info("用户已登录,用户id:{}",request.getSession().getId());
//客户端请求时候,服务器会为该请求分配一个线程,
// 因为我们请求是异步请求,所以我们登录成功后的所有请求都是在一个线程里处理的,
//这里我们用线程可以存储用户id,是为了后面MyBatisPlus的字段自动填充时,自动填充createUser和updateUser的。
Long id=(Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(id);
filterChain.doFilter(request,response);
return;
}
//5. 如果未登录,返回登录结果
//因为该方法是void,没有返回值,因此是通过输出流像前端返回json数据
log.info("用户未登录{}",requestURI);
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
//进行匹配
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = antPathMatcher.match(url,requestURI);
if(match) return true;
}
return false;
}
}
- 启动类上还需要加上扫描注解:
@ServletComponentScan
@SpringBootApplication
@ServletComponentScan //扫描过滤器的注解
@EnableTransactionManagement(proxyTargetClass = true) //开始事务注解功能,对数据库操作的那些事务
public class TakeOutApplication {
public static void main(String[] args) {
SpringApplication.run(TakeOutApplication.class, args);
}
}
三、异常处理器
- 异常处理器:基于
@ExceptionHandler
注解实现。
//捕获那些加RestController和Controller注解的类上出现的异常
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalException {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class) //捕获这种类型的异常
public R<String> ExceptionHandler(SQLIntegrityConstraintViolationException ex){
log.info(ex.getMessage());
//根据异常的具体情况进行处理
if(ex.getMessage().contains("Duplicate entry")){
String[] strings = ex.getMessage().split(" ");
String msg=strings[2]+"已存在";
return R.error(msg);
}
return R.error("未知错误");
}
@ExceptionHandler(SQLSyntaxErrorException.class)
public R<String> ExceptionHandler(SQLSyntaxErrorException ex){
log.info(ex.getMessage());
return R.error("SQLSyntaxErrorException异常");
}
}