javascript
在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息
在許多新功能中, Bean Validation 1.1引入了使用統一表達式語言(EL)表達式的錯誤消息插值。 這允許基于條件邏輯來定義錯誤消息,還可以啟用高級格式化選項 。 添加到Spring MVC應用程序后,您可以非常簡單地顯示更友好的錯誤消息。
在本文的第一部分中,我將簡短描述使用EL表達式的消息插值,在第二部分中,我們將使用Spring Boot和Thymeleaf構建一個運行在Tomcat 8上的簡單Web應用程序。
消息中的EL表達式–示例
為了可視化用EL表達式更好地進行消息內插的一些可能性,我將使用以下類:
public class Bid {private String bidder;private Date expiresAt;private BigDecimal price; }示例1:當前驗證的值
驗證引擎將當前已驗證的值在EL上下文中提供為validatedValue :
@Size(min = 5, message = "\"${validatedValue}\" is too short.") private String bidder;對于等于“約翰”的競標者,錯誤消息將是:
“約翰”太短了。
示例2:條件邏輯
錯誤消息中可能帶有EL表達式的條件邏輯。 在以下示例中,如果經過驗證的競標者的長度短于2,我們將顯示不同的消息:
@Size(min = 5, message = "\"${validatedValue}\" is ${validatedValue.length() < 2 ? 'way' : ''} too short.") private String bidder;當投標人等于“ J”時,消息將是:
“ J”太短了。
當出價者等于“ John”時,消息將是:
“約翰”太短了。
示例3:格式化程序
驗證引擎使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;當到期日期等于2001-01-01時,消息將是:
值“ 2001-01-01”不在將來!
請注意,在此示例java.util.Date使用了java.util.Date 。 Hibernate Validator 5.1.1尚不支持對新的Date-Time類型的驗證。 它將在Hibernate Validator 5.2中引入。 請參見Hibernate Validator路線圖 。
創建Spring MVC應用程序
為了可視化如何將Bean Validation 1.1與Spring MVC一起使用,我們將使用Spring Boot構建一個簡單的Web應用程序。
首先,我們需要創建一個Spring Boot項目。 我們可以從Spring Initializr開始,并生成具有以下特征的項目:
- 組 :pl.codeleak.beanvalidation11-demo
- 工件 :beanvalidation11-demo
- 名稱 :Bean驗證1.1演示
- 軟件包名稱:pl.codeleak.demo
- 風格 :網,胸腺
- 類型 :Maven項目
- 包裝 :戰爭
- Java版本 :1.8
- 語言 :Java
單擊生成后,將下載文件。 生成的項目的結構如下:
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真的很方便! 生成項目后,可以將其導入到您喜歡的IDE中。
修改項目屬性
Bean驗證1.1由Hibernate Validator 5.x實現 。 我們將使用Hibernate Validator 5.1.1,因此我們需要將其添加到我們的項目中,并且在Spring Boot 1.1.1中,RELEASE使用Hibernate Validator 5.0.3時,我們將需要修改POM屬性之一:
<properties><hibernate-validator.version>5.1.1.Final</hibernate-validator.version> </properties>在該項目中,我們將使用Tomcat8。但是為什么不能使用Tomcat 7? Hibernate Validator 5.x需要Expression EL API 2.2.4及其實現。 并且該實現在Tomcat 8中提供。要在Tomcat 8上運行Spring Boot應用程序,我們將需要添加另一個屬性:
<properties><tomcat.version>8.0.8</tomcat.version> </properties>創建出價:控制器
為了創建出價,我們需要一個控制器。 控制器有兩種方法:顯示表單和創建出價:
@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;} }創建出價:視圖
現在,我們將在Thymeleaf中創建一個簡單的頁面,其中包含我們的出價表單。 該頁面將為index.html ,并將轉到src/main/resources/templates 。
<form class="form-narrow form-horizontal" method="post" th:action="@{/}" th:object="${bid}">[...]</form>如果發生驗證錯誤,我們將顯示一條常規消息:
<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>每個表單字段都將標記為紅色,并顯示相應的消息:
<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>創建一些測試
在這個階段,我們可以運行該應用程序,但是我們將創建一些測試來檢查驗證是否按預期工作。 為此,我們將創建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();} }測試存根已準備就緒。 現在該進行一些測試了。 首先,通過驗證模型是否包含出價對象以及視圖名稱是否等于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")); }在下一個測試中,我們將驗證,如果輸入了正確的數據,則表格中不包含錯誤消息(快樂流程情況)。 請注意,使用Thymeleaf作為視圖引擎,我們可以簡單地驗證生成的視圖。
@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.")))); }在接下來的幾個測試中,我們將檢查某些對象的有效性。 測試的名稱應具有足夠的描述性,因此無需進一步說明。 看一下代碼:
@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")))); }很簡單。
運行應用程序
由于應用程序的包裝類型為war ,因此您可能需要下載Tomcat 8.0.8服務器,使用mvn clean package創建一個軟件包,然后將應用程序部署到服務器。
要使用嵌入式Tomcat運行程序,您需要將包裝類型更改為jar ,并在pom.xml中將spring-boot-starter-tomcat依賴范圍設置為default( compile ):
[...]<packaging>jar</packaging>[...]<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId> </dependency>[...]現在,您可以使用mvn clean package創建一個包,并使用java -jar命令運行生成的jar文件。 當然,您也可以通過運行pl.codeleak.demo.Application類從IDE中運行項目。
摘要
如果您有興趣查看所提供示例的完整源代碼,請檢查我的GitHub存儲庫: spring-mvc-beanvalidation11-demo 。
閱讀本文后,您應該知道:
- 如何在帶有Tomcat 8的Spring MVC應用程序中使用Bean驗證1.1
- 如何使用EL表達式改善錯誤消息
- 如何使用Spring Boot從頭開始構建應用程序
- 如何使用Spring Test測試驗證
您可能對我以前的有關使用Thymeleaf和Maven引導Spring MVC應用程序的帖子感興趣: HOW-TO:使用Maven引導Spring MVC 和Thymeleaf 。
您可能還想看看我過去寫的一些其他有關驗證的文章:
- Spring MVC中的驗證組
- Spring中的方法級別驗證
- 在Spring MVC中請求正文驗證
翻譯自: https://www.javacodegeeks.com/2014/06/better-error-messages-with-bean-validation-1-1-in-spring-mvc-application.html
總結
以上是生活随笔為你收集整理的在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么让笔记本强制重启电脑(如何将笔记本电
- 下一篇: 怎么才能投诉方正宽带