第05章 Servlet和JSP应用

Servlet与JSP很相似,但也有一些区别,我们重新说明一下:

1. Servlet是一个Java类文件,JSP是一个混编Java的HTML的文件。
2. Servlet使用方法来处理请求,JSP则使用内置对象来处理请求。
3. Servlet需要编译才能运行,而JSP由JSP Container管理,不需要编译。
4. Servlet通过配置url访问,JSP通过路径url访问,两者在Web工程中存放位置也不同。
5. Servlet的生命周期伴随Web容器的启动和关闭,JSP的生命周期伴随请求的开始和结束。
6. Servlet更倾向于做业务数据逻辑处理,JSP则倾向于做页面输出,Servlet可输出JSP文件。

在上面的区别中,重要的是最后一条,servlet侧重于业务数据逻辑处理,而jsp则倾向于页面输出。两者的最好搭配就是在servlet中对请求数据进行处理,然后将处理完毕的数据 “传递” 给JSP页面,在JSP页面中可以使用HTML展示给最终用户,而 “传递” 过来的数据可以使用 <%= 表达式 %> 或 EL 表达式来读取,并控制HTML的输出。也就是说,一个请求URL的处理分为 Servlet 和 JSP 两个部分一起完成的。

我们的Web工程由一个默认的“index.jsp”文件,这是整个工程的入口。然后就是从一个请求URL跳转到另外一个请求URL。每一个请求URL都可以对应一个页面。这个页面可以是Servlet输出的,也可以本身就是JSP页面。我们对需求功能的开发,最重要的就是将其梳理成一个一个页面组成的流程,这个前后顺序非常的重要。每一个页面对应一个请求URL,在这个页面中应该有流程中下一个页面的请求URL。需求功能的开发,其实就是根据流程,规划每一个页面请求URL。例如登录流程,首先是进入登录页面URL,然后用户在登录页面输入账号和密码,然后跳转验证URL,根据验证的结果可能会跳转到成功页面,或者失败页面。这里需要注意的是,JSP页面的请求URL就是该文件的目录地址,而Servlet的请求URL是我们自定义出来的。一个完整的登录流程应该如下所示,

1. 登录页面可以直接使用jsp页面呈现出来,对应的登录页面URL就是该jsp页面的访问路径URL

2. 用户输入完账户和密码后请求URL来验证,这个URL可以对应Servlet来完成。因为这里涉及到数据处理,使用Servlet来更合适。Servlet处理完毕之后,需要将处理结果输出。

3. Servlet输出结果分为两种情况,也就是两个页面,一个是成功页面,一个是失败页面。也可以使用一个结果页面,只是里面的数据代表了成功或者失败。不管是两个页面,还是一个页面,都需要上面的Servlet调用输出。

那么Servlet如何调用输出Jsp文件?以及Servlet如何向Jsp文件传递数据?Servlet输出JSP有两种方式,一个是转发,另一个就是重定向。两者的区别在于,浏览器url地址栏是否改变:重定向会改变url,而转发不会(仍然是当前请求url)。

这里我们先介绍如何进行转发。我们可以通过request对象提供的getRequestDispatche(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。例如下代码:

request.getRequestDispatcher("/test.jsp").forward(request, response);

request对象不仅仅是请求对象,同时也是一个存储对象,对应JSP页面中的requestScope作用域对象,开发人员可以通过request对象的setAttribute方法存储数据,这些数据会被传递给JSP页面。例如下代码:

String data ="hello";
request.setAttribute("data", data);

然后,我们就可以在“/test.jsp”中使用EL表达式 “${requestScope.data}” 来获取到这个data变量值。

接下来,我们就创建一个新的 “TestDemo” 的工程来演示如何进行转发。如何在Eclipse下创建Java动态工程,我们这里不再介绍,请参考上一个章节的内容。工程创建完毕之后,我们就创建一个TestServlet类,对应的请求映射为“/test”。

接下来,我们修改doGet方法内容:

		String data ="hello";
		request.setAttribute("data", data);
		request.getRequestDispatcher("/test.jsp").forward(request, response);

我们设置这个TestServlet的请求url是“/test”,然后它会转发给“/test.jsp”文件。请注意这个文件的路劲,它是一个绝对路径,并且是在 WebContent 根目录下。因此,我们需要在 WebContent 根目录下创建 “test.jsp”文件。同时,我们向这个 “test.jsp” 的文件传递了一个变量。注意到setAttribute方法有两个参数,第一个参数是key, 第二个参数就是 value,也就是变量 data。那么这个 key 是什么呢?它就是JSP页面中获取该变量的使用的名称。因此我们在JSP中可以使用 “${requestScope.data}” 获取到数据,这里的 “data” 就是那个key。这里需要注意的是,我们使用request放置数据,就需要使用requestScope来获取。为了不造成混乱,我们一般将这个key就定义为变量名称,让两者保持一致。接下来,我们创建“test.jsp”文件。

我们只在<body>标签中添加了一句代码:<h1>${requestScope.data}</h1>
就是使用EL 表达式来读取请求域requestScope中的数据“data”。
最后我们在补全一个工程入口文件“index.jsp”,如下所示

我们就增加了一个超链接,执行了TestServlet类,代码如下

<a href="${pageContext.request.contextPath}/test">test</a>

接下来,我们就可以运行整个工程了。

转发和数据传递都成功了,转发的时候,我们的浏览器地址:“http://localhost:8080/TestDemo/test” 是不变的,也就是说,虽然页面显示的是 “test.jsp” 的内容,但是请求的URL仍然是 TestServlet 的URL。正因为请求URL没有变化,因此TestServlet和JSP同属于这一个 “http://localhost:8080/TestDemo/test” 请求域范围,也就是 requestScope 。这就是我们为什么将数据放入到 requestScope 中,而JSP也能能够访问到的原因了。换句话说,如果请求URL改变了,那么他们就不属于同一个 请求requestScope,JSP页面也就不能从 requestScope 中获取传递过来的数据了。那么该使用什么方式来传递和获取数据呢?解决这个问题,我们先要讲解一个重定向。

response.sendRedirect(request.getContextPath()+"/hello.jsp");

请注意,转发是通过request对象实现的,而重定向是通过response对象实现的。我们调用response对象的sendRedirect方法进行重定向,它的参数就是新的请求URL地址,这个地址可以是JSP文件,也可以是其他Servlet。既然是演示Servlet输出JSP文件,那么咱们肯定是要填写jsp文件了。上面代码中request.getContextPath()是为了兼容那个 项目路径 的问题。接下来,我们就来创建 HelloServlet类,对应的请求映射为“/hello”。

然后我们继续修改doGet方法内容

        String data ="hello";
		request.setAttribute("data", data);
		response.sendRedirect(request.getContextPath()+"/hello.jsp");

我们继续使用“请求域”来传递数据,但是这次是“重定向”到“/hello.jsp”文件中。
接下来创建 “/hello.jsp ”

我们依然在<body>中添加 <h1>${requestScope.data}</h1> 来读取请求域的数据。
接下来,我们在“index.jsp”中补充上 HelloServlet 的请求链接

<a href="${pageContext.request.contextPath}/hello">hello</a>

接下来,我们重新发布并运行项目,然后去浏览器中刷新查看

点击“hello”超链接

上面出现了两个问题,第一是浏览器地址 url 不是“http://localhost:8080/TestDemo/hello” 而是 “http://localhost:8080/TestDemo/hello.jsp”。 第二是传递过来的数据没有显示出来,说明我们无法获取传递过来的数据。其实,这两个问题,我们在上面讨论转发的时候,就已经说明过了。正是因为浏览器URL地址的改变,说明 servlet 与 jsp不在同一个请求范围内了,因此我们就不能使用 requestScope 了。我们需要换一个更大范围的存储域,这里推荐大家使用 sessionScope。如何在Servlet中将数据放入到 sessionScope中呢,如下代码

        String data ="hello";
		//request.setAttribute("data", data);
		request.getSession().setAttribute("data", data);
		response.sendRedirect(request.getContextPath()+"/hello.jsp");

我们通过 request 的 getSession 方法获取会话对象,然后使用 setAttribute 将数据放入到 sessionScope中。数据存储的域对象变了,我们在JSP中也需要修改一下。

<h1>${sessionScope.data}</h1>

这里我不在使用“请求域”,而是使用“会话域”。

现在没有问题了,浏览器地址虽然改变了,但是我们依然能够获取传递过来的数据。关于 session 的内容,我们会在后面的章节详细介绍。

这里我们需要再次提醒大家一个问题,就是转发和重定向的参数,

// 转发
request.getRequestDispatcher("/test.jsp").forward(request, response);

// 重定向
response.sendRedirect(request.getContextPath()+"/hello.jsp");

转发的参数实际上是“test.jsp”的文件的目录地址,"/"代表了WebContent根目录。如果我们将“test.jsp”文件放置到“WEB-INF”目录下的话,就应该修改成:“/WEB-INF/test.jsp” 。有人可以疑问,“WEB-INF”目录是保护目录,是不能被访问的。请注意,我们转发的参数是文件的目录地址,并不是访问URL。这是两个完全不同的概念。如果JSP作为请求URL的话,它是不允许在WEB-INF下访问的。但是,如果JSP作为文件路径的话,它是可以被Java代码访问的。因此,转发的JSP文件放置到“WEB-INF”保护目录是没有任何问题的,事实上,我们也经常这么做。接下来是重定向的参数,它才是访问URL,因此它需要 request.getContextPath() 来兼容项目路径的问题。同时,我们还可以填写 servlet 的访问URL。此时,如果我们将“hello.jsp” 放置到 “WEB-INF” 保护目录的话,那么这个重定向的URL是不能被访问的。最后就是数据传递的问题,我们在servlet中将数据放置到那个域中,就需要在jsp页面中使用对应的作用域来获取。一般情况下,转发就使用“请求域”来传递数据,而重定向的话就使用“会话域”来传递数据。虽然我们也可以放置到“应用”级别的作用域applicationScope(ServletContext),但是这个作用域是共享于所有的客户端浏览器,而我们上面介绍的请求作用域和会话作用域是绑定某一个客户端浏览器的,也就是说,客户端浏览器不同,它对应的请求作用域和会话作用域是不一样的。举例而言,张三使用一个客户端浏览器访问某个页面时候,存储在请求域或会话域的数据不会被李四访问到,因为李四使用另一个客户端浏览器访问的。两者的请求域或会话域的数据是相互隔离的,互不干扰。但是,“应用”级别的作用域applicationScope(ServletContext)是共享于所有客户端浏览器,张三和李四可以访问到相同的共享数据,并且该作用域的数据有效期直到我们的WebServer(例如Tomcat)重启才会失效。

  • 35
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值