SpringMVC+FastJson 自定義日期轉換器

對於有的時候要輸出日期格式爲yyyy-MM-dd,而有的時候要輸出yyyy-MM-dd hh:mm:ss時怎麼辦?html

第一種方案:純註解式, 對日期類型的字段進行註解java

@JSONField(format = "yyyy-MM-dd")
private Date updateDate;

@JSONField(format = "yyyy-MM-dd hh:mm:ss")
private Date createDate;

public Date getUpdateDate() {
    return updateDate;
}

public void setUpdateDate(Date updateDate) {
    this.updateDate = updateDate;
}

public void setCreateDate(Date createDate) {
    this.createDate = createDate;
}

public Date getCreateDate() {
    return createDate;
}

第二種方案:使用fastjson的WriteDateUseDateFormat配置(使得返回的日期類型默認爲yyyy-MM-dd hh:mm:ss), 特殊類型使用字段@JSONField來進行控制web

<!-- 默認的註解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
   <mvc:message-converters register-defaults="true">
      <!-- 將Jackson2HttpMessageConverter的默認格式化輸出爲true -->
      <!-- 配置Fastjson支持 -->
      <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
         <property name="supportedMediaTypes">
            <list>
               <value>text/html;charset=UTF-8</value>
               <value>application/json</value>
            </list>
         </property>
         <property name="features">
            <list>
               <!-- 輸出key時是否使用雙引號 -->
               <value>QuoteFieldNames</value>
               <!-- 是否輸出值爲null的字段 -->
               <!-- <value>WriteMapNullValue</value> -->
               <!-- 數值字段若是爲null,輸出爲0,而非null -->
               <value>WriteNullNumberAsZero</value>
               <!-- List字段若是爲null,輸出爲[],而非null -->
               <value>WriteNullListAsEmpty</value>
               <!-- 字符類型字段若是爲null,輸出爲"",而非null -->
               <value>WriteNullStringAsEmpty</value>
               <!-- Boolean字段若是爲null,輸出爲false,而非null -->
               <value>WriteNullBooleanAsFalse</value>
               <!-- null String不輸出  -->
               <value>WriteNullStringAsEmpty</value>
               <!-- null String也要輸出  -->
               <!-- <value>WriteMapNullValue</value> -->

               <!-- Date的日期轉換器 -->
               <value>WriteDateUseDateFormat</value>
            </list>
         </property>
      </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

<!-- REST中根據URL後綴自動斷定Content-Type及相應的View -->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
   <property name="mediaTypes" >
      <map>
         <entry key="json" value="application/json"/>
      </map>
   </property>
   <!-- 這裏是否忽略掉accept header,默認就是false -->
   <property name="ignoreAcceptHeader" value="true"/>
   <property name="favorPathExtension" value="true"/>
</bean>
@JSONField(format = "yyyy-MM-dd")
private Date updateDate;

public Date getUpdateDate() {
    return updateDate;
}

public void setUpdateDate(Date updateDate) {
    this.updateDate = updateDate;
}

第三種方案:使用FastJson的消息轉換器, 特殊類型使用字段@JSONField來進行控制spring

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.io.OutputStream;

/**
 * 若是沒有注入默認的日期格式,也沒有配置<value>WriteDateUseDateFormat</value>, 也沒有屬性註解@JSONField(format="yyyy-MM-dd hh:mm:ss") 則會轉換輸出時間戳
 * 若是隻配置<value>WriteDateUseDateFormat</value>,則會轉換輸出yyyy-MM-dd hh:mm:ss
 * 配置<value>WriteDateUseDateFormat</value>, 屬性註解@JSONField(format="yyyy-MM-dd hh:mm:ss") 則會轉換輸出爲屬性註解的格式
 * 若是注入了默認的日期格式,屬性註解@JSONField(format="yyyy-MM-dd hh:mm:ss") 則會轉換輸出爲屬性註解的格式
 * 若是注入了默認的日期格式,則會轉換輸出爲默認的日期格式
 * 若是三者都配置則會轉換成屬性註解的格式
 * Created by PETER on 2016/2/5.
 */
public class CustomerFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {

    public static SerializeConfig mapping = new SerializeConfig();

    private String defaultDateFormat;

    @Override
    protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        OutputStream out = outputMessage.getBody();
        String text = JSON.toJSONString(obj, mapping, super.getFeatures());
        byte[] bytes = text.getBytes(getCharset());
        out.write(bytes);
    }

    public void setDefaultDateFormat(String defaultDateFormat) {
        mapping.put(java.util.Date.class, new SimpleDateFormatSerializer(defaultDateFormat));
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context" 
      xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
      xmlns:mvc="http://www.springframework.org/schema/mvc"
      xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
      http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

   <description>Spring MVC Configuration</description>

   <!-- 加載配置屬性文件 -->
   <context:property-placeholder ignore-unresolvable="true" location="classpath:/xmutca.properties" />

   <!-- 掃描dubbo註解須要在controller以前,不然會形成沒法注入的問題 -->
   <dubbo:annotation package="com.xmutca"></dubbo:annotation>

   <!-- 使用Annotation自動註冊Bean,只掃描@Controller -->
   <context:component-scan base-package="com.xmutca" use-default-filters="false">
      <!-- base-package 若是多個,用「,」分隔 -->
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
   </context:component-scan>

   <!-- 默認的註解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
   <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
      <mvc:message-converters register-defaults="true">
         <!-- 將Jackson2HttpMessageConverter的默認格式化輸出爲true -->
         <!-- 配置Fastjson支持 -->
         <bean class="com.ydyx.core.web.converter.CustomerFastJsonHttpMessageConverter">
            <property name="supportedMediaTypes">
               <list>
                  <value>text/html;charset=UTF-8</value>
                  <value>application/json</value>
               </list>
            </property>
            <property name="features">
               <list>
                  <!-- 輸出key時是否使用雙引號 -->
                  <value>QuoteFieldNames</value>
                  <!-- 是否輸出值爲null的字段 -->
                  <!-- <value>WriteMapNullValue</value> -->
                  <!-- 數值字段若是爲null,輸出爲0,而非null -->
                  <value>WriteNullNumberAsZero</value>
                  <!-- List字段若是爲null,輸出爲[],而非null -->
                  <value>WriteNullListAsEmpty</value>
                  <!-- 字符類型字段若是爲null,輸出爲"",而非null -->
                  <value>WriteNullStringAsEmpty</value>
                  <!-- Boolean字段若是爲null,輸出爲false,而非null -->
                  <value>WriteNullBooleanAsFalse</value>
                  <!-- null String不輸出  -->
                  <value>WriteNullStringAsEmpty</value>
                  <!-- null String也要輸出  -->
                  <!-- <value>WriteMapNullValue</value> -->
               </list>
            </property>
            <property name="defaultDateFormat" value="yyyy-MM-dd"></property>
         </bean>
      </mvc:message-converters>
   </mvc:annotation-driven>

   <!-- REST中根據URL後綴自動斷定Content-Type及相應的View -->
   <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
      <property name="mediaTypes" >
         <map>
            <entry key="json" value="application/json"/>
         </map>
      </property>
      <!-- 這裏是否忽略掉accept header,默認就是false -->
      <property name="ignoreAcceptHeader" value="true"/>
      <property name="favorPathExtension" value="true"/>
   </bean>

   <!-- 視圖文件解析配置 -->
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="${web.view.prefix}"/>
      <property name="suffix" value="${web.view.suffix}"/>
   </bean>

   <!-- 對靜態資源文件的訪問, 將沒法mapping到Controller的path交給default servlet handler處理 -->
   <mvc:default-servlet-handler/>

   <!-- 定義無Controller的path<->view直接映射 -->
   <mvc:view-controller path="/" view-name="redirect:${web.view.index}"/>

   <!-- 基於註解式子的異常處理 -->
   <bean id="exceptionHandlerExceptionResolver" class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
   <!-- Shiro end -->

   <!-- 上傳文件攔截,設置最大上傳文件大小   10M=10*1024*1024(B)=10485760 bytes -->
   <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <property name="maxUploadSize" value="${web.maxUploadSize}" />
   </bean>
</beans>

第四種方案:使用SpringMVC的自定義屬性編輯器express

@InitBinder
protected void initBinder(WebDataBinder binder) {
    // String類型轉換,將全部傳遞進來的String進行先後空格處理, null字符串處理
    binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
        @Override
        public void setAsText(String text) {
            setValue(text == null ? null : text.trim());
        }

        @Override
        public String getAsText() {
            Object value = getValue();
            return value != null ? value.toString() : "";
        }
    });

    // Date 類型轉換
    binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
        @Override
        public void setAsText(String text) {
            setValue(DateUtils.parseDate(text));
        }

        @Override
        public String getAsText() {
            Date date = (Date) getValue();
            return DateUtils.formatDate(date, "yyyy-MM-dd");
        }
    });
}

DateUtils源代碼:apache

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.time.DateFormatUtils;

/**
 * 日期工具類, 繼承org.apache.commons.lang.time.DateUtils類
 * 
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

   private static String[] parsePatterns = { "yyyy-MM-dd",
         "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd",
         "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm" ,"yyyyMMdd"};

   /**
    * 獲得當前日期字符串 格式(yyyy-MM-dd)
    */
   public static String getDate() {
      return getDate("yyyy-MM-dd");
   }

   /**
    * 獲得當前日期字符串 格式(yyyy-MM-dd) pattern能夠爲:"yyyy-MM-dd" "HH:mm:ss" "E"
    */
   public static String getDate(String pattern) {
      return DateFormatUtils.format(new Date(), pattern);
   }

   /**
    * 獲得日期字符串 默認格式(yyyy-MM-dd) pattern能夠爲:"yyyy-MM-dd" "HH:mm:ss" "E"
    */
   public static String formatDate(Date date, Object... pattern) {
      String formatDate = null;
      if (pattern != null && pattern.length > 0) {
         formatDate = DateFormatUtils.format(date, pattern[0].toString());
      } else {
         formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
      }
      return formatDate;
   }

   /**
    * 獲得日期時間字符串,轉換格式(yyyy-MM-dd HH:mm:ss)
    */
   public static String formatDateTime(Date date) {
      return formatDate(date, "yyyy-MM-dd HH:mm:ss");
   }

   /**
    * 獲得當前時間字符串 格式(HH:mm:ss)
    */
   public static String getTime() {
      return formatDate(new Date(), "HH:mm:ss");
   }

   /**
    * 獲得當前日期和時間字符串 格式(yyyy-MM-dd HH:mm:ss)
    */
   public static String getDateTime() {
      return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
   }

   /**
    * 獲得當前年份字符串 格式(yyyy)
    */
   public static String getYear() {
      return formatDate(new Date(), "yyyy");
   }

   /**
    * 獲得當前月份字符串 格式(MM)
    */
   public static String getMonth() {
      return formatDate(new Date(), "MM");
   }

   /**
    * 獲得當天字符串 格式(dd)
    */
   public static String getDay() {
      return formatDate(new Date(), "dd");
   }

   /**
    * 獲得當前星期字符串 格式(E)星期幾
    */
   public static String getWeek() {
      return formatDate(new Date(), "E");
   }

   /**
    * 日期型字符串轉化爲日期 格式 { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
    * "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMdd" }
    */
   public static Date parseDate(Object str) {
      if (str == null) {
         return null;
      }
      try {
         return parseDate(str.toString(), parsePatterns);
      } catch (ParseException e) {
         return null;
      }
   }

   /**
    * 獲取過去的天數
    * 
    * @param date
    * @return
    */
   public static long pastDays(Date date) {
      long t = new Date().getTime() - date.getTime();
      return t / (24 * 60 * 60 * 1000);
   }

   /**
    * 獲取過去的小時
    * @param date
    * @return
    */
   public static long pastHour(Date date) {
      long t = new Date().getTime()-date.getTime();
      return t/(60*60*1000);
   }

   /**
    * 獲取過去的分鐘
    * @param date
    * @return
    */
   public static long pastMinutes(Date date) {
      long t = new Date().getTime()-date.getTime();
      return t/(60*1000);
   }

   /**
    * 轉換爲時間(天,時:分:秒.毫秒)
    * @param timeMillis
    * @return
    */
    public static String formatDateTime(long timeMillis){
      long day = timeMillis/(24*60*60*1000);
      long hour = (timeMillis/(60*60*1000)-day*24);
      long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
      long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
      long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
      return (day>0?day+",":"")+hour+":"+min+":"+s+"."+sss;
    }

   /**
    * 獲取某一天的開始時間(0點)
    * @param date
    * @return
    */
   public static Date getDateStart(Date date) {
      if (date == null) {
         return null;
      }
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      try {
         date = sdf.parse(formatDate(date, "yyyy-MM-dd") + " 00:00:00");
      } catch (ParseException e) {
         e.printStackTrace();
      }
      return date;
   }

   /**
    * 獲取某一天的結束時間(23:59)
    * 
    * @param date
    * @return
    */
   public static Date getDateEnd(Date date) {
      if (date == null) {
         return null;
      }
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      try {
         date = sdf.parse(formatDate(date, "yyyy-MM-dd") + " 23:59:59");
      } catch (ParseException e) {
         e.printStackTrace();
      }
      return date;
   }

   /**
    * 比較兩個日期時間的大小,反回1表示preDateStr > nextDateStr,0就相等,-1爲小於
    * @author: weihuang.peng
    * @param preDateStr
    * @param nextDateStr
    * @return result
    */
   public static int compareDate(Object preDateStr, Object nextDateStr) {
      int result = 0;
      Date preDate = parseDate(preDateStr);
      Date nextDate = parseDate(nextDateStr);
      try {
         result =  preDate.compareTo(nextDate);
      } catch (Exception e) {
         result = 0;
         e.printStackTrace();
      }
      return result;
   }

   /**
    * 獲取某一天的前幾天或者後幾天,根據數字符號決定天數
    * @author: weihuang.peng
    * @param date
    * @param days
    * @return
    */
   public static String getPastDayStr(Object dateObj, int days) {
      Date date = parseDate(dateObj);
      long time = date.getTime() + days * (long)(24 * 60 * 60 * 1000);
      return formatDate(new Date(time));
   }

   /**
    * preDateStr - nextDateStr 返回秒數
    * @author: huiyang.yu
    * @param preDateStr
    * @param nextDateStr
    * @return
    */
   public static long getSubactDate(Object preDateStr, Object nextDateStr) {
      Date preDate = parseDate(preDateStr);
      Date nextDate = parseDate(nextDateStr);
      long result = (preDate.getTime() - nextDate.getTime()) / 1000L;
      return result; 
   }

   /**
    * 返回過去的天數: preDateStr - nextDateStr 
    * @author: weihuang.peng
    * @param preDateStr
    * @param nextDateStr
    * @return
    */
   public static long getDifferDate(Object preDateStr, Object nextDateStr) {
      return getSubactDate(preDateStr, nextDateStr) / (60 * 60 * 24L);
   }

   /**
    * 傳入日期時間與當前系統日期時間的比較,
    * 若日期相同,則根據時分秒來返回 ,
    * 不然返回具體日期
    * @author: huiyang.yu
    * @param updateDate 傳入日期
    * @param updateTime 傳入時間
    * @return 日期或者 xx小時前||xx分鐘前||xx秒前
    */
   public static String getNewUpdateDateString(String updateDate, String updateTime) {
      String result = updateDate;
      long time = 0;
      if (updateDate.equals(DateUtils.getDate())) {
         time = DateUtils.getSubactDate(DateUtils.getDateTime(), updateDate
               + " " + updateTime);
         if (time >= 3600) {
            result = time / 3600 + "小時前";
         } else if (time >= 60) {
            result = time / 60 + "分鐘前";
         } else if (time >= 1) {
            result = time + "秒前";
         } else {
            result = "剛剛";
         }
      } else if (result.length() >= 10) {
         result = result.substring(5);
      }
      return result;
   } 
}
相關文章
相關標籤/搜索