《Spring MVC学习指南(第2版)》——2.5 校验器

    xiaoxiao2024-04-09  120

    本节书摘来自异步社区《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 id="name" type="text" name="name"       placeholder="The complete product name"       value="${form.name}"/>   < /label>   < label>     < span>Description :< /span>     < input id="description" type="text" name="description"       placeholder="Product description"       value="${form.description}"/>   < /label>   < label>     < span>Price :< /span>     < input id="price" 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应用。

    http://localhost:8080/appdesgin3/input-product若产品表单提交了无效数据,页面将显示相应的错误信息。图2.6显示了包含两条错误信息的ProductForm页面。

    图2.6 包含两条错误信息的ProductForm页面

    相关资源:Spring MVC学习指南 高清完整.pdf版下载
    最新回复(0)