springmvc源码扩展——自定义参数解析

来源:互联网 发布:又拍云存储 域名 编辑:程序博客网 时间:2024/06/08 12:00

项目中使用json传递数据,定义了一套统一的格式,如下所示,但是实际上业务层面只需要处理data节点的数据,sign、signType参数由框架层面进行验签处理。项目中的web层使用了springmvc、resteasy框架,为了方便接收data节点的json数据,笔者扩展了springmvc的源码,添加了自定义的HandlerMethodArgumentResolver。

{    "sign":"xxx",    "signType":"xxx",    "data":{        "partnerId":"xxx",        ......    }}

springmvc部分源码分析

下面是springmvc处理请求的核心流程
这里写图片描述
先是根据HttpServletRequest遍历所有的HandlerMapping,常用的实现类有RequestMappingHandlerMapping、BeanNameUrlHandlerMapping,调用其getHandler方法获取HandlerExecutionChain,这个对象里面包括了我们熟悉的HandlerInteceptor拦截器,会在处理请求前、后、产生响应的时候被调用。然后,根据HandlerExecutionChain的Handler实例,获取HandlerAdapter,同样的,也是遍历List,如果HandlerAdapter.supports(handler)则返回,比如RequestMappingHandlerAdapter、HttpRequestHandlerAdapter。接下来,将请求交给HandlerAdapter处理,返回ModelAndView。
HanderAdapter是调用Controller的核心接口,由它负责处理请求。RequestMappingHandlerAdapter是HandlerAdapter的子类,它支持对HandlerMethod的处理,并进行参数处理、执行HandlerMethod,处理响应数据等。它包括了常见的参数解析器(HandlerMethodArgumentResolver),例如对@RequestBody、@Path的处理,大家可以看下它的实现类。另外,还有方法返回数据的处理类(HandlerMethodReturnValueHandler)。我们现在需要对入参进行处理,因此需要实现HandlerMethodArgumentResolver接口。如果对响应数据进行处理,需要实现HandlerMethodReturnValueHandler。
关键是怎么将自定义的HandlerMethodArgumentResolver添加到RequestMappingHandlerAdapter中?因为RequestMappingHandlerAdapter是受spring管理的类,如果是以xml配置springmvc的话,org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser在处理标签时会注册RequestMappingHandlerAdapter的bean定义。如果是以@EnableWebMvc注解配置springmvc的话,也会有这个类的定义。既然如此,搞个BeanPostProcessor应该是可以的。具体的代码,请笔者结合时序图进行阅读。

如何扩展

先自定义个注解,用来支持对json中的data节点进行处理

/** * 用于扩展SpringMVC的参数解析功能,只读取json串中的data节点作为Controller方法入参,eg: * public JsonResult pay( @RequestDataBody PayRequest request, Sign sign ) * @author huangxf * @date 2017年4月10日 */@Target({ElementType.TYPE, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestDataBody {    boolean required() default true;}

写个BeanPostProcessor实现postProcessBeforeInitialization方法,并且将这个bean交给spring管理即可。这样,我们在RequestMappingHandlerAdapter初始化之前,便可以添加自定义的参数解析器,如下所示。我的github提供的代码,支持SessionUser(接口)、Sign(接口)、@RequestDataBody的处理,相关的代码在net.dwade.plugins.spring.web这个包下面,github地址:https://github.com/huangxfchn/dwade/tree/master/framework-plugins

/*** 使用{@link BeanPostProcessor}对SpringMVC进行扩展,* 支持{@link RequestDataBody}、{@link Sign}、{@link SessionUser}、{@link CheckSign}、{@link SignResponseBody}* @see RequestMappingHandlerAdapter* @see BeanPostProcessor* @author huangxf* @date 2017年4月13日*/public class PaymentControllerSupport implements BeanPostProcessor, ApplicationContextAware {    private ApplicationContext applicationContext;    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName)            throws BeansException {        if ( bean instanceof RequestMappingHandlerAdapter ) {            RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter)bean;            registerArgumentsResolvers( adapter );            registerReturnValueHandlers( adapter );        }        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName)            throws BeansException {        return bean;    }    /**    * 注册参数解析器     * @param adapter    * @return void    */    private void registerArgumentsResolvers( RequestMappingHandlerAdapter adapter ) {        List<HandlerMethodArgumentResolver> resolvers = this.getCustomerArgumentResolvers( adapter );        if ( adapter.getCustomArgumentResolvers() == null ) {            adapter.setCustomArgumentResolvers( resolvers );        } else {            adapter.getCustomArgumentResolvers().addAll( resolvers );        }    }    /**    * 注册返回值处理器    * @param adapter    * @return void    */    private void registerReturnValueHandlers( RequestMappingHandlerAdapter adapter ) {        List<HandlerMethodReturnValueHandler> resolvers = this.getCustomerReturnValueHandler( adapter );        if ( adapter.getCustomReturnValueHandlers() == null ) {            adapter.setCustomReturnValueHandlers( resolvers );        } else {            adapter.getCustomReturnValueHandlers().addAll( resolvers );        }    }    protected List<HandlerMethodArgumentResolver> getCustomerArgumentResolvers( RequestMappingHandlerAdapter adapter ) {        //处理method参数中SessionUser        HandlerMethodArgumentResolver sessionUserResolver = new SessionUserResolver();        applicationContext.getAutowireCapableBeanFactory().initializeBean( sessionUserResolver, SessionUserResolver.class.getName() );        //对请求参数进行处理,解析data节点、签名        HandlerMethodArgumentResolver requestDataResolver = new RequestDataConverterProcessor( adapter.getMessageConverters() );        applicationContext.getAutowireCapableBeanFactory().initializeBean( requestDataResolver, RequestDataConverterProcessor.class.getName() );        //处理验签        HandlerMethodArgumentResolver signResolver = new SignResponseProcessor( adapter.getMessageConverters() );        applicationContext.getAutowireCapableBeanFactory().initializeBean( signResolver, SignResponseProcessor.class.getName() );        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();        resolvers.add( sessionUserResolver );        resolvers.add( requestDataResolver );        resolvers.add( signResolver );        return resolvers;    }    /**    * 获取返回参数处理的HandlerMethodReturnValueHandler实现类    * @param adapter    * @return List<HandlerMethodReturnValueHandler>    */    protected List<HandlerMethodReturnValueHandler> getCustomerReturnValueHandler( RequestMappingHandlerAdapter adapter ) {        //处理签名、验签        HandlerMethodReturnValueHandler signHandler = new SignResponseProcessor( adapter.getMessageConverters() );        applicationContext.getAutowireCapableBeanFactory().initializeBean( signHandler, SignResponseProcessor.class.getName() );        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();        handlers.add( signHandler );        return handlers;    }    @Override    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext = applicationContext;    }}

如何使用

json报文如下,假设我需要将data节点,使用PayOffRequest对象接收,只需要添加@RequestDataBody注解即可

{    "sign":"xxx",    "signType":"xxx",    "data":{        "partnerId":"xxx",        "money":10000    }}

Controller代码

@Controller@RequestMapping( "/pay" )public class PaymentController {    private final Logger logger = LoggerFactory.getLogger( PaymentController.class );    /**    * <code>@CheckSign</code>:需要验签,<code>@SignResponseBody</code>:响应的数据需要签名处理    * @param request        * @param user    * @return PaymentResponse<PayOffResponse>    */    @RequestMapping(value="payoff", method=RequestMethod.POST)    public PaymentResponse<PayOffResponse> payOff( @RequestDataBody PayOffRequest request,             HttpServletRequest httpRequest, SessionUser user ) {        // your code...    }}
阅读全文
0 0