本系列文章主要索引詳情 點(diǎn)擊查看
Java8之前,我們一般都是使用的java.util.Data API來定義日期和時(shí)間题禀,而Java8為我們提供了一個(gè)新的Java data-time API(JSR 310)缀蹄。這個(gè)新的API比老的API要好的多,因?yàn)樗鼘?duì)人類的日期進(jìn)行了細(xì)致的區(qū)分,并使用了流暢的API和不可變的數(shù)據(jù)結(jié)構(gòu)猿妈。
在本實(shí)例中肢藐,我們將使用新API中的LocalDate類故河,LocalDate類就是一個(gè)簡(jiǎn)單的日期,沒有與其向關(guān)聯(lián)的時(shí)間吆豹。這與老API中的LocalTime是有區(qū)別的鱼的,后者代表了一天中的某個(gè)時(shí)間,而LocalDateTime能包含日期和時(shí)間兩部分信息痘煤,或者是ZonedDateTime凑阶,它還包含了一個(gè)時(shí)區(qū)。
了解 Java 8 data-time API更多信息:
????http://docs.oracle.com/javase/tutorial/datetime/TOC.html
工具
IntelliJ IDEA 16
JDK 1.8
Maven 3.5
Tomcat 1.8
使用LocalDate日期
1衷快、修改前一篇中我們新建的DTO類ProfileForm,將其中birthDate字段的類型修改為L(zhǎng)ocalDate
package com.example.dto;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import java.time.LocalDate;
public class ProfileForm {
private String twitterHandle;
private String email;
private LocalDate birthDate;
public String getTwitterHandle() {
return twitterHandle;
}
public void setTwitterHandle(String twitterHandle) {
this.twitterHandle = twitterHandle;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public LocalDate getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
@Override
public String toString() {
return "ProfileForm{" +
"twitterHandle='" + twitterHandle + '\'' +
", email='" + email + '\'' +
", birthDate='" + birthDate + '\'' +
'}';
}
}
2宙橱、啟動(dòng)項(xiàng)目,訪問http://localhost:8081/profile,錄入表單數(shù)據(jù)蘸拔,并提交师郑,此時(shí)如果我們使用一個(gè)日期值(如2017/08/01),它其實(shí)不能運(yùn)行调窍,會(huì)提示一個(gè)400錯(cuò)誤
3宝冕、我們需要調(diào)試應(yīng)用來了解發(fā)生了什么錯(cuò)誤,我們可以通過輸出日志邓萨,來定位問題猬仁。我們只需要在application.properties中添加如下這行代碼:
logging.level.org.springframework.web=DEBUG
添加上述配置之后,我們就可以在控制臺(tái)中看到Spring Web所產(chǎn)生的調(diào)試信息先誉。如果想要將日志輸出到文件中湿刽,則只需要指定日志文件路徑即可:
logging.file=D:/IDEA/log/log.log
4、此時(shí)我們?cè)俅翁峤槐韱魏侄偃罩局袝?huì)看到如下的錯(cuò)誤:
Field error in object 'profileForm' on field 'birthDate': rejected value [2017-08-01]; codes [typeMismatch.profileForm.birthDate,typeMismatch.birthDate,typeMismatch.java.time.LocalDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [profileForm.birthDate,birthDate]; arguments []; default message [birthDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'birthDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for value '2017-08-01'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2017-08-01]]
此時(shí)我們需要一個(gè)Formatter诈闺,來對(duì)我們的日期進(jìn)行格式化。
在Spring 中铃芦,F(xiàn)ormatter類能夠用來print和parse對(duì)象雅镊。它可以將一個(gè)String轉(zhuǎn)碼為值,也可而已將一個(gè)值輸出為String刃滓。
5仁烹、在dto包的同級(jí)新建一個(gè)date包,然后創(chuàng)建一個(gè)簡(jiǎn)單的Formatter咧虎,命名為L(zhǎng)ocalDateFormatter卓缰,實(shí)現(xiàn)Formatter,并重寫print和parse方法:
package com.example.date;
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateFormatter implements Formatter<LocalDate> {
public static final String US_PATTERN = "yyyy-MM-dd";
public static final String NORMAL_PATTERN="yyyy-MM-dd";
@Override
public String print(LocalDate localDate, Locale locale) {
return DateTimeFormatter.ofPattern(getPattern(locale)).format(localDate);
}
@Override
public LocalDate parse(String s, Locale locale) throws ParseException {
return LocalDate.parse(s,DateTimeFormatter.ofPattern(getPattern(locale)));
}
/**
* 獲取用戶所處地域的日期格式
* @param locale
* @return
*/
public static String getPattern(Locale locale){
return isUnitedStates(locale)?US_PATTERN : NORMAL_PATTERN;
}
private static boolean isUnitedStates(Locale locale){
return Locale.US.getCountry().equals(locale.getCountry());
}
}
這個(gè)類能夠根據(jù)用戶所在地域來解析日期。
6征唬、在date包的同級(jí)新建config包捌显,并創(chuàng)建名為WebConfiguration的新類:
package com.example.config;
import com.example.date.LocalDateFormatter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.time.LocalDate;
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter{
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldType(LocalDate.class,new LocalDateFormatter());
}
}
這個(gè)類擴(kuò)展了WebMvcConfigurerAdapter,這是對(duì)Spring MVC進(jìn)行自定義配置的一個(gè)很便利的類总寒,它提供了很多的擴(kuò)展點(diǎn)扶歪,我們可以重寫如addFormatters()這樣的方法來訪問這些擴(kuò)展點(diǎn)。
@Configuration注解:標(biāo)注在類上摄闸,相當(dāng)于把該類作為spring的xml配置文件中的<beans>善镰,作用為:配置spring容器(應(yīng)用上下文)。
7年枕、此時(shí)我們?cè)偬峤槐韱蔚脑掛牌郏筒粫?huì)產(chǎn)生錯(cuò)誤了,除非我們不按照正確的格式來進(jìn)行輸入画切。
8、但是現(xiàn)在我們并不知道需要以什么樣的格式來輸入日期囱怕,我們可以在表單上添加這個(gè)信息霍弹。
在ProfileController中,添加一個(gè)dateFormat屬性:
@ModelAttribute("dataFormat")
public String localeFormat(Locale locale){
return LocalDateFormatter.getPattern(locale);
}
@ModelAttribute注解允許我們暴露一個(gè)屬性給Web頁面娃弓,完全類似于我們之前使用的mode.addAttribute()方法典格。
然后,我們可以在頁面上使用這個(gè)信息了台丛,只需要在日期輸入域中添加一個(gè)占位符(th:placeholder)即可:
<div class="row">
<div class="input-field col s6">
<input id="birthDate" type="text" th:field="${profileForm.birthDate}" th:placeholder="${dateFormat}"/>
<label for="birthDate">Birth Date</label>
</div>
</div>
現(xiàn)在再進(jìn)入頁面耍缴,我們就可以得到日期格式的提示信息了,并且此提示信息是根據(jù)我們自定義的Formatter中設(shè)置的地域日期格式和用戶所處地域決定挽霉。