【Spring MVC】Spring Boot框架开发Web项目
本系列文章主要索引如下:
【Spring MVC】Spring Boot 框架开发Web项目之一 前期准备
【Spring MVC】Spring Boot框架开发Web项目之二 Hello Spring Boot
【Spring MVC】Spring Boot框架开发Web项目之三 第一个页面
【Spring MVC】Spring Boot框架开发Web项目之四 将数据传递给视图
【Spring MVC】Spring Boot框架开发Web项目之五 使用Webjars实现质感设计
【Spring MVC】Spring Boot框架开发Web项目之六 表单数据提交
【Spring MVC】Spring Boot框架开发Web项目之七 日期的使用和输出日志
【Spring MVC】Spring Boot框架开发Web项目之八 表单校验
【Spring MVC】Spring Boot 框架开发Web项目之九 Spring Boot项目的打包和部署
【Spring MVC】Spring Boot 框架开发Web项目之十 整合MongoDB
Java8之前,我们一般都是使用的java.util.Data API来定义日期和时间,而Java8为我们提供了一个新的Java data-time API(JSR 310)。这个新的API比老的API要好的多,因为它对人类的日期进行了细致的区分,并使用了流畅的API和不可变的数据结构。
在本实例中,我们将使用新API中的LocalDate类,LocalDate类就是一个简单的日期,没有与其向关联的时间。这与老API中的LocalTime是有区别的,后者代表了一天中的某个时间,而LocalDateTime能包含日期和时间两部分信息,或者是ZonedDateTime,它还包含了一个时区。
了解 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字段的类型修改为LocalDate
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、启动项目,访问http://localhost:8081/profile,录入表单数据,并提交,此时如果我们使用一个日期值(如2017/08/01),它其实不能运行,会提示一个400错误
3、我们需要调试应用来了解发生了什么错误,我们可以通过输出日志,来定位问题。我们只需要在application.properties中添加如下这行代码:
logging.level.org.springframework.web=DEBUG
添加上述配置之后,我们就可以在控制台中看到Spring Web所产生的调试信息。如果想要将日志输出到文件中,则只需要指定日志文件路径即可:
logging.file=D:/IDEA/log/log.log
4、此时我们再次提交表单,再日志中会看到如下的错误:
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]]
此时我们需要一个Formatter,来对我们的日期进行格式化。
在Spring 中,Formatter类能够用来print和parse对象。它可以将一个String转码为值,也可而已将一个值输出为String。
5、在dto包的同级新建一个date包,然后创建一个简单的Formatter,命名为LocalDateFormatter,实现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());
}
}
这个类能够根据用户所在地域来解析日期。
6、在date包的同级新建config包,并创建名为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());
}
}
这个类扩展了WebMvcConfigurerAdapter,这是对Spring MVC进行自定义配置的一个很便利的类,它提供了很多的扩展点,我们可以重写如addFormatters()这样的方法来访问这些扩展点。
@Configuration注解:标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)。
7、此时我们再提交表单的话,就不会产生错误了,除非我们不按照正确的格式来进行输入。
8、但是现在我们并不知道需要以什么样的格式来输入日期,我们可以在表单上添加这个信息。
在ProfileController中,添加一个dateFormat属性:
@ModelAttribute("dataFormat")
public String localeFormat(Locale locale){
return LocalDateFormatter.getPattern(locale);
}
@ModelAttribute注解允许我们暴露一个属性给Web页面,完全类似于我们之前使用的mode.addAttribute()方法。
然后,我们可以在页面上使用这个信息了,只需要在日期输入域中添加一个占位符(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>
现在再进入页面,我们就可以得到日期格式的提示信息了,并且此提示信息是根据我们自定义的Formatter中设置的地域日期格式和用户所处地域决定。