java WebMvcConfigurer实现类

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信息

相关推荐
言慢行善14 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星14 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟14 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z14 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可14 小时前
Java 中的实现类是什么
java·开发语言
He少年15 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
克里斯蒂亚诺更新15 小时前
myeclipse的pojie
java·ide·myeclipse
迷藏49415 小时前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏49415 小时前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链
qq_4335021815 小时前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书