WebMvcConfigurer 介绍:
WebMvcConfigurer配置其实是Spring内部的配置方式,采用javaBean的形式代替XMl配置形式实现定制.可以实现一些全局的定制需求.
WebMvcConfigurer存在的方法:
makefile
addViewControllers:用于注册简单的视图控制器。
addResourceHandlers:用于注册静态资源处理器,可以将静态资源映射到指定的URL路径。
configureViewResolvers:用于配置视图解析器,可以将逻辑视图名称解析为实际的视图。
configureContentNegotiation:用于配置内容协商策略,可以根据请求头中的Accept字段来返回不同的响应格式。
configureDefaultServletHandling:用于配置静态资源的处理方式,可以将请求转发给默认的Servlet。
addReturnValueHandlers:用于注册自定义的返回值处理器,可以将控制器方法的返回值转换为响应体。
addInterceptors 拦截器
addArgumentResolvers:用于注册自定义的方法参数解析器,可以将请求参数解析为控制器方法的参数。
addCrosmappings: 实现跨域
WebMvcConfigurer addInterceptors 详解:
拦截器配置,主要是实现WebMvcConfigurer中的一个方法,方法中存在使用的对应参数:
vbnet
addInterceptor: 需要一个实现HandlerInterceptor接口的拦截器实现
addPathPatterns: 用于设置拦截器的过滤路径规则, addPathPatterns("/**") 对所有请求都拦截
excludePathPatterns: 用于设置不需要拦截的过滤规则
WebMvcConfigurer addArgumentResolvers 详解:
主要作用用于对Controller中的方法参数,传入之前对参数进行处理。然后将处理好的参数传给Controller中的方法.
场景描述:
erlang
在权限场景中,通常会要求用户登录之后才能有权限访问的场景.对于这些问题通常有很多实现的方案,cookies+session,拦截器,其他安全组件等等
Cookie+Session的逻辑:
用户第一次登陆会存在一个cookie,在以后每次的访问过程中都会携带cookie进行访问.在后台的Controller中对于需要登陆权限的访问需要获取Cookie中的Token,再使用Token从Session中获取用户登录信息再判断用户登陆情况决定是否放行.
WebMvcConfigurer addCrosmappings 详解:
跨域问题,是浏览器为了安全做的保证,前后端都对跨域做了支持. 重写addCorsMappings
typescript
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://www.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
解析: 使得所有以 /api/ 开头的请求都允许来自 www.example.com 域名的访问,并且支持 GET、POST、PUT、DELETE 请求方法,允许携带身份验证信息,设置了缓存时间为1小时。
具体WebMvcConfigurer + 拦截器 + 注解 实现代码:
拦截器代码实现:
实现WebMvcConfigurer 类
typescript
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 添加拦截器
* 注册拦截器,制定拦截和放行路径,先注册的会先执行
*
* @param registry 注册表
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*
* addInterceptor 添加自定义的拦截器
* addPathPatterns 拦截的请求路径,支持正则
* excludePathPatterns 排除的路径,这些路径不拦截
*
* */
registry.addInterceptor(new TestInterceptor()).addPathPatterns("/interceptor/*").excludePathPatterns("/login");
}
}
new TestInterceptor() 为具体拦截器实现代码
java
@Slf4j
public class TestInterceptor implements HandlerInterceptor {
/**
* 前置处理程序
* 在业务处理器请求完之前被调用(Controller之前)
*
* @param request 请求
* @param response 响应
* @param handler 处理程序
* @return boolean
* @throws Exception 例外
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
log.info("执行了 preHandle 的拦截器 这个拦截在@RequestMapping 中标注");
} else {
log.info("执行了 preHandle 的拦截器");
}
return false;
}
/**
* 在业务处理器请求完成之后,生成视图之前执行(Controller 执行完成,前端生成视图之前)
*
* @param request 请求
* @param response 响应
* @param handler 处理程序
* @param modelAndView 模型和视图
* @throws Exception 例外
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
log.info("执行了 postHandle 拦截器");
}
/**
* 在DispatcherServlet完全处理请求之后被调用,可用于清理资源
*
* @param request 请求
* @param response 响应
* @param handler 处理程序
* @param ex ex
* @throws Exception 例外
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
log.info("执行了 afterCompletion 拦截器");
}
}
以上可以测试拦截器实现demo,如果preHandle返回false则不会继续执行
如果需要对是否登陆进行校验,并且登录用户存储session则可以实现以下代码 重写(preHandle 方法)
java
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 查看这个方法上是否存在指定注解,如果不存在则不进行处理
Method method = handlerMethod.getMethod();
CmsAccountRequired permission = method.getAnnotation(CmsAccountRequired.class);
if (permission == null) {
return true;
}
/**
* 获取这个用户的信息从数据库 or redis (通过token获取session)
* 1 校验登陆状态
* 2 校验权限信息
* 3 校验自定义的登陆前信息
* 4 如果校验通过则把session存储进入request,controller可以使用
*/
String sessionId = request.getHeader(CmsAccountSession.SESSION_ID);
CmsAccountSession accountSession = cmsAccountService.getBySessionId(sessionId);
// 检查登录状态
if (!this.checkLogin(accountSession, permission, request, response)) {
return false;
}
// 检查角色权限
if (!this.checkRole(accountSession.getRoles(), permission, request, response)) {
return false;
}
request.setAttribute(CmsAccountSession.REQUEST_ATTR_NAME, accountSession);
return true;
}
具体WebMvcConfigurer + addArgumentResolvers + 注解 实现代码:
WebMvcConfigurer 实现的代码
less
/**
* Controller代码, @CurrentCmsAccount 注解标注用于后续判断
* 主要用途: 后端不想判断request大量的参数,可能还需要class解析等问题,只想要试用几个参数进行后续处理
* 所以这里可能对request处理,并且拿到一些共用参数存入CmsAccountSession中
* 而且这些参数前端不存储,后端通过拦截器注入到request中,这里相当于二次处理
*/
@CmsAccountRequired
@GetMapping("/test")
public Result<CmsAccountSessionVo> currentAccountInfo(@CurrentCmsAccount CmsAccountSession session) {
CmsAccountSessionVo userSessionVo = cmsAccountService.info(session);
return Result.success(userSessionVo);
}
typescript
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 添加参数解析器
*
* @param resolvers 解析器
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserArgumentResolver());
}
}
new UserArgumentResolver() 需要自己实现自定义需求
java
// 主要用于对传入参数系统自动赋值
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 该方法用于判断Controller中方法参数中是否有符合条件的参数:
* 有则进入下一个方法resolveArgument
* 没有则跳过不做处理
* 通常在这里拦截一些请求,所有的请求都会经过这里判断
* 常规做法:
* 查看传入的controller是否存在指定注解,和指定参数,如果存在则解析出来注入
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return parameter.getParameterType().isAssignableFrom(CmsAccountSession.class)
&& parameter.hasParameterAnnotation(CurrentCmsAccount.class);
}
/**
* 该方法在上一个方法同通过之后调用:
* 在这里可以进行处理,根据情况返回对象------返回的对象将被赋值到Controller的方法的参数中
*
* @param methodParameter 方法参数
* @param modelAndViewContainer 模型和视图容器
* @param nativeWebRequest 原生Web请求
* @param webDataBinderFactory Web数据绑定器工厂
* @return {@link Object}
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
assert request != null;
HttpSession session = request.getSession();
// 获取cookie
Cookie[] cookies = request.getCookies();
String token = null;
for (Cookie c : cookies){
if ("token".equals(c.getName())){
token = c.getValue();
break;
}
}
// 如果token不存在,则返回null
if (token == null) {
return null;
}
// 获取session中对象
return session.getAttribute(token);
}
}
以上为通用的拦截器,用于拦截指定的正则接口,并且自动注入session信息