《Spring MVC學習指南(第2版)》——2.5 校驗器
本節書摘來自異步社區《Spring MVC學習指南(第2版)》一書中的第2章,第2.5節,作者:【美】Paul Deck著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.5 校驗器
在Web應用執行action時,很重要的一個步驟就是進行輸入校驗。校驗的內容可以是簡單的,如檢查一個輸入是否為空,也可以是複雜的,如校驗信用卡號。實際上,因為校驗工作如此重要,Java社區專門發布了JSR 303 Bean Validation以及JSR 349 Bean Validation 1.1版本,將Java世界的輸入檢驗進行標準化。現代的MVC框架通常同時支持編程式和聲明式兩種校驗方法。在編程式中,需要通過編碼進行用戶輸入校驗,而在聲明式中,則需要提供包含校驗規則的XML文檔或者屬性文件。
注意
即使您可以使用HTML5或JavaScript執行客戶端輸入驗證,也不要依賴它,因為精明的用戶可以輕鬆地繞過它。始終執行服務器端輸入驗證!
本節的新應用(appdesign3)擴展自appdesign1,但多了一個ProductValidator類(見清單2.8)。
清單2.8 ProductValidator類
package appdesign3.validator;
import java.util.ArrayList;
import java.util.List;
import appdesign3.form.ProductForm;
public class ProductValidator {
public List<String> validate(ProductForm productForm) {
List<String> errors = new ArrayList< >();
String name = productForm.getName();
if (name == null || name.trim().isEmpty()) {
errors.add("Product must have a name");
}
String price = productForm.getPrice();
if (price == null || price.trim().isEmpty()) {
errors.add("Product must have a price");
} else {
try {
Float.parseFloat(price);
} catch (NumberFormatException e) {
errors.add("Invalid price value");
}
}
return errors;
}
}
注意
ProductValidator類中有一個操作ProductForm對象的validate方法,確保產品的名字非空,其價格是一個合理的數字。validate方法返回一個包含錯誤信息的字符串列表,若返回一個空列表,則表示輸入合法。
現在需要讓控製器使用這個校驗器了,清單2.9展示了一個更新後的ControllerServlet,注意黑體部分。
清單2.9 新版的ControllerServlet類
package appdesign3.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import appdesign3.action.SaveProductAction;
import appdesign3.form.ProductForm;
import appdesign3.model.Product;
import appdesign3.validator.ProductValidator;
import java.math.BigDecimal;
@WebServlet(name = "ControllerServlet", urlPatterns = {
"/input-product", "/save-product"})
public class ControllerServlet extends HttpServlet {
private static final long serialVersionUID = 98279L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
@Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
private void process(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String uri = request.getRequestURI();
/*
* uri is in this form: /contextName/resourceName,
* for example: /appdesign1/input-product.
* However, in the case of a default context, the
* context name is empty, and uri has this form
* /resourceName, e.g.: /input-product
*/
int lastIndex = uri.lastIndexOf("/");
String action = uri.substring(lastIndex + 1);
String dispatchUrl = null;
if ("input-product".eauals(action)) {
// no action class, Hrele is nathing to be done
dispatchUrl = "/jsp/ProductForm.jsp";
} else if ("save-product"-eaoals(action)) {
// instantiatle action class
ProductForm productForm = new ProductForm();
// populate action properties
productForm.setName(
request.getParameter("name"));
productForm.setDescription(
request.getParameter("description"));
productForm.setPrice(request.getParameter("price"));
// validate ProductForm
ProductValidator productValidator = new
ProductValidator();
List< String> errors =
productValidator.validate(productForm);
if(errors.isEmpty()){
// create product from productForm
Product product = new Product();
product.setName(productForm.getName());
product.setDescription(
productForm.getDescription());
product.setPrice(new BigDecimal (productForm.getPrice()));
// no validation error execute action method
SaveProductAction saveProductAction = new
SaveProductAction();
saveProductAction.save(product);
// store model in a scope variable for the view
request.setAttribute("product", product);
dispatchUrl = "/jsp/ProductDetails.jsp";
} else {
request.setAttribute("errors", errors);
request.setAttribute("form", productForm);
dispatchUrl = "/jsp/ProductForm.jsp";
}
}
// forward to a new
if (dispatchUrl != null) {
RequestDispatcher rd =
request.getRequestDispatcher(dispatchUrl);
rd.forward(request, response);
}
}
}
新版的ControllerServlet類添加了初始化ProductValidator類並調用其validate方法的代碼。
// validate ProductForm
ProductValidator productValidator = new
ProductValidator();
List<String> errors =
productValidator.validate(productForm);
validate方法接受一個ProductForm參數,它封裝了輸入到HTML表單的產品信息。如果不用ProductForm,則應將ServletRequest傳遞給驗證器。
如果驗證成功,validate方法返回一個空列表,在這種情況下,將創建一個產品並傳遞給SaveProductAction,然後,控製器將Product存儲在ServletContext中,並轉發到ProductDetails.jsp頁麵,顯示產品的詳細信息。如果驗證失敗,控製器將錯誤列表和ProductForm存儲在ServletContext中,並返回到ProductForm.jsp。
if (errors.isEmpty()) {
// create Product from ProductForm
Product product = new Product();
product.setName(productForm.getName());
product.setDescription(
productForm.getDescription());
product.setPrice(new BigDecimal(productForm.getPrice()));
// no validation error, execute action method
SaveProductAction saveProductAction = new
SaveProductAction();
saveProductAction.save(product);
// store action in a scope variable for the view
request.setAttribute("product", product);
dispatchur1="/jsp/ProductDetails.jsp";
} else {
request.setAttribute("errors", errors);
request.setAttribute("form", productForm);
dispatchur1="/jsp/ProductForm.jsp";
}
現在,需要修改appdesign3應用的ProductForm.jsp頁麵(見清單2.10),使其可以顯示錯誤信息以及錯誤的輸入。
清單2.10 ProductForm.jsp頁麵
< !DOCTYPE html>
< html>
< head>
< title>Add Product Form< /title>
< style type="text/css">@import url(css/main.css);< /style>
< /head>
< body>
< form method="post" action="save-product">
< h1>Add Product
< span>Please use this form to enter product details< /span>
< /h1>
${empty requestScope.errors? "" : "< p style='color:red'>"
+= "Error(s)!"
+= "< ul>"}
< !--${requestScope.errors.stream().map(
x -> "-->< li>"+=x+="< /li>< !--").toList()}-->
${empty requestScope.errors? "" : "< /ul>< /p>"}
< label>
< span>Product Name :< /span>
< input type="text" name="name"
placeholder="The complete product name"
value="${form.name}"/>
< /label>
< label>
< span>Description :< /span>
< input type="text" name="description"
placeholder="Product description"
value="${form.description}"/>
< /label>
< label>
< span>Price :< /span>
< input name="price" type="number" step="any"
placeholder="Product price in #.## format"
value="${form.price}"/>
< /label>
< label>
< span> < /span>
< input type="submit"/>
< /label>
< /form>
< /body>
< /html>
現在訪問input-product,測試appdesign3應用。
https://localhost:8080/appdesgin3/input-product
若產品表單提交了無效數據,頁麵將顯示相應的錯誤信息。圖2.6顯示了包含兩條錯誤信息的ProductForm頁麵。
圖2.6 包含兩條錯誤信息的ProductForm頁麵
最後更新:2017-05-27 13:31:28