在我们使用tomcat时, 通常会继承HttpServlet, 然后重写里面的doGet和doPost方法, 然后在web.xml配置请求路径与servlet处理类的映射
示例一:
public class AddItemServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
<servlet>
<description></description>
<display-name>AddItemServlet</display-name>
<servlet-name>AddItemServlet</servlet-name>
<servlet-class>com.bookstore.web.servlet.AddItemServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddItemServlet</servlet-name>
<url-pattern>/addItem</url-pattern>
</servlet-mapping>
对于这种方式去处理请求, 每处理一个请求, 都需要编写对应的Servlet来处理;
请求路径示例:
添加商品,移除商品请求:
http://localhost:8080/bookStore/addItem
http://localhost:8080/bookStore/removeItem
登录, 注册请求:
http://localhost:8080/bookStore/loginUser
http://localhost:8080/bookStore/registerUser
逻辑如图:
但是, 这样有很大的局限性, 不利于扩展; 那么, 可以这样设计, 我们可以编写一个基础Servlet实现类, 继承HttpServlet, 重写service()方法, 在该方法中, 我们可以根据请求信息中需要请求的方法参数获取对应的处理方法, 然后利用反射执行即可;
实例二:
public class BaseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//1.获取子类,创建子类或者调用子类的时候this代表的是子类对象
Class clazz = this.getClass();
//2.获取请求的方法
String m = request.getParameter("method");
if(m==null){
m="index";
}
//3.获取方法对象
Method method = clazz.getMethod(m, HttpServletRequest.class,HttpServletResponse.class);
//4.让方法执行,返回值为请求转发的路径
String s = (String) method.invoke(this, request,response); //相当于 userservlet.add(request,response)
//5.判断s是否为空
if(s!=null){
request.getRequestDispatcher(s).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//如果m为空,m被赋值为"index",所以为保证程序正常执行, 即clazz.getMethod(...)正常执行,需要index()方法存在.
//在index方法中访问服务器/indexServlet查询所有首页需要的商品信息,并返回跳转路径:"/jsp/index.jsp"
public String index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
return null;
}
}
public class AdminCategoryServlet extends BaseServlet {
public String findAllCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
}
public String editCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
}
public String addCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
}
}
这样, 对比示例一中的处理方式: 处理每一个请求都必须编写一个Servlet的实现类, 示例二有了一定的扩展性: 可以在一个Servlet实现类中处理多个请求信息, 只要我们在一个Servlet实现类中编写对应的处理方法即可;
请求路径示例:
添加商品,移除商品请求:
http://localhost:8080/bookStore/book?method=addItem
http://localhost:8080/bookStore/book?method=removeItem
登录, 注册请求:
http://localhost:8080/bookStore/user?method=login
http://localhost:8080/bookStore/user?method=register
逻辑如图:
但是, 这样设计并也需要配置不同的Servlet映射, 比如商品信息请求和用户登录信息请求的GoodsServlet和UserServlet, 在开发过程中随时都有可能需要添加信息的请求信息, 这样硬编码灵活性很差, 但是优点是示例2把请求处理从类级别缩小到方法级别了,
因此, 我们需要扬长避短, 对于需要硬编码的Servlet处理类, 我们可以编写一个UserController类来处理用户的登录信息; 一个GoodsController类来处理商品信息; 然后在一个Map集合中配置请求路径与对应处理方法的映射, 我们可以对示例二的BaseServlet进行改造, 在新的基础Servlet(DispatcherServlet)中, 根据请求信息解析到需要调用的处理类, 然后在Map集合中获取到该请求信息映射的处理方法, 然后通过反射去执行该处理器类中对应的处理方法对请求进行处理, 并根据处理方法返回的视图信息, 进行解析;
请求路径示例:
添加商品,移除商品请求:
http://localhost:8080/bookStore/book/addItem
http://localhost:8080/bookStore/book/removeItem
登录, 注册请求:
http://localhost:8080/bookStore/user/login
http://localhost:8080/bookStore/user/register
逻辑如图:
处理逻辑:
- 根据请求信息获取对应的处理方法
- 执行处理方法, 对请求进行处理
- 对处理方法执行完成后返回的视图信息进行解析
有没有发现这个过程很熟悉....
这就是SpringMVC的设计思想, 这也就是为什么SpringMVC中只定义了一个Servlet也可以处理大量不同的请求信息;
以上分析过程是我的个人理解, 如果有不对的地方, 欢迎指出, 共同进步!