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);
}
- 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
- 点赞
- 收藏
- 关注作者
评论(0)