[Servlet]请求调派、请求范围属性、Model 2设计思想简述

本文深入探讨了Web应用程序中请求调派的基本概念,包括包含和转发的区别,以及如何实现请求调派。同时,介绍了Model2设计思想在Web开发中的应用,包括控制器、模型和视图之间的职责划分。通过示例代码,展示了如何使用请求调派进行数据共享和Model2设计思想的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 请求调派的目的:

    1) 在Web应用程序中一个请求通常会由多个Servlet相互协调来完成相应,因此需要在程序中调派各个Servlet协作响应;

    2) 请求调派主要有两种类型:

         i. include:包含,即将另一个Servlet的执行流程包含在当前Servlet中;

         ii. forward:转发,将请求转发给另一个Servlet来处理;

         iii. 两种方法特点和不同:

              a. 特点:如果在一个Servlet中调用了include或forward,则都会等待调用结束返回后才会执行接下来的语句(函数调用后面的语句),即都是等待式的;

              b. 不同:不同主要表现在输出上,include调用后的页面输出语句有效,forward调用后的页面输出语句无效(最终不会出现在客户端的相应页面中),即forward将输出流转发了,被调用的Servlet响应完成后直接将输出流返回给客户端了,而调用它的Servlet将只能得到一个空的无法再输出的输出流(PrintWriter out);


2. 请求调派的实现步骤:

    1) 首先需要创建一个调派员引用RequestDispatcher dispatcher;

    2) 然后再利用HttpServletRequest的getRequestDispatcher函数获取一个调派员对象来初始化dispatcher引用:RequestDispatcher getRequestDispatcher(String path);

    3) 其中getRequestDispatcher的参数path需要指定要将响应调派给谁,填写的应该是目标Servlet的URL模式;

    4) 接下来在需要的地方调用dispatcher的include或forward方法进行包含或转发:

         i. include:void include(ServletRequest request, ServletResponse response);

         ii. forward:void forward(ServletReqeust request, ServletResponse response);

!!传的参数就是主调Servlet的request和response;

    5) 举例:

ReuqestDispatcher dispatcher = request.getRequestDispatcher("other.do?data=123456");
request.include(request, response); // request.forward(request, response);
!!可以在设定调派目的地时添加新的请求参数!上面的例子就是,在other.do后面添加了新的请求参数data=12345

3. 共享对象——请求范围参数:

    1) 有时候在调派前可能在主调Servlet中会创建一些对象或其它数据想让被调Servlet利用,但是调派时只能传递请求对象中的原来就保存好的那些字符串数据;

    2) HttpServletRequest提供了请求范围参数的功能,可以让你将一些临时创建的对象作为请求的一个参数专递给其它的Servlet,而这些属性可以称为对象属性,因为相对于URL中指定的参数属性来说(URL中的参数属性都是纯字符串类型的);

    3) 为什么叫做请求范围参数呢?因为这些对象属性的生命周期是伴随请求对象的,当请求对象被销毁时它们也会被销毁,因此它们的生命范围就是请求的有效范围,但是为了便于理解后面还是会称为对象参数;

    4) 如何设置和提取对象属性呢?

         i. 设置:void HttpServletRequest.setAttribute(String name, Object o);

         ii. 提取:Object HttpServletRequest.getAttribute(String name);

!!其中name就是自己起的对象参数名,前者在调派前设定,后者在被调者中提取并利用;

         iii. 示例:

// 主调中
List<Book> books = bookDAO.query("C++");
request.setAttribute("books", books);
request.getRequestDispatcher("do.view").include(request, response);

// 被调中
List<Book> books = (List<Book>)request.getAttribute("books");
...
    5) 获取所有对象属性的参数名:Enumeration<String> ServletRequest.getAttributeNames(); // 这是一个从ServletRequest继承而来的方法

    6) 移除指定的对象属性:void ServletRequest.removeAttribute(String name);


4. Model 2设计思想简述:

    1) 这里利用刚学的请求调派,因此顺便介绍一下请求调派在Model 2设计思想的运用;

    2) Model 2大致的设计流程:

         i. 请求进入控制器;

         ii. 控制器获取请求参数,然后将请求参数交给相应的模型处理(业务逻辑层,直接解决问题)获得运算结果;

         iii. 模型运算完毕回到控制器中,同时将运算结果返回给控制器;

         iv. 控制器将模型的运算结果作为对象属性插入到请求对象中,再将请求对象调派给专门负责显示画面的Servlet处理;

         v. 负责画面输出的Servlet提取请求对象中模型的运算结果,将数据运算结果可视化返回给客户端浏览器显示;

    3) 因此可以看出:

         i. 控制器必然是一个Servlet,控制器起到了获取请求参数、模型/视觉输出之间进行协调的作用;

         ii. 模型完全可以是一个纯Java类,负责运算、处理数据,并返回结果;

         iii. 画面输出Servlet只负责画面输出;

!!因此可以看到在Model 2设计思想中控制器中绝对不能包含画面输出语句,模型最好是纯Java类值负责运算、处理而不要包含任何和请求/响应有关的任何语句,画面输出Servlet最好只包含画面输出语句,不要包含任何和业务逻辑处理有关的任何语句,因此在画面输出这一环通常是由JSP实现的;


5. Model 2设计思路示例:

    1) 这里我们展示一个Model 2设计思路下的一个程序实例,由于还没学JSP,因此画面输出这一环先使用Servlet来实现;

    2) 控制器:HelloController.java

package com.lirx;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloController
 */
@WebServlet("/hello.do")
public class HelloController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloController() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
    private HelloModel model = new HelloModel();
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		
		String name = request.getParameter("user");
		String message = model.doHello(name); // 获取请求参数并交由模型来处理		
		request.setAttribute("message", message); // 将模型的运算结果插入到请求对象中
		request.getRequestDispatcher("hello.view").forward(request, response); // 转发给画面输出进行输出
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}
   3) 模型:HelloModel.java

package com.lirx;

import java.util.HashMap;
import java.util.Map;

public class HelloModel {
	private Map<String, String> messages = new HashMap<String, String>();

	public HelloModel() {
		messages.put("Peter", "Hello");
		messages.put("Tom", "Welcome");
		messages.put("Marry", "Hi");
	}

	public String doHello(String user) {
		return messages.get(user) + ", " + user + "!";
	}
}
    4) 画面输出:HelloView.java

package com.lirx;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloView
 */
@WebServlet("/hello.view")
public class HelloView extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloView() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
    private String htmlTemplate = 
			"<html>" +
			" <head>" +
			"  <meta http-equiv='Content-Type'" +
			"   content='text/html;charset=UTF-8'>" +
			"  <title>%s</title>" +
			" </head>" +
			" <body>" +
			"  <h1>%s</h1>" +
			" </body>" +
			"</html>";
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		
		String user = request.getParameter("user");
		String message = (String)request.getAttribute("message");
		String html = String.format(htmlTemplate, user, message);
		response.getWriter().print(html);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}
    5) 测试URL:http://localhost:8080/HelloModel2/hello.do?user=Peter,结果在页面中返回Hello, Peter!

    6) 和HelloView等效的JSP:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<title>${param.user}</title>
	</head>
	<body>
		<h1>${message}</h1>
	</body>
</html>
!可以看到该JSP里不包含任何Java代码;

!!同时控制器中不包含任何画面输出语句;

!!而且模型也只是一个纯Java类;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值