Spring MVC 之 处理Date类型

Posted carl-zhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring MVC 之 处理Date类型相关的知识,希望对你有一定的参考价值。

在使用Spring MVC的项目中,我们经常需要遇到处理时间类型的字段。一般情况下大家可能都是通过String来接收这个对象,然后再把它转化成Date类型。如何能够优雅的处理这些时间类型的字段呢?下面我来分享一下我总结的一些方法。

一、Input

假如我们有一个User对象里面有一个birthday属性。一般情况下大家在使用Spring MVC的时候可能都是使用String字段来接收。然后再把它转换成Date类型插入到数据库中。但是今天要讲的是直接使用Date类型来接收前台传输过来的日期属性。

User.class

public class User 

    private Date birthday;

    public Date getBirthday() 
        return birthday;
    

    public void setBirthday(Date birthday) 
        this.birthday = birthday;
    

1.1 form data

首先以form data的形式传输一个birthday属性。我们写一个简单Controller来测试一下。

方法一:

@Controller
public class DateController 

    @InitBinder
    public void intDate(WebDataBinder dataBinder)
        dataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
    

    @RequestMapping("test")
    @ResponseBody
    public User test( User date)
        System.out.println(date);
        return date;
    

没有错,就是加了@InitBinder注解,为处理Date类型添加了处理类。而且请注意这个@InitBinder是这个类级别的,也就是说你其它Controller也可以使用这种方法添加Date处理类用于处理不同的pattern.

使用@InitBinder注解还可以指定哪些属性需要被处理。

    @InitBinder
    public void intDate(WebDataBinder dataBinder)
        dataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"), "birthday");
    

其实@InitBinder注解还可以办其它很多的事情。大家可以慢慢挖掘。

方法二:

不使用@InitBinder注解,而在你需要绑定属性的注解上面添加@DateTimeFormat注解也同样能够达到你的目的。

方法三:

使用Spring MVC的扩展接口HandlerMethodArgumentResolver。它的使用是把HttpRequest里面的参数解析成Controller里面标注了@RequestMapping方法的方法参数。

1) Date.java – 指定该方法参数需要特殊处理

Date.java

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Date 

    String[] params () default "";

    String pattern() default "yyyy-MM-dd HH:mm:ss";

2) DateHandlerMethodArgumentResolver – 处理标注了@Date注解的方法参数

public class DateHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver 

    private String[] params;

    private String pattern;

    @Override
    public boolean supportsParameter(MethodParameter parameter) 

        boolean hasParameterAnnotation = parameter.hasParameterAnnotation(Date.class);
        if(!hasParameterAnnotation)
            return false;
        
        Date parameterAnnotations = parameter.getParameterAnnotation(Date.class);
        String[] parameters = parameterAnnotations.params();
        if(StringUtils.isNoneBlank(parameters))
            params = parameters;
            pattern = parameterAnnotations.pattern();
            return true;
        
        return false;
    

    @Override
    public Object resolveArgument(MethodParameter methodParam, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception 
        Object object = BeanUtils.instantiateClass(methodParam.getParameterType());
        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        for (String param : params) 
            String value = request.getParameter(param);
            if(StringUtils.isNoneBlank(value))
                SimpleDateFormat sdf = new SimpleDateFormat(this.pattern);
                java.util.Date date = sdf.parse(value);
                PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) 
                    if(propertyDescriptor.getName().equals(param))
                        Method writeMethod = propertyDescriptor.getWriteMethod();
                        if(!Modifier.isPublic(writeMethod.getModifiers()))
                            writeMethod.setAccessible(true);
                        
                        writeMethod.invoke(object, date);
                    
                
            
        
        return object;
    

3) MyMVCConfig – 配置Spring MVC扩展

MyMVCConfig.java

@Configuration
@EnableWebMvc
public class MyMVCConfig extends WebMvcConfigurerAdapter

    ......

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) 
        argumentResolvers.add(new DateHandlerMethodArgumentResolver());
    

4) DateController – 测试类

@Controller
public class DateController 

    @RequestMapping("test")
    @ResponseBody
    public User test(@Date(params = "birthday") User date)
        System.out.println(date);
        return date;
    

User类不需要做任何改变。

可以看到,这样同样能够达到效果。

1.2 restful – json

上面的两种情况针对表格提交有效,但是对于Spring MVC里面的Restful语法就会无效。下面就来看看如何针对restful请求的日期对象。

对应的Controller就需要修改一下了。

DateController.java

@Controller
public class DateController 

    @RequestMapping("test")
    @ResponseBody
    public User test( @RequestBody User date)
        System.out.println(date);
        return date;
    

Spring MVC restful是底层是使用Jackson来实现的。所以针对这种情况,我们就可以使用Jackson的注解@JsonDeserialize来实现。

修改点:

1 、User.java

public class User 

    @JsonDeserialize(using = DateJsonDeserialize.class)
    private Date birthday;

    public Date getBirthday() 
        return birthday;
    

    public void setBirthday(Date birthday) 
        this.birthday = birthday;
    

对应的添加一个JsonDeserialize反序列化类。

2、DateJsonDeserialize.java

public class DateJsonDeserialize extends JsonDeserializer<Date> 

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctx) throws IOException 
        String text = p.getText();
        if(StringUtils.isBlank(text))
            return null;
        
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try 
            date = sdf.parse(text);
         catch (ParseException e) 
            e.printStackTrace();
        
        return date;
    

二、ouput

对于输出,我们就使用Spring MVC使用的@ResponseBody来返回json对象。但是如果我们不加处理返回的对象就是一个时间long的数据。

同样的Spring MVC的返回值也是使用的Jackson来实现返回json的,那么我们就使用Jackson的@JsonSerialize注解来序列化Date类型。

修改点:

1、User.java

public class User 

    @JsonDeserialize(using = DateJsonDeserialize.class)
    @JsonSerialize(using = DateJsonSerialize.class)
    private Date birthday;

    public Date getBirthday() 
        return birthday;
    

    public void setBirthday(Date birthday) 
        this.birthday = birthday;
    

同样的你也需要自定义一个日期的序列化的类。

2、DateJsonSerialize.java

public class DateJsonSerialize extends JsonSerializer 

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException 
        if(value != null)
            if(value.getClass().isAssignableFrom(Date.class))
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String format = sdf.format((Date) value);
                gen.writeString(format);
            
        
    

再次调用就能够达到自己想要的效果了。

三、总结

通过这个例子一方面是想向给大家推荐一下在项目中我们经常遇到的日期类型我们如何能够优雅的处理它。另一方面也想为大家展示一下Spring MVC restful中的序列化与反序列化情况。通过对日期类型的展示,我想大家可以很简单的处理其它对象的序列化与反序列化情况。

与50位技术专家面对面 20年技术见证,附赠技术全景图

以上是关于Spring MVC 之 处理Date类型的主要内容,如果未能解决你的问题,请参考以下文章

关于springmvc怎么自动把前台string类型日期字段转换成date类型

Spring MVC中自定义类型转换器(Date)

Spring MVC中自定义类型转换器(Date)

java之spring mvc之数据处理

Spting +Spring MVC+spring date jsp +hibernate+jq

Spring MVC 接收请求参数所有方式总结!