同一功能的处理也就是Aop的练习,之前在Aop的切面中实现用户登录权限的校验,有两个问题:
1.无法获取HttpSession对象;
2.拦截的规则该怎样设置呢?拦截谁?不拦截谁?
以上的问题就可以通过拦截器来实现。
Spring拦截器的实现
1、自定义拦截器,需要实现HandlerInterceptor类,并重写preHandle方法,此方法参数有preHandle(HttpServletRequest request, HttpServletResponse response, Object handler),可以获取session;
2、将自定义的拦截器配置到项目中,实现WebMvcConfigurer类和类中的addInterceptors方法。
以下为具体示例:
一、用户登录权限校验
1.用户类
@Data
public class UserInfo {
private int id;
private String username;
private String password;
}
2.业务操作
package com.example.spring_aop_test.controller;
import com.example.spring_aop_test.model.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
@ResponseBody
@RequestMapping("/user")
public class UserController {
@RequestMapping("/reg")
public boolean reg(){
return true;
}
@RequestMapping("/getuser")
public UserInfo getUser(){
UserInfo userInfo=new UserInfo();
userInfo.setId(1);
userInfo.setUsername("张三");
userInfo.setPassword("123");
return userInfo;
}
@RequestMapping("/login")
public boolean login(String username, String password, HttpServletRequest request){
if(StringUtils.hasLength(username) && StringUtils.hasLength(password)){
if(username.equals("admin") && password.equals("123")) {
//登录成功,将会话信息存储
HttpSession session = request.getSession(true);
session.setAttribute("userInfo", new UserInfo(1, "admin", "123"));
return true;
}
}
return false;
}
}
3.自定义登录拦截器
//登录拦截器
//1.实现HandlerInterceptor,再实现方法preHandle
//登录拦截器
//1.实现HandlerInterceptor,再实现方法preHandle
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session=request.getSession(false);
if(session!=null && session.getAttribute("userInfo")!=null){
//已经登录
return true;//返回true不会被拦截,继续执行后面的代码
}
//未登录
response.sendRedirect("/login.html");
return false;//返回false就会被拦截
}
}
4.配置拦截器
//配置拦截器
@Configuration
public class AppConfig implements WebMvcConfigurer {
//添加拦截器
@Resource
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")//拦截所有实现
.excludePathPatterns("/user/reg")//不拦截谁
.excludePathPatterns("/user/login")
.excludePathPatterns("/**/*.html");
}
}
结果:
未登录,访问getuser被拦截,直接跳到登录页面
注册不需要拦截,直接访问
登录成功后,可访问getuser
二、统一异常处理
1、创建异常类,类上加@ControllerAdvice注解,进行增强;
2.异常类中添加同一异常处理的方法,方法上添加@ExceptionHandler(ArithmeticException.class),括号内为异常的类型。
(1)注册方法中出现异常
@RequestMapping("/reg")
public boolean reg(){
int num=10/0;
return true;
}
(2)查看异常类型
(3)添加异常处理类
@ControllerAdvice//当前类对异常进行了封装
public class ErrorAdvice {
//算术异常处理方法
@ResponseBody
@ExceptionHandler(ArithmeticException.class)//标识异常的类型
//出现此类异常就调用这个方法,并且将异常传入参数
public HashMap<String, Object> myArithmeticException(ArithmeticException e){
HashMap<String,Object> result=new HashMap<>();
result.put("satte",-1);
result.put("msg","算数异常"+e.getMessage());//得到异常信息
result.put("data",null);
return result;
}
//还可以添加空指针异常等等、、、、、、
//也可以设置默认异常
//Exception为异常的父类
@ResponseBody
@ExceptionHandler(Exception.class)//标识异常的类型
//出现此类异常就调用这个方法,并且将异常传入参数
public HashMap<String, Object> myExceptio(Exception e){
HashMap<String,Object> result=new HashMap<>();
result.put("satte",-1);
result.put("msg","默认异常"+e.getMessage());//得到异常信息
result.put("data",null);
return result;
}
}
异常非常多,可以列举典型异常,其他用默认异常。
出现哪个异常就走哪个异常
没有处理异常前,会返回此类界面,用户会很懵
处理后,但凡此类异常都会返回如下界面,不会影响前后端交互失败,前端可以识别到。
三、统一数据返回格式
1.表示封装的类为@ControllerAdvice,并实现ResponseBodyAdvice 接口;
2.重写supports和beforeBodyWrite方法。
//统一返回类型
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;//必须是true,表示要对返回的数据进行封装
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
HashMap<String,Object> result=new HashMap<>();
result.put("state",1);
result.put("msg","");
result.put("data",body);//原始数据
return result;
}
}
设置前:
设置后:将true封装在data中