一、实现用户登录校验
在之前的项目中,在需要验证用户登录的部分,每次都需要利用Session会话信息来进行判断用户是否处于登录状态,那么利用AOP思想可以进行统一处理,首先想到的是利用Spring AOP来进行实现,但是获取Session信息时需要HttpSession会话以及Request对象,这点StringAOP的五大通知都无法实现,并且在实际项目中并不是指定包或者指定类要进行拦截,适用AspectJ表达式就无法满足需求了,因此,就需要Spring拦截器来实现用户的登录的校验。
使用Spring拦截器的步骤:
- 实现自定义拦截器,实现Spring中的HandlerInterceptor接口中的preHandler方法。
- 将自定义的拦截器添加到框架的配置中,并且设置拦截的规则。
实现自定义拦截器
重写HandlerInterceptor接口中的preHandler方法,先获取到session对象,判断对象是否为空来判断登录状态,若未登录则自动跳转到登录页面。
@Component public class LoginIntercept implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //先得到session对象,传入参数为false,表示Session为空时不会自动创建,传入参数为true则反之。 HttpSession session = request.getSession(false); if(session != null && session.getAttribute("user") != null){ //表示登录成功 return true; } //表示未登录,则请求重定向到登录页面 response.sendRedirect("/login.html"); return false; } }
将自定义的拦截器添加到框架的配置中,并且设置拦截的规则
将自定义的拦截器添加到框架的配置中,设置所有页面都要判断登录状态,除了一些指定页面。
@Configuration public class AppConfig implements WebMvcConfigurer { @Resource private LoginIntercept loginIntercept; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginIntercept) .addPathPatterns("/**") .excludePathPatterns("/user/reg") .excludePathPatterns("/user/login") .excludePathPatterns("/**/*.css") .excludePathPatterns("/**/*.js") .excludePathPatterns("/**/*.jpg") .excludePathPatterns("/**/*.png"); } }
userController类的内容如下:
RestController @RequestMapping("/user") public class UserController { @RequestMapping("/login") public boolean login(HttpServletRequest request, String userName, String password){ if(StringUtils.hasLength(userName) && StringUtils.hasLength(password)){ if(userName.equals("zhangsan") && password.equals("1234")){ HttpSession session = request.getSession(); session.setAttribute("user","user"); return true; } } return false; } @RequestMapping("/test") public boolean test(){ return true; } }
那么访问test页面时就会出现:
此时就会进行拦截,并且重定向到登录页面。
二、实现统一异常处理
统一异常处理使用的是@ControllerAdvice注解,在方法前使用@ExceptionHandler注解,其中的参数为捕捉的异常类.class。
@RestControllerAdvice //表示当前处理异常的页面返回的是数据 public class MyExceptionAdvice { @ExceptionHandler(NullPointerException.class) public HashMap<String,Object> nullPointException(NullPointerException e){ HashMap<String,Object> res = new HashMap<>(); res.put("data",-1); res.put("state",-1); res.put("msg",e.getMessage()); return res; } }
那么访问一个空指针异常的页面:
@RequestMapping("/test") public boolean test(){ Object test = null; test.toString(); return true; }
进行访问:
但是我们不可能将所有的异常都列举出来,就可以定义一个方法处理所有的异常。
@ExceptionHandler(Exception.class) public HashMap<String,Object> allException(Exception e){ HashMap<String,Object> res = new HashMap<>(); res.put("data",-1); res.put("state",-1); res.put("msg",e.getMessage()); return res; }
三、实现统一数据格式封装
对数据进行统一的格式封装,给当前类添加@Controller注解,实现ResponseBodyAdvice接口,并重写其方法。
@RestControllerAdvice public class MyResponseAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; //返回true则表示对之前的数据进行重写,才会调用下面的beforeBodyWrite方法,若传入false则反之。 } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //此处也可以设置为别的格式 HashMap<String,Object> res = new HashMap<>(); res.put("data",body); res.put("state",1); res.put("msg",""); return res; } }
UserController类的test方法如下:
@RequestMapping("/test") public String test(){ return "hello"; }
访问test:
也可以设置为别的数据格式:
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //此处也可以设置为别的格式 return body; }
再次访问: