zoukankan      html  css  js  c++  java
  • Spring拦截机制之后端国际化心得

    需求

    前端请求的header里带有Prefer_Lang参数,向后端传递国际化信息,后端需要在处理业务之前(建立拦截机制),将Prefer_Lang保存于线程上下文。

    思路分析

    初次接收该需求时,为了不改变既有代码而捕获request中的Prefer_Lang参数,脑海中第一反应是拦截器的概念。

    方案一

    Servlet的javax.servlet.Filter 或起源于Spring Security的org.springframework.web.filter.DelegatingFilterProxy

    要点分析

    • 这种Filter在web.xml中配置,表面上能满足需求,但Filter与web容器耦合,不利于将国际化模块提供给第三方使用

    方案二

    SpringMVC的org.springframework.web.servlet.HandlerInterceptor

    具体实施

    • 在spring mvc的xml中配置,基于request-response模型进行拦截,与方案一Filter类似
    <mvc:interceptors>
        <mvc:interceptor>
        <mvc:mapping path="/**" />
        <bean class="com.shjv.tdscdma.omc.server.platform.web.interceptor.LanguageInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    

    要点分析

    • 仔细探讨需求后,发现我们仅需要对Controller的调用进行拦截即可,只有Controller的调用才与后端国际化逻辑有关
    • 该方案对包括html、js等等与后端国际化逻辑无关的任意请求皆进行拦截,无意义地消耗大量系统资源
    • 虽然request-response模型上的拦截机制不可取,但是拦截也是AOP概念中的一部分,故有更优方案

    方案三

    Spring古老的AOP技术org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator

    具体实施

    • 在spring mvc的xml中配置,为所有beanNameController为后缀的bean生成代理对象
    <bean id="languageInterceptor"
          class="com.shjv.tdscdma.omc.server.platform.web.interceptor.LanguageInterceptor"></bean>
    <bean
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
        <list>
        <value>*Controller</value>
        </list>
        </property>
        <property name="interceptorNames">
        <list>
        <value>languageInterceptor</value>
        </list>
        </property>
    </bean>
    

    要点分析

    • 表面上,该方案很好地实现了对所有beanNameController为后缀的bean进行拦截,没有方案二浪费系统资源的弊端。
    • 但是,无法保证开发人员自行编写的其他bean就不会以Controller为后缀
    • 同时,无法保证开发人员编写的Controller类就一定是以ControllerbeanName后缀
    • 我们知道,编写的Controller能为Spring MVC调度,是因为从代码结构上,强制了Controller类必须标注@Controller的注解,故有更优方案

    方案四

    Spring AOP的XML配置

    具体实施

    • 在spring mvc的xml中配置,拦截所有标注@Controller的注解的Controller
    <bean id="languageInterceptor"
          class="com.shjv.tdscdma.omc.server.platform.web.interceptor.LanguageInterceptor"></bean>
    <aop:config>
        <aop:aspect ref="languageInterceptor">
            <aop:before method="trapLanguage"
                        pointcut="execution(* *(..)) and within(@org.springframework.stereotype.Controller *)"/>
        </aop:aspect>
    </aop:config>
    

    要点分析

    • 目前看来,该方案已经近乎完美地满足了我们的需求,通过within(@org.springframework.stereotype.Controller *)只拦截Spring MVC中的Controller的public方法
      做到。
    • 如果你与我一样是个XML Hater,我们还有更优雅的实现方式。

    方案五

    Spring AOP的Annotation配置。

    具体实施

    • 在此,我们更进一步,只拦截Controller下标注了@RequestMapping的公共方法,JAVA代码如下
    @Component
    @Aspect
    public class LanguageInterceptor {
        @Pointcut("execution(@org.springframework.web.bind.annotation.RequestMapping * *(..)) && within(@org.springframework.stereotype.Controller *)")
        public void controllerMethod() {
        }
    
        @Before("controllerMethod()")
        public void trapLanguage() {
            final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            LanguageOption.setPreferLang(request == null ? null : request.getHeader("Prefer_Lang"));
        }
    }
    
    • 在spring mvc的xml中配置如下
    <aop:aspectj-autoproxy />
    
  • 相关阅读:
    JDBC遇到向ORACLE数据库表执行插入操作时,报错“列在此处不允许”
    关于对称加密和非对称加密以及签名,认证和证书的理解
    .net framework 各版本区别
    数据库设计三大范式
    业务系统设计
    修改 Windows 服务器默认远程端口3389
    iis读取不到本地证书问题 提示已经导入成功
    HTTPS 建立连接的详细过程
    使用ServiceStack构建Web服务
    转-微信支付(公众号支付JSAPI)
  • 原文地址:https://www.cnblogs.com/lewh/p/6248267.html
Copyright © 2011-2022 走看看