javascript
在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息
在許多新功能中, Bean Validation 1.1引入了使用統(tǒng)一表達(dá)式語言(EL)表達(dá)式的錯誤消息插值。 這允許基于條件邏輯來定義錯誤消息,還可以啟用高級格式化選項(xiàng) 。 添加到Spring MVC應(yīng)用程序后,您可以非常簡單地顯示更友好的錯誤消息。
在本文的第一部分中,我將簡短描述使用EL表達(dá)式的消息插值,在第二部分中,我們將使用Spring Boot和Thymeleaf構(gòu)建一個運(yùn)行在Tomcat 8上的簡單Web應(yīng)用程序。
消息中的EL表達(dá)式–示例
為了可視化用EL表達(dá)式更好地進(jìn)行消息內(nèi)插的一些可能性,我將使用以下類:
public class Bid {private String bidder;private Date expiresAt;private BigDecimal price; }示例1:當(dāng)前驗(yàn)證的值
驗(yàn)證引擎將當(dāng)前已驗(yàn)證的值在EL上下文中提供為validatedValue :
@Size(min = 5, message = "\"${validatedValue}\" is too short.") private String bidder;對于等于“約翰”的競標(biāo)者,錯誤消息將是:
“約翰”太短了。
示例2:條件邏輯
錯誤消息中可能帶有EL表達(dá)式的條件邏輯。 在以下示例中,如果經(jīng)過驗(yàn)證的競標(biāo)者的長度短于2,我們將顯示不同的消息:
@Size(min = 5, message = "\"${validatedValue}\" is ${validatedValue.length() < 2 ? 'way' : ''} too short.") private String bidder;當(dāng)投標(biāo)人等于“ J”時,消息將是:
“ J”太短了。
當(dāng)出價者等于“ John”時,消息將是:
“約翰”太短了。
示例3:格式化程序
驗(yàn)證引擎使formatter對象在EL上下文中可用。 formatter行為為java.util.Formatter.format(String format, Object... args) 。 在下面的示例中,日期格式為ISO日期:
@Future(message = "The value \"${formatter.format('%1$tY-%1$tm-%1$td', validatedValue)}\" is not in future!") private Date expiresAt;當(dāng)?shù)狡谌掌诘扔?001-01-01時,消息將是:
值“ 2001-01-01”不在將來!
請注意,在此示例java.util.Date使用了java.util.Date 。 Hibernate Validator 5.1.1尚不支持對新的Date-Time類型的驗(yàn)證。 它將在Hibernate Validator 5.2中引入。 請參見Hibernate Validator路線圖 。
創(chuàng)建Spring MVC應(yīng)用程序
為了可視化如何將Bean Validation 1.1與Spring MVC一起使用,我們將使用Spring Boot構(gòu)建一個簡單的Web應(yīng)用程序。
首先,我們需要創(chuàng)建一個Spring Boot項(xiàng)目。 我們可以從Spring Initializr開始,并生成具有以下特征的項(xiàng)目:
- 組 :pl.codeleak.beanvalidation11-demo
- 工件 :beanvalidation11-demo
- 名稱 :Bean驗(yàn)證1.1演示
- 軟件包名稱:pl.codeleak.demo
- 風(fēng)格 :網(wǎng),胸腺
- 類型 :Maven項(xiàng)目
- 包裝 :戰(zhàn)爭
- Java版本 :1.8
- 語言 :Java
單擊生成后,將下載文件。 生成的項(xiàng)目的結(jié)構(gòu)如下:
src ├───main │ ├───java │ │ └───pl │ │ └───codeleak │ │ └───demo │ └───resources │ ├───static │ └───templates └───test└───java└───pl└───codeleak└───demo截至2014年6月,生成的POM如下所示:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>pl.codeleak.beanvalidation11-demo</groupId><artifactId>beanvalidation11-demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><name>Bean Validation 1.1 Demo</name><description></description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.1.1.RELEASE</version><relativePath/></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><start-class>pl.codeleak.demo.Application</start-class><java.version>1.8</java.version></properties><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>太快了! Spring Initializr真的很方便! 生成項(xiàng)目后,可以將其導(dǎo)入到您喜歡的IDE中。
修改項(xiàng)目屬性
Bean驗(yàn)證1.1由Hibernate Validator 5.x實(shí)現(xiàn) 。 我們將使用Hibernate Validator 5.1.1,因此我們需要將其添加到我們的項(xiàng)目中,并且在Spring Boot 1.1.1中,RELEASE使用Hibernate Validator 5.0.3時,我們將需要修改POM屬性之一:
<properties><hibernate-validator.version>5.1.1.Final</hibernate-validator.version> </properties>在該項(xiàng)目中,我們將使用Tomcat8。但是為什么不能使用Tomcat 7? Hibernate Validator 5.x需要Expression EL API 2.2.4及其實(shí)現(xiàn)。 并且該實(shí)現(xiàn)在Tomcat 8中提供。要在Tomcat 8上運(yùn)行Spring Boot應(yīng)用程序,我們將需要添加另一個屬性:
<properties><tomcat.version>8.0.8</tomcat.version> </properties>創(chuàng)建出價:控制器
為了創(chuàng)建出價,我們需要一個控制器。 控制器有兩種方法:顯示表單和創(chuàng)建出價:
@Controller public class BidController {@RequestMapping(value = "/")public String index(Model model) {model.addAttribute("bid", new Bid("John", new Date(), BigDecimal.valueOf(5.00)));return "index";}@RequestMapping(value = "/", method = RequestMethod.POST)public String create(@ModelAttribute @Valid Bid bid, Errors errors) {if (errors.hasErrors()) {return "index";}// create a bid herereturn "redirect:/";} }最終的Bid類代碼如下。 請注意,郵件沒有在Bid類中直接指定。 我將它們移動到ValidationMessages捆綁文件( src/main/resources ValidationMessages.properties )。
public class Bid {@Size.List({@Size(min = 5, message = "{bid.bidder.min.message}"),@Size(max = 10, message = "{bid.bidder.max.message}")})private String bidder;@NotNull@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)@Future(message = "{bid.expiresAt.message}")private Date expiresAt;@NotNull@DecimalMin(value = "10.00", message = "{bid.price.message}")@NumberFormat(style = NumberFormat.Style.CURRENCY)private BigDecimal price;protected Bid() {}public Bid(String bidder, Date expiresAt, BigDecimal price) {this.bidder = bidder;this.expiresAt = expiresAt;this.price = price;}public String getBidder() {return bidder;}public Date getExpiresAt() {return expiresAt;}public BigDecimal getPrice() {return price;}public void setBidder(String bidder) {this.bidder = bidder;}public void setExpiresAt(Date expiresAt) {this.expiresAt = expiresAt;}public void setPrice(BigDecimal price) {this.price = price;} }創(chuàng)建出價:視圖
現(xiàn)在,我們將在Thymeleaf中創(chuàng)建一個簡單的頁面,其中包含我們的出價表單。 該頁面將為index.html ,并將轉(zhuǎn)到src/main/resources/templates 。
<form class="form-narrow form-horizontal" method="post" th:action="@{/}" th:object="${bid}">[...]</form>如果發(fā)生驗(yàn)證錯誤,我們將顯示一條常規(guī)消息:
<th:block th:if="${#fields.hasErrors('${bid.*}')}"><div class="alert alert-dismissable" th:classappend="'alert-danger'"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><span th:text="Form contains errors. Please try again.">Test</span></div> </th:block>每個表單字段都將標(biāo)記為紅色,并顯示相應(yīng)的消息:
<div class="form-group" th:classappend="${#fields.hasErrors('bidder')}? 'has-error'"><label for="bidder" class="col-lg-4 control-label">Bidder</label><div class="col-lg-8"><input type="text" class="form-control" id="bidder" th:field="*{bidder}" /><span class="help-block" th:if="${#fields.hasErrors('bidder')}" th:errors="*{bidder}">Incorrect</span></div> </div>創(chuàng)建一些測試
在這個階段,我們可以運(yùn)行該應(yīng)用程序,但是我們將創(chuàng)建一些測試來檢查驗(yàn)證是否按預(yù)期工作。 為此,我們將創(chuàng)建BidControllerTest :
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class BidControllerTest {@Autowiredprivate WebApplicationContext wac;private MockMvc mockMvc;@Beforepublic void setup() {this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();} }測試存根已準(zhǔn)備就緒。 現(xiàn)在該進(jìn)行一些測試了。 首先,通過驗(yàn)證模型是否包含出價對象以及視圖名稱是否等于index檢查表單是否正確“顯示”:
@Test public void displaysABidForm() throws Exception {this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(model().attribute("bid", any(Bid.class))).andExpect(view().name("index")); }在下一個測試中,我們將驗(yàn)證,如果輸入了正確的數(shù)據(jù),則表格中不包含錯誤消息(快樂流程情況)。 請注意,使用Thymeleaf作為視圖引擎,我們可以簡單地驗(yàn)證生成的視圖。
@Test public void postsAValidBid() throws Exception {this.mockMvc.perform(post("/").param("bidder", "John Smith").param("expiresAt", "2020-01-01").param("price", "11.88")).andExpect(content().string(not(containsString("Form contains errors. Please try again.")))); }在接下來的幾個測試中,我們將檢查某些對象的有效性。 測試的名稱應(yīng)具有足夠的描述性,因此無需進(jìn)一步說明。 看一下代碼:
@Test public void postsABidWithBidderTooShort() throws Exception {this.mockMvc.perform(post("/").param("bidder", "John")) // too short.andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString(""John" is too short. Should not be shorter than 5")))); }@Test public void postsABidWithBidderWayTooShort() throws Exception {this.mockMvc.perform(post("/").param("bidder", "J")) // way too short.andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString(""J" is way too short. Should not be shorter than 5")))); }@Test public void postsABidWithBidderTooLong() throws Exception {this.mockMvc.perform(post("/").param("bidder", "John S. Smith")) // too long.andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString(""John S. Smith" is too long. Should not be longer than 10")))); }@Test public void postsABidWithBidderWayTooLong() throws Exception {this.mockMvc.perform(post("/").param("bidder", "John The Saint Smith")).andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString(""John The Saint Smith" is way too long. Should not be longer than 10")))); }@Test public void postsABidWithExpiresAtInPast() throws Exception {this.mockMvc.perform(post("/").param("expiresAt", "2010-01-01")).andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString("Value "2010-01-01" is not in future!")))); }@Test public void postsABidWithPriceLowerThanFive() throws Exception {this.mockMvc.perform(post("/").param("price", "4.99")).andExpect(content().string(allOf(containsString("Form contains errors. Please try again."),containsString("Value "4.99" is incorrect. Must be greater than or equal to 10.00")))); }很簡單。
運(yùn)行應(yīng)用程序
由于應(yīng)用程序的包裝類型為war ,因此您可能需要下載Tomcat 8.0.8服務(wù)器,使用mvn clean package創(chuàng)建一個軟件包,然后將應(yīng)用程序部署到服務(wù)器。
要使用嵌入式Tomcat運(yùn)行程序,您需要將包裝類型更改為jar ,并在pom.xml中將spring-boot-starter-tomcat依賴范圍設(shè)置為default( compile ):
[...]<packaging>jar</packaging>[...]<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId> </dependency>[...]現(xiàn)在,您可以使用mvn clean package創(chuàng)建一個包,并使用java -jar命令運(yùn)行生成的jar文件。 當(dāng)然,您也可以通過運(yùn)行pl.codeleak.demo.Application類從IDE中運(yùn)行項(xiàng)目。
摘要
如果您有興趣查看所提供示例的完整源代碼,請檢查我的GitHub存儲庫: spring-mvc-beanvalidation11-demo 。
閱讀本文后,您應(yīng)該知道:
- 如何在帶有Tomcat 8的Spring MVC應(yīng)用程序中使用Bean驗(yàn)證1.1
- 如何使用EL表達(dá)式改善錯誤消息
- 如何使用Spring Boot從頭開始構(gòu)建應(yīng)用程序
- 如何使用Spring Test測試驗(yàn)證
您可能對我以前的有關(guān)使用Thymeleaf和Maven引導(dǎo)Spring MVC應(yīng)用程序的帖子感興趣: HOW-TO:使用Maven引導(dǎo)Spring MVC 和Thymeleaf 。
您可能還想看看我過去寫的一些其他有關(guān)驗(yàn)證的文章:
- Spring MVC中的驗(yàn)證組
- Spring中的方法級別驗(yàn)證
- 在Spring MVC中請求正文驗(yàn)證
翻譯自: https://www.javacodegeeks.com/2014/06/better-error-messages-with-bean-validation-1-1-in-spring-mvc-application.html
總結(jié)
以上是生活随笔為你收集整理的在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么让笔记本强制重启电脑(如何将笔记本电
- 下一篇: Spring4:没有默认构造函数的基于C