javascript
Spring MVC-02循序渐进之解耦控制器和校验器
- 概述
- 項目結構
- 示例
- 校驗器
- 源碼
概述
在上篇博文 Spring MVC-01循序漸進之Model 2和MVC中,我們可以看到業務邏輯代碼都寫在了Servlet控制器中,這個Servlet隨著應用復雜度的增加而不斷增加,變得難以維護,為了避免該問題,我們應該將業務邏輯代碼提取到獨立的被稱為controller的類中
項目結構
我們在controller包下,增加了一個自定義的Controller接口和兩個controller實現類用于執行對應的action ,該接口只有handleRequest方法。
實現類通過該方法訪問到當前請求的HttpServletRequest和HttpServletResponse
示例
Controller接口
package com.artisan.learnmvc.controller;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public interface Controller {String handleRequest(HttpServletRequest request ,HttpServletResponse response);}InputProductController
package com.artisan.learnmvc.controller;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class InputProductController implements Controller {@Overridepublic String handleRequest(HttpServletRequest request, HttpServletResponse response) {System.out.println("find page");return "/WEB-INF/jsp/ProductForm.jsp";}}該類直接返回ProductForm.jsp的路徑。
SaveProductController
package com.artisan.learnmvc.controller;import java.util.List;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.artisan.learnmvc.form.ProductForm; import com.artisan.learnmvc.model.Product; import com.artisan.learnmvc.validator.ProductValidator;public class SaveProductController implements Controller {@Overridepublic String handleRequest(HttpServletRequest request,HttpServletResponse response) {ProductForm productForm = new ProductForm();// populate action propertiesproductForm.setName(request.getParameter("name"));productForm.setDescription(request.getParameter("description"));productForm.setPrice(request.getParameter("price"));// validate ProductFormProductValidator productValidator = new ProductValidator();List<String> errors = productValidator.validate(productForm);if (errors.isEmpty()) {// create Product from ProductFormProduct product = new Product();product.setName(productForm.getName());product.setDescription(productForm.getDescription());product.setPrice(Float.parseFloat(productForm.getPrice()));// no validation error, execute action method// insert code to save product to the database// store product in a scope variable for the viewrequest.setAttribute("product", product);return "/WEB-INF/jsp/ProductDetails.jsp";} else {// store errors and form in a scope variable for the viewrequest.setAttribute("errors", errors);request.setAttribute("form", productForm);return "/WEB-INF/jsp/ProductForm.jsp";}} }SaveProductController類則會讀取請求參數構造一個ProductForm對象,之后用ProductForm對象來構造一個Product對象,并返回SaveProductController.jsp的路徑。
將業務邏輯遷移到controller類中的好處很明顯:Controller Servlet變得更加的專注。作用更加像一個dispatcher,而非一個controller,因此我們將其改名為DispatcherServlet.
DispatcherServlet類檢查每個URI,創建對應的controller,并調用其handleRequest方法
package com.artisan.learnmvc.servlet;import java.io.IOException;import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.artisan.learnmvc.controller.InputProductController; import com.artisan.learnmvc.controller.SaveProductController;public class DispatcherServlet extends HttpServlet {private static final long serialVersionUID = -5454977373262337215L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {process(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {process(req, resp);}private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String uri = request.getRequestURI();/** uri is in this form: /contextName/resourceName, for example:* /chapter02b/product_input.action However, in the event of a default* context, the context name is empty, and uri has this form* /resourceName, e.g.: /product_input*/int lastIndex = uri.lastIndexOf("/");String action = uri.substring(lastIndex + 1);System.out.println("action:" + action); String dispatchUrl = null;// execute an actionif (action.equals("product_input.action")) {InputProductController inputProductController = new InputProductController();dispatchUrl = inputProductController.handleRequest(request, response);} else if (action.equals("product_save.action")) {SaveProductController saveProductController = new SaveProductController();dispatchUrl = saveProductController.handleRequest(request, response);}System.out.println("dispatchUrl:" + dispatchUrl);// 頁面跳轉if (dispatchUrl != null) {RequestDispatcher rd =request.getRequestDispatcher(dispatchUrl);rd.forward(request, response);}} }校驗器
我們這里僅僅說前臺校驗,不涉及后臺校驗,這里只是簡單的演示下
package com.artisan.learnmvc.validator;import java.util.ArrayList; import java.util.List;import com.artisan.learnmvc.form.ProductForm;public class ProductValidator {public List<String> validate(ProductForm form){List<String> errors = new ArrayList<String>();String name = form.getName();if(name == null || name.trim().isEmpty()){System.out.println("name must input");errors.add("Product must have a name");}String price = form.getPrice();if (price == null || price.trim().isEmpty()) {System.out.println("price must input");errors.add("Product must have a price");}else {try {Float.parseFloat(price);} catch (NumberFormatException e) {System.out.println("price must be right format");errors.add("Invalid price");e.printStackTrace();}}return errors;}}ProductValidator類中有一個操作ProductForm對象的validate方法,確保產品的名字非空,價格是一個合理的數字。
validate方法返回一個包含錯誤信息的字符串列表,若返回一個空列表,表示輸入合法。
應用中需要用到產品校驗的地方是保存產品時,即SaveProductController類。現在為SaveProductController類引入ProductValidator類,調用validate方法
// validate ProductFormProductValidator productValidator = new ProductValidator();List<String> errors = productValidator.validate(productForm);接下來我們修改ProductForm.jsp頁面,使其可以顯示錯誤信息
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE HTML> <html> <head> <title>Add Product Form</title> <style type="text/css">@import url(css/main.css);</style> </head> <body><div id="global"> <c:if test="${requestScope.errors != null}"> <p id="errors">Error(s)!<ul><c:forEach var="error" items="${requestScope.errors}"><li>${error}</li></c:forEach></ul></p> </c:if> <form action="product_save.action" method="post"><fieldset><legend>Add a product</legend><p><label for="name">Product Name: </label><input type="text" id="name" name="name" tabindex="1"></p><p><label for="description">Description: </label><input type="text" id="description" name="description" tabindex="2"></p><p><label for="price">Price: </label><input type="text" id="price" name="price" tabindex="3"></p><p id="buttons"><input id="reset" type="reset" tabindex="4"><input id="submit" type="submit" tabindex="5" value="Add Product"></p></fieldset> </form> </div> </body> </html>運行項目,測試
源碼
代碼已提交到github
https://github.com/yangshangwei/SpringMvcTutorialArtisan
總結
以上是生活随笔為你收集整理的Spring MVC-02循序渐进之解耦控制器和校验器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring MVC-01循序渐进之Mo
- 下一篇: Spring MVC-03循序渐进之Sp