本章简介

  本章将系统介绍JSP页面元素以及内置对象,其中重点介绍了outrequestresponsesession等常用内置对象以及Cookie等使用,并且从使用原理上讲 解了pageContextrequestsessionapplication等四种范围对象的作用域。

回顾第一个jsp程序,如下,

index.jsp

<html><head><title>First Web Project</title></head><body><%out.print("Hello World");%></body>
</html>

  其中 <% out.print("Hello World”); %>称为脚本。可以发现,在JSP文件中,既有HTML标签,又有JAVA代码,因此我们可以把JSP看成“嵌入JAVA的HTML代码”。

但是在Eclipse中生成的Jsp内容,如下

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body></body>
</html>

  Eclipse生成的JSP文件中,除了典型的html元素外,还有很多其他内容。这是因为JSP页面本身就可以包含多种页面元素,如脚本、HTML、指令、注释等。

2.1 JSP页面元素

1) 脚本Scriptlet

所有嵌入在HTML中的JAVA代码都必须使用scriptlet包裹起来。
在JSP中共有3种Scriptlet:<% … %><% ! …%><% =…%>

Scriptlet一般写在<body>标签中。

①<%…%>

<% …%>主要用来定义局部变量编写java语句

scriptlet.jsp

<body>
<%String bookName ="疯狂Java讲义";String author = "李刚" ;out.print("书名:"+bookName+"<br/>作者:"+author);%>
</body>

运行结果:

其中,out.print();是JSP页面的输出语句。

②<%! … %>

<% ! … %>主要用来定义全局变量定义方法

scriptlet2.jsp

<body><%!public String bookName ; //定义全局变量-书名public String author ; //定义全局变量-作者public void initInfo(){ //定义一个方法bookName = "《Java疯狂讲义》";author = "李刚";}%><%initInfo();//调用方法out.print( "书名:" + bookName + "</br>" +"作者:"+ author);%>
</body>

运行结果:

注意:
out.print()只能写在<%…%>里面。写在<%!..%>里面会报错的。

③<%=…%>

<%= … %> 用来输出=后面的表达式的值,功能类似out.print()

<body>
<%String bookName ="疯狂Java讲义";String author = "李刚" ;%><%="书名:" + bookName + "</br>" +  "作者:" + author %>
</body>

运行结果同上。

从上面代码,可以发现:
out.print()和<%=… >不仅能输出变量,还可解析”&lt;br/&gt;”等html代码。
<%= …>中没有“;”

2) 指令

JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言。

JSP指令写在 <%@ …%>
指令可以有很多个属性,它们以键值对的形式存在,并用逗号隔开。

JSP中的三种指令标签:

指令 描述
<%@ page … %> 定义网页依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include … %> 包含其他文件
<%@ taglib … %> 引入标签库的定义

①page指令

Page指令为容器提供当前页面的使用说明。
一个JSP页面可以包含多个page指令。

Page指令的语法格式:

<%@ page language="java" import="java.util.*" contentType="text/html;
charset=UTF-8"  pageEncoding="UTF-8"%>
属性 说明
language 指定JSP页面使用的脚本语言,默认是java,一般不用修改。
import 与java中import的用法一致,可以执行导包操作
pageEncoding 指定JSP文件本身的编码方式
contentType 指定服务器发送给客户端的内容的编码方式,通常与pageEncoding保持一致
errorPage 指定当JSP页面发生异常时需要转向的错误处理页面
isErrorPage 指定当前页面是否可以作为另一个JSP页面的错误处理页面
extends 指定servlet从哪一个类继承
info 定义JSP页面的描述信息
session 指定JSP页面是否使用session
isThreadSafe 指定对JSP页面的访问是否为线程安全
isELIgnored 指定是否执行EL表达式

page.jsp

<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>page指令</title>
</head>
<body>
<%Date date = new Date();out.print(date);%>
</body>
</html>

运行结果:

②include指令

JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。

Include指令的语法格式如下:

<%@ include file="文件相对 url 地址" %>

include 指令中的文件名实际上是一个相对的 URL 地址。
如果您没有给文件关联一个路径,JSP编译器默认在当前路径下寻找。

③taglib指令

JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。
Taglib指令引入一个自定义标签集合的定义,包括库路径、自定义标签。

Taglib指令的语法:

<%@ taglib uri="uri" prefix="prefixOfTag" %>

uri属性确定标签库的位置,prefix属性指定标签库的前缀。

3) 注释

前面讲过,基本的JSP包含了HTML和JAVA两种代码。因此,JSP的注释既包括HTML的注释,又包含JAVA的注释,此外还拥有JSP自己独有的注释

注释方式 说明
<!-- --> HTML注释。可以用来注释HTML代码,但要注意此种注释能通过客户端(浏览器)查看到,因此是不安全的。
<%-- --%> JSP注释。如果想让注释不被浏览器所查看到,就可以使用JSP注释。
<% //单行注释 %> <% /*多行注释 */ %> JAVA注释。<% %>中放置的是JAVA代码,所以可以在<% %>使用//和//来对其中的JAVA代码进行注释。

note.jsp

<body>
<!-- HTML注释 -->
<%--jsp注释 --%>
<%
//java单行注释
/*java多行注释
*/
%>
</body>

运行结果:

鼠标右键网页空白处,查看源代码,如图:

可以发现HTML的注释能被浏览器所查看到,而JSP注释和JAVA注释不能被查看。

2.2 九大内置对象

<%
out.print("Hello World");
%>

在上面的代码中,像out这样,没有定义和实例化(new)就可以直接使用的对象,就称为内置对象。JSP还提供了9个内置对象,如下表

内置对象 类型 简介
page Context javax.servlet.jsp.PageContext JSP页面容器
request javax.servlet.http.HttpServletRequest 客户端向服务端发送的请求信息
response javax.servlet.http.HttpServletResponse 服务器端向客户端的响应信息
session javax.servlet.http.HttpSession 客户端与服务器端的一次会话
application javax.servlet.ServletContext 可存放全局变量,实现用户间数据的共享
config javax.servlet.ServletConfig 服务器配置信息,可以取得初始化参数
out javax.servlet.jsp.JspWriter 向客户端输出内容
page java.lang.Object 当前JSP页面本身,类似于Java类中的this关键字.
exception java.lang.Throwable 当一个页面在运行过程中发生了异常,就产生这个对象

1) out

out用于向客户端输出数据,最常用的是out.print();
需要注意的是,out.println()或者out.print(“\n”)均不能实现在客户端的换行功能

out.jsp

<body><%out.println("hello");out.print("world\n");out.print("hello world");
%>
</body>

运行结果:


若要实现换行,必须借助于HTML的&lt;br/&gt;或者</br>标签

out2.jsp

<body><%out.println("hello</br>");out.print("world");
%>
</body>

运行结果:

2) request

request对象主要用于存储“客户端发送给服务端的请求信息

因此我们可以通过request对象来获取用户发送的相关数据,request对象的常用方法如下表:

方法 简介
public String getParameter(String name) 获取客户端发送给服务端的参数值(由name指定的唯一参数值,如单选框、密码框的值)
public String[] getParameterValues(String name) 获取客户端发送给服务端的参数值(由name指定的多个参数值,如复选框的值)
public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException 指定请求的编码,用于解决乱码问题
public RequestDispatcher getRequestDispatcher(String path) 返回RequestDispatcher对象,该对象的forward()方法用于转发请求
public HttpSession getSession() 返回和请求相关Session
public ServletContext getServletContext() 获取web应用的ServletContext对象

下面通过一个简单的注册及显示功能,演示上述部分方法的使用:

register.jsp

<body><form action="show.jsp" method="post">用户名:<input type="text" name="username"></br>密码:<input type="password" name="userpwd"></br>爱好:<input type="checkbox" name="hobby"  value="足球">足球<input type="checkbox" name="hobby" value="篮球">篮球<input type="checkbox" name="hobby" value="羽毛球">羽毛球</br><input type="submit" name="注册"></form>
</body>

运行结果:

show.jsp

<body>
<%request.setCharacterEncoding("UTF-8");//设置请求编码和页面一致,为utf-8String userName = request.getParameter("username");//获取用户名String userPwd = request.getParameter("userpwd");//获取用户密码String[] hobbies = request.getParameterValues("hobby");//获取爱好//将hobbies数组转化为字符串String userHobbies = "";if(hobbies != null){for(int i = 0 ; i < hobbies.length ; i++){userHobbies =  hobbies[i]+userHobbies +  " ";}}
%>用户的注册信息如下:</br>用户名:<%=userName %></br>密码:<%=userPwd %></br>爱好:<%=userHobbies %></br>
</body>

运行结果:

  上述代码中,通过request.setCharacterEncoding("UTF-8")将POST方式的编码设置为UTF-8,,并通过request.getParameter()request.getParameterValues()方法获取到了从表单传来的数据。

  需要注意的是,客户端的数据不一定必须从表单传递过来,也可以通过URL地址进行传递,格式如下:

页面地址?参数名1=参数内容1&参数名2=参数内容2&…

  即通过“?”将页面地址和参数分离,然后按照“参数名=参数内容”的格式来传递数据,并且多个参数之间用“&”分隔。
  例如,上例中,我们可以不运行注册页register.jsp,而直接在浏览器中输入 http://localhost:8080/JspProject/register/show.jsp?username=李四&userpwd=123&hobby=足球&hobby=篮球

也能正常运行程序,并得到结果,如图

补充:Get与Post请求

  我们仔细观察一下表单提交和URL地址提交两种方式的地址栏,

表单提交方式的地址栏: http://localhost:8080/JspProject/register/show.jsp

URL地址提交方式的地址栏: http://localhost:8080/JspProject/register/show.jsp?uname=李四&upwd=123&hobby=足球&hobby=篮球

  这两种地址不同的本质原因,在于表单的的提交方式,在register.jsp中有一行代码 <form action="show.jsp" method="post" >其中method就可以用来指定表单的提交方式,常用属性值有get和post两种。

当method=”post”时,表示以post方式请求表单,请求后的地址为 http://localhost:8080/JspProject/register/show.jsp

当method=”get”时,再次提交表单,则地址栏就会显示 http://localhost:8080/JspProject/register/show.jsp?username=张三&userpwd=123&hobby=足球&hobby=篮球

  因此,可以发现用get方式提交表单,实际就是通过URL地址提交的方式向服务器端发送数据。

说明:

  如果 “URL地址传递”中的值是中文,而JSP页面编码是UTF-8时,则会显示乱码。
原因是“URL地址传递”使用的是GET方式传递数据,而GET方式的默认编码是ISO-8859-1,与JSP页面编码UTF-8不一致。
解决方法就是将GET方式提交的数据,进行统一字符编码,详见后文。

  除了地址栏的不同以外,get和post方式在提交的数据大小上也有区别。因为get方式会在地址栏上显示数据信息,而地址栏中能容纳的信息长度是有限制的(一般是4-5KB); 与之不同的是,post方式不会在地址栏中显示数据信息,所以能提交更多的数据内容。因此,如果表单中有一些大文本、图文、文件、视频等数据,就必须使用post的方式提交。 request的其余方法,我们会在后面详细讲述。

补充:统一字符集编码

  了解完get方式和post方式的区别后,我们再来看看两种方式如何解决字符乱码问题。

解决Web项目乱码问题的基本步骤如下(以将编码统一为UTF-8为例):

1.将所有JSP文件的编码设置为UTF-8,如下,
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
…

此步骤,也可通过Eclipse来设置,详细步骤参见第一章。

2.对于GET或POST方式,实施不同的统一编码操作。

我们首先要知道tomcat服务器,默认使用的编码方式是ISO-8859-1。

(1)如果是以get方式提交表单(或URL地址传递的方式),则有两种方式处理编码:

方法①:分别把每一个变量的编码方式,从ISO-8859-1转为UTF-8

如以下代码:

 //将name的编码方式,从ISO-8859-1转为UTF-8String name = request.getParameter("uname");name = new String(name.getBytes("ISO-8859-1"), "UTF-8");//将pwd的编码方式,从ISO-8859-1转为UTF-8String pwd = request.getParameter("upwd");pwd = new String(pwd.getBytes("ISO-8859-1"), "UTF-8");

方法②:修改tomcat配置
  一次性的,将所有通过get方式传递的变量编码都设置为UTF-8(推荐)。具体修改如下:打开tomcat的conf目录,在server.xml的64行附近的元素中,加入URIEncoding=”UTF-8”,如下

server.xml

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"  URIEncoding="UTF-8" />

说明:

要使修改的server.xml生效,必须把Eclipse的tomat服务器设置成本地Tomcat托管模式,设置托管模式方法如下:
  我们使用Eclipse配置完Tomcat后,会在左侧项目导航栏多出一个Servers项目,该项目中就有Tomcat的一些配置文件,如context.xml,server.xml等。为了使Servers项目中的配置文件,与我们本地安装的Tomcat目录中的配置文件保持一致,我们可以双击控制台Servers下的Tomcat V9.0。在双击后打开的页面里,将Server Locations指定为第二项,如图

  之后,我们只需要在Servers项目中修改配置文件,修改结果就会同步到我们本地安装的Tomcat配置文件中。因此,以后如果要对Tomcat进行操作,就只需要对Servers项目进行操作。

注意,如果发现Server Locations中的选项是灰色不可选,则需要将现有的Tomcat从Servers面板中删除,然后重新创建Tomcat服务后再选择。

(2)如果是以post方式提交表单,可以通过在服务器端加入request.setCharacterEncoding(“UTF-8”)来设置编码,详见前面的show.jsp。

3) response

我们已经知道,客户端可以通过request向服务端发送请求数据,那反过来呢?
当服务器端接收到请求的数据后,如何向客户端响应呢?答案就是response,即服务端可以通过response向客户端做出响应

response也提供了一些方法用来处理响应,如下表所示,

方法 简介
public void addCookie(Cookie cookie) 服务端向客户端增加Cookie对象
public void sendRedirect(String location) throws IOException 将客户端发来的请求,重新定位(跳转)到另一个URL上(习惯上称为“重定向”)
public void setContentType(String type) 设置服务器端响应的contentType类型

  我们先来了解一下重定向方法sendRedirect()的使用。 这次我们实现一个登陆功能:用户输入用户名和密码,如果验证正确,则跳转到欢迎页,如下:

login.jsp(输入用户名:admin,密码:123)

<body><form action="check.jsp"  method="post">用户名:<input type="text" name="username"></br>密码:<input type="password" name="userpwd"></br><input type="submit" name="登录"></form>
</body>

运行结果:

验证页: check.jsp

<%String userName = request.getParameter("username");//获取用户名String userPwd = request.getParameter("userpwd");//获取用户密码if("admin".equals(userName) && "123".equals(userPwd)){//判断用户输入的用户名或者密码是否匹配response.sendRedirect("success.jsp");//验证成功,跳转到成功界面}else{response.sendRedirect("fail.jsp");//验证失败,跳转到失败界面}
%>

若登陆成功,则跳转到成功提示页: success.jsp

<body>
<%String userName = request.getParameter("username");
%>
欢迎你,<%=userName%>
</body>

运行结果:

从“运行结果”可以发现两点:

1.如果用户名和密码验证成功,确实跳转到了欢迎页success.jsp,但数据却丢失了,用户名name的值为null。
2.重定向到success.jsp后,地址栏也变成了success.jsp页面的地址。

补充:请求转发与重定向

send:发送
redirect:改变方向
request:请求
dispatcher:调度员

  为了解决重定向以后数据丢失的问题,我们先来回忆一下request对象中的一个方法: public RequestDispatcher getRequestDispatcher(String path)

之前说过,此方法的返回值为RequestDispatcher(请求调度员)对象,有一个forward()方法可以用于转发请求,也就是说,request的getRequestDispatcher()方法和response的sendRedirect()方法有相同之处:都可以实现页面之间的跳转。

我们将check.jsp中的response.sendRedirect("success.jsp")改为request.getRequestDispatcher("success.jsp").forward(request, response),其他代码均不变,再次运行程序,可以看到success.jsp的结果如图:

  可以发现, 采用了request.getRequestDispatcher("success.jsp").forward(request, response)来跳转页面后:

1.成功页面就可以获取到客户端发送的表单数据;
2.页面内容确实跳转到了success.jsp中编写的内容,但地址栏却仍然停留在check.jsp,即采用请求转发方式,地址栏不会发生改变。

  关于请求转发(request.getRequestDispatcher(“xx”).forward(request, response))和重定向response.sendRedirect(“xx”)的区别,经常会在面试中被提到,我们在此做一个总结,如下表:

请求转发(forward()) 重定向(redirect())
请求服务器次数 1次 2次
是否保留第一次请求时request范围中的属性 保留 不保留
地址栏里的请求URL,是否改变 不变 改变为重定向之后的新目标URL。
关于“请求服务器次数”的问题,再做以下详尽分析:

请求转发:客户端(浏览器)向服务器的资源A发起一次请求,服务器的资源A接收到该请求后,将该请求转发到内部的其他资源B,资源B处理完请求后,最终给客户端做出响应。

重定向:客户端(浏览器)向服务器的资源A发起一次请求,服务器的资源A接收到该请求后,给客户端做出响应,告诉客户端去重新访问资源B的地址 ,客户端收到资源B的地址后再次向服务器的资源B发出第二次请求,服务器资源B处理完该请求并做出响应。

情景模拟:

请求转发:张三去银行的A窗口办理业务,A窗口的业务员发现该业务自己办不了,就将张三的业务请求转发给其他同事办理,最后将办理完的业务返回给张三。也就是说,张三只是给银行的A窗口发送了一次请求,而该业务办理人员之间的换人工作,是银行内部处理的。即张三只发出了一次请求,更换窗口业务员(跳转)是银行的行为。

重定向:张三去银行的A窗口办理业务,A窗口的业务员发现该业务自己办不了,然后告诉张三应该重新去窗口B办理,张三收到该消息后,又重新向银行的窗口B再次请求办理业务,最终银行的窗口B处理完张三的请求,并将办理完的业务返回给张三。也就是说,张三分别向银行的窗口A、窗口B各发送了一次请求(共2次请求),更换窗口业务员(跳转)是张三的行为。

4)cookie和内置对象session

  在学习session之前,我们有必要先来了解一下cookie。
  注意:cookie不是内置对象

① cookie

  cookie对象是先由服务端产生,再发送给客户端(浏览器)的,并且浏览器会将该cookie保存在客户端的某个文件中。也就是说,cookie技术能将服务器端的一些数据,保存在用户使用的客户端计算机中。这样一来,用户下次就可以直接通过自己的计算机访问到该数据,而不必再访问服务器。因而cookie技术可以提高网页处理的效率,也能减少服务器端的负载。但是由于cookie是服务器端保存在客户端的信息,所以其安全性相对较差。

(1)cookie的使用:

  一个Cookie对象包含一个键值对,即key=value。cookie不是JSP的内置对象,需要通过JSP提供的javax.servlet.http.Cookie类来创建,Cookie类提供的常用方法如下表:

方法 简介
public Cookie(String name, String value) 构造方法,用来实例化Cookie对象,同时设置Cookie对象的属性名和属性值
public String getName() 获取Cookie对象的名称
public String getValue() 获取Cookie对象的内容
public void setMaxAge(int expiry) 设置Cookie的保存时间,以秒为单位

  服务器端可以通过response对象的addCookie()方法,将Cookie对象设置到客户端;
而客户端也可以通过request对象的getCookies()方法来获取全部的Cookie对象,如下:

服务器端 response_addCookie.jsp:

<body>
<%Cookie cookie1 = new Cookie("name","zhangSan");//创建一个cookie存nameCookie cookie2 = new Cookie("age","15");//创建一个cookie存ageresponse.addCookie(cookie1);//服务端将cookie1添加到客户端response.addCookie(cookie2);//服务端将cookie2添加到客户端response.sendRedirect("temp.jsp");
%>

跳转页面 temp.jsp

<body>
<a href="request_getCookie.jsp">跳转到客户端</a>
</body>

客户端 request_getCookie.jsp

<body>
<%Cookie[] cookies = request.getCookies();for(int i = 0 ; i< cookies.length; i++){out.print(cookies[i].getName()+","+cookies[i].getValue()+"   ");}
%>
</body>

  先执行response_addCookie.jsp,并在跳转后的页面temp.jsp里点击超链接,运行结果:

  可以发现,temp.jsp中的超链接并没有携带任何参数,但跳转后的客户端response_addCookie.jsp页面却依然能获取到Cookie对象。这是因为,在客户端发送的请求中(超链接请求、表单请求等)包含着非常丰富的内容,除了可以携带URL参数、表单数据意外,还会传递丰富的请求头信息,如图


  可以发现,请求头信息中包含着多个Cookie对象,每个Cookie对象都是以“键=值”的形式存在的,并且键为JSESSIONID的Cookie对象是由服务器自动产生的。

  实际上,在客户端每一次访问服务器时,服务器为了区分各个不同的客户端,就会自动在每个客户端的Cookie里设置一个JSESSIONID,表示该客户端的唯一标示符。

(2)补充:谷歌浏览器查看所有cookie信息

设置–>高级–>隐私设置和安全性–>网站设置–>cookie–>所有 Cookie 和网站数据

(3)通过Cookie来实现一个简单的“记住用户名”功能:

登录页login_cookie.jsp

<body>
<%!String username ;String pwd;
%>
<%Cookie[] cookies = request.getCookies();if(cookies!=null){for ( int i = 0 ; i< cookies.length; i++){if("username".equals(cookies[i].getName())){username = cookies[i].getValue();}if("pwd".equals(cookies[i].getName())){pwd = cookies[i].getValue();}}}
%><form action="check.jsp"><input type="text" name="username" value="<%=username == null ?"":username%>"></br> <input type="password" name="pwd" value="<%=pwd == null ?null :pwd%>"></br> <input type="submit" value="登录"></form>
</body>

登录验证页check_cookie.jsp

<body>
<%String username = request.getParameter("username");//获取用户名String pwd = request.getParameter("pwd");//获取密码Cookie cookie = new Cookie("username",username);Cookie cookie2 = new Cookie("pwd",pwd);response.addCookie(cookie);response.addCookie(cookie2);
%>
</body>

运行结果:

第一次访问登录页login_cookie.jsp:

输入用户名“张三”及密码并点击登录,之后如果再次访问登录页login_cookie.jsp,就会看到页面已经保存了用户名和密码,如图

(5)cookie的有效期

  需要注意的是,Cookie在客户端保存的时间不是永久性的,它也是有生命周期的,我们可以通过setMaxAge(int expiry)方法设置cookie的有效期。
  例如以下代码,我们先通过setCookieAge.jsp页面设置一个Cookie对象,然后再尝试通过getCookie.jsp页面来获取该Cookie对象,

生成cookie页面:setCookieAge.jsp

<body>
<%Cookie cookie = new Cookie("user","韩梅梅");//生成一个cookiecookie.setMaxAge(10);//设置cookie在10秒钟后失效response.addCookie(cookie);//服务端把cookie发送给客户端response.sendRedirect("getCookie.jsp");
%>
</body>

获取cookie页面:getCookie.jsp

<body>
<%Cookie[] cookie = request.getCookies();//客户端获取cookieboolean flag = false;//cookie存在的标识,false为失效,true为有效for(int i = 0; i< cookie.length; i++){if("user".equals(cookie[i].getName())){out.print("欢迎你,"+cookie[i].getValue());flag = true;//把cookie设置为有效}}if(!flag){out.print("cookie失效了!");}
%>
</body>

先执行setCookieAge.jsp来设置Cookie对象。之后,如果在10秒以内运行getCookie.jsp,则运行结果:

10秒钟之后,执行getCookie.jsp,运行结果:

即,我们可以通过setMaxAge(秒数)来设置Cookie对象的有效期。

2)session

  session通常被翻译成“会话”。一个会话是指:用户通过浏览器(客户端)与服务器之间进行的一系列的交互过程,交互期间可以包含浏览器与服务器之间的多次请求、响应。以下是3个常见的session使用情景:

①用户在浏览某个网站时,从进入网站到关闭这个网站所经过的这段时间,也就是用户浏览这个网站的整个过程,就是一个session。

②在电子邮件应用中,从一个客户登录到电子邮件系统开始,经过收信、写信和发信等一系列操作,直至最后退出邮件系统,整个过程为一个session。

③在购物网站应用中,从一个客户开始购物,到浏览商品、结算等,直至最后的结账,整个过程为一个session。

session运行机制:

  当用户(浏览器)向Web应用第一次发送请求时,服务器会创建一个session对象并分配给该用户;该session对象中包含着一个唯一标识符sessionId,并且服务器会在第一次响应用户时,将此sessionId作为jsessionid保存在浏览器的Cookie对象中;这个session将一直延续到用户访问结束(浏览器关闭或用户长时间不访问Web应用)。

客户端(用户)每次都是带着自己的jsessionid去访问服务端。
①当客户端没有jsessionid的时候,服务端会创建一个session对象,然后将这个session对象发送给客户端,客户端会用jsessionid去保存这个session对象,存在cookie中。
②当客户端有jsessionid的时候,服务端就会通过客户端传来的jsessionId找到对应的session,以确定是这个用户在访问服务器。

  如果客户端禁用了Cookie,则服务器会自动使用URL-rewriting(URL重写,URL中包含session ID的信息)的技术来保存sessionId。

  session内置对象是javax.servlet.ServletContext.HttpSession接口的实例化对象,常用方法如下表:

方法 简介
public String getId() 获取sessionId
public boolean isNew() 判断是否是新的session(新用户)
public void invalidate() 使session失效
public void setAttribute(String name, Object value) 设置session对象名和对象值
public Object getAttribute(String name) 根据session对象名,获取session对象值
public void setMaxInactiveInterval(int interval) 设置session的有效非活动时间, 单位是秒
public int getMaxInactiveInterval() 获取session的有效非活动时间,单位是秒

  下面来验证一下服务端生成的sessionId和客户端生成的JSESSIONID相同。
createSession.jsp

<body>
<%session.setAttribute("username", "lee");response.sendRedirect("showSession.jsp");
%>
</body>

showSession.jsp

<body>
<%out.print("sessionID:"+session.getId()+"</br>");//输出sessionIDCookie[] cookies = request.getCookies();out.print(cookies[0].getName()+":"+cookies[0].getValue());
%>
</body>

运行结果:

下面通过一个登陆的案例来演示session在开发中的应用:

登陆界面:login.jsp

<body>
<form action="check.jsp" method="post">用户姓名:<input type="text" name="username" ></br>用户密码:<input type="password" name="password" ></br><input type="submit" value="登陆">
</form>
</body>

登陆判断:check.jsp

<body>
<%String username = request.getParameter("username");//获取用户名String password = request.getParameter("password");//获取密码if("admin".equals(username) && "123456".equals(password)){//验证通过session.setAttribute("username", username);//将用户名添加到sessionsession.setMaxInactiveInterval(60*10)    ;//设置session最大存活时间为10分钟response.sendRedirect("welcome.jsp");}else{//验证不通过response.sendRedirect("login.jsp");//重新跳转到登陆界面}
%>
</body>

欢迎页面:welcome.jsp

<body>
<%String username = (String)session.getAttribute("username");//从session获取usernameif(username == null ){response.sendRedirect("login.jsp");}else{out.print("欢迎您,"+ username  ) ;out.print("<a href='logout.jsp' >注销</a>");}
%>
</body>

注销页面:logout.jsp

<body>
<%String username = (String)session.getAttribute("username");if(username == null){response.sendRedirect("login.jsp");}else{session.invalidate();response.sendRedirect("login.jsp");}
%>
</body>

  可以发现,如果输入正确的用户名和密码(admin/123456),则直接跳转到欢迎页,如图

  如果用户名或密码输入有误,则返回登录页。而且,如果用户没有登录,直接访问welcome.jsp或logout.jsp,也会因为session作用域中的“username”为null而直接跳转返回登录页,从而实现访问权限的控制。

解释一下:
对于session.setMaxInactiveInterval(10);,括号中的参数单位是是秒,表示session的有效最大非活动时间是10秒钟,意思就是只要在同一个浏览器下,最后一次访问同一个项目的时间在10秒钟之内,session就不会失效。只有超过10秒钟不操作该项目,session才会失效。

最后,再说明一下cookie和session的几点区别:

cookie session
保存信息的位置 客户端 服务器端
保存的内容 字符串 对象
安全性 不安全 安全

5)application

  application对象是javax.servlet.ServletContext接口的实例化对象,代表了整个web项目,所以application对象的数据可以在整个web项目中共享,用法上类似于“全局变量”的概念。application对象的常用方法如下表:

方法 简介
public String getContextPath() 获取相对路径(默认是"/项目名称")
public String getRealPath(String path) 获取虚拟路径对应的绝对路径

我们先直接通过一段代码,看一下运行结果,
applicationDemo.jsp

<body>
<%String contextPath = application.getContextPath();//获取上下文路径,也就是相对路径String realPath = application.getRealPath("/");//获取绝对路径out.print("contextPath:" + contextPath);out.print("</br>");out.print("realPath:" + realPath);
%>
</body>

运行结果:

  可以发现,相对路径就是“/项目名”,而绝对路径是完整的本地路径。
相对路径和绝对路径都可以修改,可以在第一章的“配置Web应用的虚拟路径”一节中查看。

2.3 四大作用域

  在JSP的内置对象中,包含着四种范围对象(或称为“域对象”),简介如下

对象 作用域
pageContext 数据只在当前自身的页面有效
request 数据在一次请求中有效
session 数据在一次会话中有效;但若是新开浏览器,则无效
application 数据在当前Web项目有效,可供所有用户共享

以上的四个范围对象,都可以用以下的方法:

方法 说明
public void setAttribute(String name, Object o) 设置属性名和属性值
public Object getAttribute(String name) 根据属性名,获取对应的属性值
public void removeAttribute(String name) 根据属性名,删除对应的属性值

1) pageContext作用域

  我们创建一个页面 pageDemo.jsp,然后通过pageContext.setAttribute()添加两个属性(每个属性都由键值对组成),再通过pageContext.getAttribute()将属性的值取出,代码如下:

<body>
<%//设置pageContext属性pageContext.setAttribute("username", "admin");pageContext.setAttribute("password", "123");
%>用户:<%=pageContext.getAttribute("username") %></br>密码:<%=pageContext.getAttribute("password") %>
</body>

运行结果:

  因为pageContext对象中的属性的作用域是“在当前自身的页面内有效”,所以能够正常显示。
  但如果将上述页面进行修改,将增加属性放在page_scope_one.jsp中执行,再通过请求转发跳转到page_scope_two.jsp页面,并在page_scope_two.jsp中显示属性的值,如下代码:

page_scope_one.jsp

<body>
<%//设置pageContext属性pageContext.setAttribute("username", "admin");pageContext.setAttribute("password", "123");request.getRequestDispatcher("page_scope_two.jsp").forward(request, response);
%>
</body>

page_scope_two.jsp

<body>
姓名:<%=pageContext.getAttribute("usernmae") %></br>
密码:<%=pageContext.getAttribute("password") %>
</body>

  执行page_scope_one.jsp,运行结果:

  因为页面从page_scope_one.jsp,通过请求转发跳转到page_scope_two.jsp后,就已经不再是同一个页面了,所以无法再通过pageContext对象获取到数据。

2) request作用域

  要想在请求转发后的page_scope_two.jsp页面获取到属性值,可以使用request的作用域。
request的作用域是“在客户端向服务器端,发送的一次请求中有效”。我们将上面的例子修改如下:

request_scope_one.jsp

<body>
<%//设置request属性request.setAttribute("username", "admin");request.setAttribute("password", "123");request.getRequestDispatcher("request_scope_two.jsp").forward(request, response);
%>
</body>

request_scope_two.jsp

<body>
姓名:<%=request.getAttribute("username") %></br>
密码:<%=request.getAttribute("password") %>
</body>

执行request_scope_one.jsp,运行结果:

  因为从request_scope_one.jsprequest_scope_two.jsp的跳转是“请求转发”,即仍然是同一次请求,而request的作用范围就是“在一次请求中有效”。

3) session作用域

  如果希望在增加属性以后,能够在跳转后的任何页面(无论是请求转发、重定向或超链接跳转),甚至是项目中任何一个页面都能获取到该属性值,就可以使用session的作用域来实现。

现在将上例的作用域从request改为session,如以下代码:

session_scope_one.jsp

<body><%session.setAttribute("username","admin");session.setAttribute("password","1234");response.sendRedirect("session_scope_two.jsp");%>
</body>

session_scope_two.jsp

<body>书名:<%=session.getAttribute("username") %> <br/>作者:<%=session.getAttribute("password") %></body>

执行session_scope_one.jsp,运行结果:


  此外,如果我们重新打开一个浏览器标签(一定要相同浏览器),然后在新标签里直接输入request_scope_two.jsp,也能获取到数据,如图,

  但是,如果我们换一个其他浏览器(比如从火狐换成IE),再次直接访问request_scope_two.jsp,就无法再获取到数据了。如图是Safari浏览器直接运行http://localhost:8080/JspProject/session_scope_two.jsp的结果:

  我们发现,无法从session中获取值了。因为Safari浏览器的session并没有set书名和作者的值,所以在获取的时候才会是空值。

  我们可以联想一下平日的网购经验,如果通过谷歌浏览器登录淘宝,那么只要登录一次以后,在短时间内即使我们重新开启一个火狐标签,也会以“已登录”的身份访问淘宝;但如果换成IE浏览器,则又需要我们重新登录了。所以网站中的登录功能,就可以通过session来实现。

4) application作用域

  继续上面的讨论,如果想实现这样一个功能“只要在一个页面中增加了属性,那么即使重新换一个新浏览器,也要能访问到该属性值”,该如何实现呢?答案就是applicaton的作用域。

我们再将上例中的作用域,从session改为application,如以下代码:

application_scope_one.jsp

<body><%application.setAttribute("username","admin");application.setAttribute("password","1234");response.sendRedirect("application_scope_two.jsp");%>
</body>

application_scope_two.jsp

<body>书名:<%=application.getAttribute("username") %> <br/>作者:<%=application.getAttribute("password") %>
</body>

  此外,读者可以发现,只要运行过一次application_scope_one.jsp以后,无论是新开一个浏览器标签,或者是更换新的浏览器,直接再运行application_scope_two.jsp,也都能获取到数据。如图是谷歌上执行了application_scope_one.jsp以后,在IE浏览器直接运行application_scope_two.jsp的运行结果:

  即只要是通过application.setAttribute()增加的属性,那么任何浏览器的任何页面都可以获取到该属性值。但是如果将tomcat服务器关闭,application中的属性值就全部消失了。

我们可以利用applicatoin作用域的这一特性,来实现一个网页计数器功能:

webCounterDemo.jsp

 <body><%Integer count = (Integer)application.getAttribute("count");//从application里面获取count值if(count ==  null){//如果是第一次访问,将count赋值为1 count = 1;}else{  //如果不是第一次访问,则累加一次访问次数count = 1 + count; }application.setAttribute("count",count); //将访问次数的变量count保存在application的属性count中out.println("您是第 " + application.getAttribute("count") +" 位访问本网站的用户" );%></body>

  之后,无论是刷新当前页,还是新开一个浏览器标签,或者打开一个其他浏览器再次访问,每访问一次,访问次数就会累加一次。

  需要说明的是,虽然四种作用域的大小依次是pageContext<request<session<application,但我们不能为了方便就随便使用范围较大的范围对象,因为范围越大造成的性能损耗就越大。因此,如果多个作用域都能完成相同的功能,我们一般会使用范围小的那个对象。

2.4 本章练习

一、选择题

1.下列关于HTTP响应中状态码的描述,错误的是( )。(选择一项)

A.3**表示重定向,表示需要客户端采取进一步的操作才能完成请求

B.2**表示成功,表示请求已被成功接收、理解、接受

C.4**表示客户端错误,请求有语法错误或请求无法实现

D.5**表示数据库端错误,服务器未能实现合法的请求

2.下列( )方法可以获取请求的字符编码方式。(选择一项)

A.request.getCharacterEncoding()

B.request.getProtocol()

C.request.getRequestURI()

D.request.getQueryString()

3.请求转发的forward(request,response)方法是( )的方法。(选择一项)

A.request对象

B.response对象

C.RequestDispatcher对象

D.session对象

4.下列( )不是JSP九大内置对象之一。(选择一项)

A.out对象

B.exception对象

C.cookie对象

D.session对象

5.<%page language=”java” import=”java.util.ArrayList;java.sql.*” contentType=”text/html; charset=UTF-8” %>

以上指令共存在()处错误。

A:1

B:2

C:3

D:4

6.以下page指令的描述中,正确的是()。

A:可以通过<%@page include=”java.util.*”%>导入java.util下所有的类

B:可以通过<%@page include=”java.util.Date;java.util”%>导入java.util下所有的类

C:可以通过<%@page contentType=”text/html;charset=UTF-8”%>设置页面编码为UTF-8

D:可以通过<%@page version=”1.6”%>指定采用什么版本的jdk编译页面

7.以下JSP代码的运行结果是()。

A:i8

B:88

C:16

D:编译错误

<%@ page language=”java” contentType=”text/html; charset=UTF-8”%><%
out.println("hello lanqiao");
%>

对于以上代码,描述正确的是()。

A:此段代码没有错误,能够正确向页面打印出“hello,lanqiao!”

B:此段代码没有错误,但是不向页面输出任何语句

C:此段代码缺少引用,应该在page指令中添加import=”java.util.*”

D:此段代码存在错误,应改为:response.out.println(“hello,lanqiao!”);

9.<%@ page __=”text/html; __=UTF-8”%>

使用page指令设置页面的字符集,横线处应填写()。

A:content_Type、charsetEncoding

B:contentType、charset

C:type、charset

D:contentType、pageEncoding

10.<% ing num = 10 ;%>这段代码在JSP中称为()。

A:小脚本

B:表达式

C:JSP注释

D:JSP指令

<%
int[] scores = new int[2]{89,87};
%>
最高分:<% Math.max(scores[0],scores[1]) %>最低分:<% out.print(Math.min(scores[0],scores[1])) %>

以上代码共有()处错误。
A:1

B:2

C:3

D:4

12.以下()不是JSP页面的page指令。

A:language=”java”

B:import=”java.util.*”

C:http-equiv=”keywords”

D:contentType=”text/html; charset=UTF-8”

13.有关会话跟踪技术描述正确的是()
A. Cookie是Web服务器发送给客户端的一小段信息,客户端请求时,可以读取该信息发送到服务器端
B. 关闭浏览器意味着会话ID丢失,但所有与原会话关联的会话数据仍保留在服务器上,直至会话过期
C. 在禁用Cookie时可以使用URL重写技术跟踪会话
D. 隐藏表单域将字段添加到HTML表单并在客户端浏览器中显示

14.在J2EE中,重定向到另一个页面,以下()语句是正确的
A. request . sendRedirect(“http:// www . baidu.com”);
B. request . sendRedirect();
C. response . sendRedirect(“http: // www . baidu.com”);
D. response .sendRedirect();

二、简答题

1.JSP中有几种Scriptlet,各自的作用是什么?

2.JSP中有几种注释,各有什么特点?

3.对于GET请求和POST请求,各如何设置编码?

4.简述pageContext、request、session、application等四个内置对象的作用域范围。

5.简述请求转发与重定向的区别。

6.如何更改Tomcat端口号。

7.简述Session和Cookie的区别。

8.什么情况下会造成“表单重复提交”?如何解决?

三、编程题

1.在一个JSP中提供一组复选框,可以让用户选择自己喜爱的水果,提交后,在另一个JSP页面输出用户的所有选择项。

2.在index.jsp中编写两个输入框,用于接收用户输入的两个数,然后通过表单提交跳转到result.jsp。再在result.jsp中比较判断出较大的数字,并显示。

3.实现以下表单,并在用户单击“注册”后,在另一个JSP中获取各个表单元素的值:


4.<a href=”showStudents.jsp?page=2&size=10”>学生信息,获取超链接中的page、size参数值。

5.demo01.jsp的部分内容如下:

<body><%Student stu = new Student("张三",23);...%>
</body>

将demo01.jsp中的stu对象传递到demo02.jsp。

6.实现登陆功能,要求:在客户端保存用户名,在服务端保存登录信息。

7.禁止从外部网站提交数据(即服务端只接受本项目中传来的数据)。

8.(1)实现以下功能的网页记录器:

(2)实现IP计数器,如下:

统计用户在站点的停留时间,如下:

第二章 Jsp基本语法相关推荐

  1. 使用java实现面向对象编程第二章_java面向对象编程——第二章 java基础语法

    第二章 java基础语法 1.java关键字 abstract boolean break byte case catch char class const continue default do d ...

  2. JavaSE入门0基础笔记 第二章Java基础语法

    JavaSE入门0基础笔记 第二章Java基础语法 1.运算符 1.1算术运算符 1.1.1运算符和表达式 1.1.2 算术运算符 1.1.3字符的"+"操作 1.1.4 字符串中 ...

  3. 【python第一章 基础捋顺,第二章 python基础语法】

    第一章 基础捋顺,第二章 python基础语法 第一章 基础捋顺 第二章 python基础语法 2.1输入输出 2.2代码注释 2.3代码缩进 2.4命名规范 2.5变量 2.6基本数据类型 2.7数 ...

  4. JSP实用教程第二章-JSP语法

    目录 前言 2.1 JSP页面的基本结构 2.2声明变量和定义方法 2.2.1 声明变量 2.22 定义方法和类 2.3Java程序片 2.4Java表达式 2.5 JSP中的注释 2.6 JSP指令 ...

  5. JSP实用教程——第二章:JSP语法

    JSP基本语法 在传统的HTML页面文件中嵌入脚本语言和JSP标签就构成了一个JSP页面文件.一个JSP页面可有5中元素组合而成. HTML页面内容 JSP注释 JSP指令 JSP脚本元素 JSP动作 ...

  6. 尚硅谷Java入门视频教程第二章——Java基本语法

    尚硅谷Java入门视频教程第二章 第一章复习 课后习题 Java语言概述 第2章:Java基本语法 2.1 关键字和保留字 2.2 标识符(Identifier) 2.3 变量 2.3.1 变量基本概 ...

  7. 第二章 疯狂Caché 语法规则

    文章目录 第二章 Caché 语法规则 区分大小写 标识符 Unicode 空格 注释 例程和方法的int代码中的注释 例程和方法的MAC代码中的注释 方法代码之外的类定义中的注释 文字值 字符串文字 ...

  8. JSP实用教程——第二章JSP语法

    目录 2.1 JSP页面的基本结构 2.2 声明变量和定义方法 2.2.1 声明变量 2.2.2 定义方法和类 2.3 Java程序片 2.4 Java表达式 2.5 JSP指令标记 2.5.1 pa ...

  9. Java EE入门教程系列第二章JSP(三)——JSP指令与动作组件

    2.3 指令与动作组件 2.3.1 page指令 page指令的基本语法为: <%@ page 属性1="属性1的值" 属性2="属性2的值"···%&g ...

  10. python基本语法语句-第二章 python基本语法元素

    python有两种编程方式,交互式和文件式. 交互式:对每个输入语句即时运行结果------适合语法练习 文件式:批量执行一组语句并运行结果------编程的主要方式 实例1:圆面积的计算(根据半径r ...

最新文章

  1. android edittext限制字节_android EditText输入限制
  2. python lambda表达式的使用方法(匿名函数)
  3. linux常用操作命令汇总
  4. VUEJS-checkbox全选全不选
  5. android滑动开关框架,Android之实现滑动开关组件
  6. 打榜前10名:天池AI医疗人工智能辅助糖尿病遗传风险预测
  7. kotlin_Kotlin print(),println(),readLine(),Scanner,REPL
  8. CSS 块状元素和内联元素
  9. Struts2常用标签总结
  10. linux tree命令,Linux tree命令实例详解
  11. 电脑录屏怎么录?3个方法,教你如何录制视频
  12. 你的六岁在玩儿泥巴,他们六岁已经在讲算法了
  13. Laravel-Vue开发初探二:Inertia拾遗
  14. 家用洗地机哪款好?家用洗地机好用品牌推荐
  15. 数据中心交换机基础自学系列 | MAC简介
  16. Word处理控件Aspose.Words功能演示:使用Java合并MS Word文档
  17. 【ROCKCHIP瑞芯微芯片平台方案介绍】
  18. ET钱包2月25日早报 | 过去24小时EOS区块链活跃度指数蝉联榜首
  19. 中文分词的python实现-基于FMM算法
  20. 商城项目01 _电商系统基本模式、分布式基础概念、微服务架构图、微服务划分图

热门文章

  1. rgba与16进制互相转换
  2. 代码审计工具Fortify 17.10及Mac平台license版本
  3. h5 兑换商品 页面模版_H5商城静态页面(模板)
  4. UE4保存信息到本地
  5. Gaussian09 optimization trajectory: python script
  6. 分布式对象存储解决方案
  7. 戴口罩人脸数据集和戴口罩人脸生成方法
  8. 平面2R机器人(二连杆)运动学与动力学建模+附仿真模型
  9. uniapp中使用colorUI说明文档
  10. 纪中游记 - Day 3