通过自定义参数解析器+注解 实现SpringMVC属性注入指定格式的Date对象

By | 2019年7月19日

一、需求分析

默认情况下,如果注入Date类型的对象,会报如下错误:

Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value 'xxxx-xx-xx'; nested exception is java.lang.IllegalArgumentException
原代码如下:
@RequestMapping(value="/generateReport.json",method = RequestMethod.GET)
@ResponseBody
public JSONObject generateReport(Date date){
   JSONObject ret = new JSONObject();
   /***********/
   return ret;
}

二、解决方法

虽然这里可以直接改为String类型,然后手动去解析,但是如果项目中这种需求出现多次的话,那每次都去手动解析并不是一种较好的选择。

所以这里,我通过自定义参数解析器加注解来实现,用注解可以更加灵活!

2.1、先写一个注解类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface RequestFormat {
    String value() default "yyyy-MM-dd HH:mm:ss";
}
2.2、调用该注解类
@RequestMapping(value="/generateReport.json",method = RequestMethod.GET)
@ResponseBody
public JSONObject generateReport(@RequestFormat("yyyy-MM-dd") Date date){
   JSONObject ret = new JSONObject();
   /***代码写的不好,就不贴了***/
   return ret;
}
2.3、编写自定义参数解析器

我这里写的比较基础,后续如果有更多的功能要求,再完善。本文也只是记录自己解决该问题的一种思路!

package com.renyiwei.web.resolver;

import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.beans.PropertyEditorSupport;
import java.lang.annotation.Annotation;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateArgumentResolver implements HandlerMethodArgumentResolver {


    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        // 获取参数类型
        Class<?> paramType = methodParameter.getParameterType();
        return Date.class.isAssignableFrom(paramType) && methodParameter.getParameterAnnotation(RequestFormat.class)!=null;
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        RequestFormat requestFormat = methodParameter.getParameterAnnotation(RequestFormat.class);
        String format = requestFormat.value();
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
        //获取方法的函数形参名称
        String[] parameterNames = discover.getParameterNames(methodParameter.getMethod());
        //获取当前参数的名称
        String parameterName = parameterNames[methodParameter.getParameterIndex()];
        //获取值
        String requestValue = nativeWebRequest.getParameter(parameterName);
        return sdf.parse(requestValue);
    }
}
2.4、配置该参数解析器

在Springboot中配置该参数解析器

package com.renyiwei.sprintboot;

@Configuration
//@EnableWebMvc
@ControllerAdvice
public class SpringMvcConfig implements WebMvcConfigurer {
  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new CustomDateArgumentResolver());
  }
}