[TOC]
# 步骤1:一个路径对应一个Servlet的弊端
通过观察
```
http://192.168.10.165:8080/tmall_ssm/admin_category_list
```
可以发现,分类管理需要:增加,删除,编辑,修改,查询5个服务端功能。
那么按照传统的Servlet方式(`web.xml`配置或者使用注解`@WebServlet`),一个路径对应一个Servlet的思路,就需要设计5个Servlet类。
比如:
```
AddCategoryServlet
DeleteCategoryServlet
EditCategoryServlet
UpdateCategoryServlet
ListCategoryServlet
```
而后台需要做分类,产品,属性,产品图片,用户,订单这么6种管理,那么就一共需要30个Servlet,也就是`一个请求对应一个Servlet`,控制器就显得比较臃肿,写起来也比较麻烦。
# 步骤2: 对设计进行改进
但是观察已经实现了分类管理的`可运行的项目`里的代码,却发现Servlet只有一个即CategoryServlet。
如图是对于最后完工了的项目的servlet包里类的截图,可以发现,每种实体类,对应了一个Servlet,而不是对应了5个,这样首先从Servlet数量上来讲,就大大的减少了。
![](https://box.kancloud.cn/e636147285dcd26471fcf9686c3b5af1_216x141.png)
# 步骤3: 原理流程图
那么是如何做到一个CategoryServlet类,就能完成本来需要5个Servlet类才能完成的功能的呢?
让我们借助流程图来分析,为什么访问`admin_category_list`的时候,CategoryServlet的list()方法会被调用。
1. 假设访问路径是 `http://127.0.0.1:8080/tmall_j2ee/admin_category_list`
2. 过滤器BackServletFilter进行拦截,判断访问的地址是否以`admin_`开头
3. 如果是,那么做如下操作
3.1 取出两个下划线之间的值 category
3.2 取出最后一个下划线之后的值 list
3.3 然后根据这个值,服务端跳转到categoryServlet,并且把list这个值传递过去
4. categoryServlet 继承了BaseBackServlet,其service方法会被调用。 在service中,借助反射技术,根据传递过来的值 list,调用对应categoryServlet 中的方法list() 。
5. 这样就实现了当访问的路径是 `admin_category_list`的时候,就会调用`categoryServlet.list()`方法这样一个效果。
> 换句话说:
如果访问的路径是admin\_category\_add,就会调用categoryServlet.add()方法
如果访问的路径是admin\_category\_delete,就会调用categoryServlet.delete()方法
如果访问的路径是admin\_category\_edit,就会调用categoryServlet.edit()方法
如果访问的路径是admin\_category\_update,就会调用categoryServlet.update()方法
如此这般,一个categoryServlet类,就完成了本来需要5个Servlet类才能完成的功能。
![](https://box.kancloud.cn/791385aa832c22ed4d1aaceffd117ad6_761x639.png)
# 步骤4:代码讲解 - BackServletFilter
那么BackServletFilter类到底是如何工作的呢? 接下来我们此类进行代码讲解。
1. 首先在web.xml配置文件中,让所有的请求都会经过BackServletFilter
```
<filter-mapping>
<filter-name>BackServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
```
2\. 还是假设访问的路径是:
http://127.0.0.1:8080/tmall_j2ee/admin\_category\_list
3\. 在BackServletFilter 中通过request.getRequestURI()取出访问的uri: /tmall_j2ee/admin\_category\_list
4\. 然后截掉/tmall_j2ee,得到路径/admin\_category\_list
5\. 判断其是否以/admin开头
6\. 如果是,那么就取出两个\_之间的字符串,category,并且拼接成/CategoryServlet,通过服务端跳转到/CategoryServlet
7\. 在跳转之前,还取出了list字符串,然后通过request.setAttribute的方式,借助服务端跳转,传递到categoryServlet里去。
```
package com.dodoke.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
/**
* Servlet Filter implementation class BackServletFilter
*/
public class BackServletFilter implements Filter {
/**
* Default constructor.
*/
public BackServletFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String contextPath = request.getContextPath();
String uri = request.getRequestURI();
uri = StringUtils.remove(uri, contextPath);
if (uri.startsWith("/admin_")) {
// 从admin_category_list截取出category
String temp = StringUtils.substringBetween(uri, "_", "_");
// category首字母大写与Servlet拼接
String servletPath = StringUtils.capitalize(temp) + "Servlet";
String method = StringUtils.substringAfterLast(uri, "_");
request.setAttribute("method", method);
req.getRequestDispatcher("/" + servletPath).forward(request, response);
return;
}
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
```
# 步骤5:代码讲解 - CategoryServlet和BaseBackServlet
接着流程就到了categoryServlet这里。
服务端跳转/categoryServlet就到了CategoryServlet这个类里
1. 首先CategoryServlet继承了BaseBackServlet,而BaseBackServlet又继承了HttpServlet。
2. 服务端跳转过来之后,会访问CategoryServlet的doGet()或者doPost()方法
3. 在访问doGet()或者doPost()之前,会访问service()方法
4. BaseBackServlet中重写了service() 方法,所以流程就进入到了service()中
5. 在service()方法
根据**反射**访问对应的方法,然后根据对应方法的返回值,进行服务端跳转、客户端跳转、或者直接输出字符串。
5.1 取到从BackServletFilter中request.setAttribute()传递过来的值 list
5.2 根据这个值list,借助**反射机制**调用CategoryServlet类中的list()方法
这样就达到了CategoryServlet.list()方法被调用的效果
BaseBackServlet
```
package com.dodoke.controller;
import java.lang.reflect.Method;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dodoke.dao.impl.CategoryDaoImpl;
import com.dodoke.dao.inter.CategoryDao;
import com.dodoke.util.Page;
/**
* Servlet implementation class BaseBackServlet
*/
@WebServlet("/BaseBackServlet")
public abstract class BaseBackServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public abstract String add(HttpServletRequest request, HttpServletResponse response);
public abstract String delete(HttpServletRequest request, HttpServletResponse response);
public abstract String edit(HttpServletRequest request, HttpServletResponse response);
public abstract String update(HttpServletRequest request, HttpServletResponse response);
public abstract String list(HttpServletRequest request, HttpServletResponse response);
protected CategoryDao categoryDao = new CategoryDaoImpl();
public void service(HttpServletRequest request, HttpServletResponse response) {
try {
/* 借助反射,调用对应的方法 */
String method = (String) request.getAttribute("method");
Method m = this.getClass().getMethod(method, javax.servlet.http.HttpServletRequest.class,
javax.servlet.http.HttpServletResponse.class, Page.class);
String redirect = m.invoke(this, request, response).toString();
/* 根据方法的返回值,进行相应的客户端跳转,服务端跳转,或者仅仅是输出字符串 */
System.out.println(redirect);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
```
CategoryServlet
```
package com.dodoke.controller;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class CategoryServlet
*/
@WebServlet("/CategoryServlet")
public class CategoryServlet extends BaseBackServlet {
@Override
public String add(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "add";
}
@Override
public String delete(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "delete";
}
@Override
public String edit(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "edit";
}
@Override
public String update(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "update";
}
@Override
public String list(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "list";
}
}
```
# 步骤6: 一个Servlet类就能满足CRUD一系列业务要求
通过这样一种模式,一个Servlet类就能满足CRUD一系列业务要求
如果访问的路径是admin\_category\_list,就会调用categoryServlet.list()方法
如果访问的路径是admin\_category\_add,就会调用categoryServlet.add()方法
如果访问的路径是admin\_category\_delete,就会调用categoryServlet.delete()方法
如果访问的路径是admin\_category\_edit,就会调用categoryServlet.edit()方法
如果访问的路径是admin\_category\_update,就会调用categoryServlet.update()方法
![](https://box.kancloud.cn/56edd50d3577fdcb98af642836a9cdda_434x147.png)
- 项目简介
- 功能一览
- 前台
- 后台
- 开发流程
- 需求分析-展示
- 首页
- 产品页
- 分类页
- 搜索结果页
- 购物车查看页
- 结算页
- 确认支付页
- 支付成功页
- 我的订单页
- 确认收货页
- 评价页
- 页头信息展示
- 需求分析-交互
- 分类页排序
- 立即购买
- 加入购物车
- 调整订单项数量
- 删除订单项
- 生成订单
- 订单页功能
- 确认付款
- 确认收货
- 提交评价信息
- 登录
- 注册
- 退出
- 搜索
- 前台需求列表
- 需求分析后台
- 分类管理
- 属性管理
- 产品管理
- 产品图片管理
- 产品属性设置
- 用户管理
- 订单管理
- 后台需求列表
- 表结构设计
- 数据建模
- 表与表之间的关系
- 实体类设计
- DAO类设计
- 工具类
- CategoryDao设计
- Service业务类设计
- 后台-分类管理
- 可运行的项目
- 静态资源
- FILTER配合SERVLET
- JSP包含关系
- 查询
- 分页
- 增加
- 删除
- 编辑
- 修改
- 后台其他管理
- 属性管理
- 产品管理
- 产品图片管理
- 产品属性值设置
- 用户管理
- 订单管理