Spring MVC-02循序渐进之解耦控制器和校验器

举报
小工匠 发表于 2021/09/11 00:03:52 2021/09/11
【摘要】 概述项目结构示例校验器源码 概述 在上篇博文 Spring MVC-01循序渐进之Model 2和MVC中,我们可以看到业务逻辑代码都写在了Servlet控制器中,这个Se...

概述

在上篇博文 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);

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

InputProductController

package com.artisan.learnmvc.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InputProductController implements Controller {

    @Override
    public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("find page");
        return "/WEB-INF/jsp/ProductForm.jsp";
    }

}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

该类直接返回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 {

    @Override
    public String handleRequest(HttpServletRequest request,
                                HttpServletResponse response) {
        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(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 view
            request.setAttribute("product", product);
            return "/WEB-INF/jsp/ProductDetails.jsp";
        } else {
            // store errors and form in a scope variable for the view
            request.setAttribute("errors", errors);
            request.setAttribute("form", productForm);
            return "/WEB-INF/jsp/ProductForm.jsp";
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

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;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        process(req, resp);
    }

    @Override
    protected 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 action
        if (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);
            }

    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

校验器

我们这里仅仅说前台校验,不涉及后台校验,这里只是简单的演示下

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;
    }



}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

ProductValidator类中有一个操作ProductForm对象的validate方法,确保产品的名字非空,价格是一个合理的数字。

validate方法返回一个包含错误信息的字符串列表,若返回一个空列表,表示输入合法。

应用中需要用到产品校验的地方是保存产品时,即SaveProductController类。现在为SaveProductController类引入ProductValidator类,调用validate方法

   // validate ProductForm
        ProductValidator productValidator = new ProductValidator();
        List<String> errors = productValidator.validate(productForm);
  
 
  • 1
  • 2
  • 3

接下来我们修改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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

运行项目,测试

这里写图片描述


源码

代码已提交到github

https://github.com/yangshangwei/SpringMvcTutorialArtisan

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/78981226

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。