第二章 Jsp基本语法
本章简介
本章将系统介绍JSP页面元素以及内置对象,其中重点介绍了out
、request
、 response
、session
等常用内置对象以及Cookie等使用,并且从使用原理上讲 解了pageContext
、request
、session
、application
等四种范围对象的作用域。
回顾第一个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()和<%=… >不仅能输出变量,还可解析”<br/>
”等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的<br/>
或者</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.jsp到request_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基本语法相关推荐
- 使用java实现面向对象编程第二章_java面向对象编程——第二章 java基础语法
第二章 java基础语法 1.java关键字 abstract boolean break byte case catch char class const continue default do d ...
- JavaSE入门0基础笔记 第二章Java基础语法
JavaSE入门0基础笔记 第二章Java基础语法 1.运算符 1.1算术运算符 1.1.1运算符和表达式 1.1.2 算术运算符 1.1.3字符的"+"操作 1.1.4 字符串中 ...
- 【python第一章 基础捋顺,第二章 python基础语法】
第一章 基础捋顺,第二章 python基础语法 第一章 基础捋顺 第二章 python基础语法 2.1输入输出 2.2代码注释 2.3代码缩进 2.4命名规范 2.5变量 2.6基本数据类型 2.7数 ...
- JSP实用教程第二章-JSP语法
目录 前言 2.1 JSP页面的基本结构 2.2声明变量和定义方法 2.2.1 声明变量 2.22 定义方法和类 2.3Java程序片 2.4Java表达式 2.5 JSP中的注释 2.6 JSP指令 ...
- JSP实用教程——第二章:JSP语法
JSP基本语法 在传统的HTML页面文件中嵌入脚本语言和JSP标签就构成了一个JSP页面文件.一个JSP页面可有5中元素组合而成. HTML页面内容 JSP注释 JSP指令 JSP脚本元素 JSP动作 ...
- 尚硅谷Java入门视频教程第二章——Java基本语法
尚硅谷Java入门视频教程第二章 第一章复习 课后习题 Java语言概述 第2章:Java基本语法 2.1 关键字和保留字 2.2 标识符(Identifier) 2.3 变量 2.3.1 变量基本概 ...
- 第二章 疯狂Caché 语法规则
文章目录 第二章 Caché 语法规则 区分大小写 标识符 Unicode 空格 注释 例程和方法的int代码中的注释 例程和方法的MAC代码中的注释 方法代码之外的类定义中的注释 文字值 字符串文字 ...
- 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 ...
- Java EE入门教程系列第二章JSP(三)——JSP指令与动作组件
2.3 指令与动作组件 2.3.1 page指令 page指令的基本语法为: <%@ page 属性1="属性1的值" 属性2="属性2的值"···%&g ...
- python基本语法语句-第二章 python基本语法元素
python有两种编程方式,交互式和文件式. 交互式:对每个输入语句即时运行结果------适合语法练习 文件式:批量执行一组语句并运行结果------编程的主要方式 实例1:圆面积的计算(根据半径r ...
最新文章
- android edittext限制字节_android EditText输入限制
- python lambda表达式的使用方法(匿名函数)
- linux常用操作命令汇总
- VUEJS-checkbox全选全不选
- android滑动开关框架,Android之实现滑动开关组件
- 打榜前10名:天池AI医疗人工智能辅助糖尿病遗传风险预测
- kotlin_Kotlin print(),println(),readLine(),Scanner,REPL
- CSS 块状元素和内联元素
- Struts2常用标签总结
- linux tree命令,Linux tree命令实例详解
- 电脑录屏怎么录?3个方法,教你如何录制视频
- 你的六岁在玩儿泥巴,他们六岁已经在讲算法了
- Laravel-Vue开发初探二:Inertia拾遗
- 家用洗地机哪款好?家用洗地机好用品牌推荐
- 数据中心交换机基础自学系列 | MAC简介
- Word处理控件Aspose.Words功能演示:使用Java合并MS Word文档
- 【ROCKCHIP瑞芯微芯片平台方案介绍】
- ET钱包2月25日早报 | 过去24小时EOS区块链活跃度指数蝉联榜首
- 中文分词的python实现-基于FMM算法
- 商城项目01 _电商系统基本模式、分布式基础概念、微服务架构图、微服务划分图