一、登录验证
登录验证通过拦截器实现,拦截器就是在用户访问服务器时,预先拦截检查一下用户的访问请求。
- 没有拦截器时,用户访问服务器的流程是:用户–>controller–>service–>Mapper。
- 有拦截器时,用户访问服务器流程是:用户–>拦截器–>controller–>service–>Mapper。
拦截器起到了预先帮助Controller层检查请求是否合规的作用,让Controller层的代码更加专注于核心的业务逻辑。
登录验证就是拦截器的一种应用。在请求没Controller层处理前,先判断发出请求的用户是否是登录状态。
-
创建拦截器类
- 拦截器类要实现拦截器接口HanderInterCeptor
- 重写里面的preHandle方法,这个preHandle方法就是拦截器在拦截到http请求后做的事情。
- 返回值是Boolean类型,返回true代表通过拦截,继续向深层代码执行
- 返回false代表请求不合规,被拦截了,直接返回响应。
@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; } return false; } }
-
配置拦截器拦截的url
- 重新创建一个配置类,并且这个类要加上@Configuration注释交给Spring容器托管。
- 继承WebMvcConfigurer接口,并且重写addInterceptor方法
- 参数InterceptorRegistry就是拦截器的注册列表,要将拦截器添加到列表中拦截器才能在url访问时候调用。
- registry的addInterceptor方法就是将传入的拦截器对象注册加入拦截器列
- addPathPatterns方法就是添加拦截器的拦截路径,/※代表这一级的所有路径,/** 代表所有的多级路径。
- excludePathPatterns方法就是在已添加的路径中剔除路径
@Configuration
public class LoginConfiguration implements WebMvcConfigurer {
@Autowired
private LoginInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor).
addPathPatterns("/**").
excludePathPatterns("/image/**").excludePathPatterns("/sayhi");
}
}
拦截器的工作原理:
为了理解拦截器源码实现,首先要知道一件事,一个http请求访问到项目,项目进行处理的时候,是有一个调度器(DispatcherServlet)来调度程序执行的先后顺序的.这个调度器是SpringMVC框架实现的。
当spring boot项目启动后,控制台没有DispatcherServlet启动的日志
但是当首个http请求发出后,DispatcherServlet就会被初始化
调度器在收到http请求后的首先就会执行拦截器列表中的拦截器对象的方法,只有列表中的所有方法都返回true后,拦截器才会调度深层代码继续执行。有一个返回false都会直接返回响应。
二、统一异常处理
当前端传入的某些特殊数据时,可能会导致后端程序在执行时抛出异常,如果不对这个异常做出处理,后端会直接返回500的错误页面,破坏前后端交互的正常进行,异常处理的作用就是就算后端抛出了异常,响应也要按照正确格式返回,只是在返回的时候说明后端发生了错误。
- 自定义异常处理类
-
这个类要用@ControllerAdvice和@ResponseBody修饰
-
类内的方法要指定是针对哪个异常进行处理,使用@ExceptionHandeler注解指定异常,注解参数是异常类的class对象
-
处理方法的返回值就是响应的body返回值(要将按正常格式返回)
@ControllerAdvice @ResponseBody public class MyExceptionController { @ExceptionHandler(Exception.class) public HashMap<String,Object> handException(Exception e){ HashMap<String,Object> map=new HashMap<>(); map.put("data",e.getMessage()); return map; } }
上面的代码指定的异常类的class是所有异常的父类Exception,这样指定是起到一个保底的作用,因为异常是不可预知的,你在写代码的时候,并不知道代码会抛出什么异常,针对特定异常的处理是极少的,直接使用父类异常接受可以兜底保证异常抛出时,会被正确的处理。
抛出异常时,处理方法的匹配原则是先匹配对应异常的处理方法,如果没有才会匹配父类异常的处理方法。
-
三、统一数据格式
- 要定义一个格式处理类,使用@ControllerAdvice类修饰
- 然后这个类要继承ResponseBodyAdvice接口,重写supports方法和beforeBodyWrite方法
-
Support方法的返回值就是设置是否要调用beforeBodyWrite方法的,true表示要调用,false表示不调用
-
beforeBodyWrite就是修改body的数据格式的方法,可以根据自带的object参数body获取判断参数格式是否符合要求。(用instanceof方法判断Object是否是约定要返回的对象类型)
@ControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice { @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 HashMap){ //格式正确 return body; } HashMap<String,Object> map=new HashMap(); map.put("code",1); map.put("data",body); return map; } }
-
注意:如果body是String类型的数据,将这个hashMap最终转换成json格式的时候,会报错。
原因就是在hashmap转换成json字符串的时候会判断Value的类型,如果HashMap中的value是Object,并且原类型是String就是使用的StringHttpMessageConverter进行转换,这个转换就会出错。
解决办法就是,在统一格式转换方法里,将body为String的HashMap直接转换成Json格式字符串
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@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 HashMap){
//格式正确
return body;
}
HashMap<String,Object> map=new HashMap();
map.put("code",1);
map.put("data",body);
//判断是否是String
if(body instanceof String){
ObjectMapper objectMapper=new ObjectMapper();
String result= null;
try {
result = objectMapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return result;
}
return map;
}
}