学习要点
- request对象
- response对象
- 转发与重定向
- session对象
- include指令
课程回顾
- 需求描述:编写JSP页面,计算2000—3000年中存在几个闰年。
- 实现分析:判断闰年的算法写在方法boolean leapYear(int year)中。
- 提示:闰年——能够被4整除而不能被100整除,或者能够被400整除。
JSP内置对象
概念
JSP内置对象是 Web 容器加载的一组Servlet API实例,这些实例由JSP规范进行了默认的初始化操作,可以直接在JSP中使用,不需要使用new来创建即可使用的对象,例如out对象。
JSP内置对象
内置对象 |
所属类 |
说明 |
out |
javax.servlet.jsp.JspWriter |
写入页面内容 |
request |
javax.servlet.http.HttpServletRequest |
客户请求 |
response |
javax.servlet.http.HttpServletResponse |
服务器响应 |
session |
javax.servlet.http.HttpSession |
会话 |
application |
javax.servlet.ServletContext |
web程序对象 |
page |
java.lang.Object |
页面实例 |
pageContext |
javax.servlet.jsp.PageContext |
JSP页面 |
config |
javax.servlet.ServletConfig |
配置文件信息 |
exception |
java.lang.Throwable |
异常对象 |
out
out对象向浏览器输出数据,常用方法有:
- print():在页面中显示字符串信息。
- println():在页面中显示字符串信息和换行符。(html页面换行:<br>标签)
request
作用
用于处理客户端请求,是最常用的JSP内置对象,该对象包含了有关浏览器请求的信息。
工作原理
常用方法
方法名称 |
说明 |
String getParameter(String name) |
根据表单组件名称获取提交数据 |
String[ ] getParameterValues(String name) |
获取表单组件对应多个值时的请求数据 |
void setCharacterEncoding(String charset) |
指定每个请求的编码 |
RequestDispatcher getRequestDispatcher(String path) |
返回一个RequestDispatcher对象,该对象的forward( )方法用于转发请求。 |
示例:获取注册页面信息
注册页面示例代码
<form name="myform" method="post" action="doreg.jsp"> <table border="0" align="center"> <tr><td>账号</td><td><input type="text" name="name"></td></tr> <tr><td>密码</td><td><input type="password" name="pwd"></td></tr> <tr><td>授权</td><td><input type="checkbox" name="channel" value="邮箱">邮箱
<input type="checkbox" name="channel" value="微博">微博<br>
<input type="checkbox" name="channel" value="空间">空间
<input type="checkbox" name="channel" value="微信">微信</td> </tr> <tr> <td></td> <td><input type="submit" value="注册"> <input type="reset" value="取消"> </td> </tr> </table> </form>
注册信息处理页面示例代码
String name = request.getParameter("name"); String pwd = request.getParameter("pwd"); //输出用户名密码 out.print("账号:" + name + "<br>"); out.print("密码:" + pwd + "<br>"); //读取复选框选择项 String[] channels = request.getParameterValues("channel"); if (channels != null) { for (String channel : channels) { out.println(channel); } }
乱码问题
表单以POST方法提交
Web容器默认的编码为ISO-8859-1,请求对象request的getParameter()方法得到的字符串是以ISO-8859-1转换而来的。
- 所以在获取请求参数之前,可以设置请求的编码格式:
request.setCharacterEncoding("utf-8");
- 在向浏览器发送数据之前,通过JSP页面设置page指令的contentType属性:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page contentType="text/html; charset=UTF-8"%>
- pageEncoding和contentType的区别:
pageEncoding:JSP文件的字符集以及默认的contentType字符集。
contentType:定义响应的资源类型,包含了JSP页面和响应内容的字符集。
表单以GET方法提交
以GET方式提交的数据作为查询字符串被附加到URL的末端发送到服务器。这个时候在服务器端采用setCharacterEncoding()方法将失去作用。因为浏览器缺省对URL后面的参数是不编码发送的,但是Tomat缺省是按ISO8859-1来进行URL编码的(tomcat8以上版本默认采用UTF-8编码)。
- 因此在接收到数据后需要重新编码
String name = request.getParameter("name"); name=new String(name.getBytes("ISO-8859-1"),"UTF-8");
//不推荐使用java.net.URLDecoder.decode
- 修改Tomcat对URL的编码
在tomcat目录下的confserver.xml文件中,在<Connector>元素中添加URIEncoding属性,将其值设置为“UTF-8”。示例:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
- 注意:修改了tomcat对url的编码后,无需再使用new String()对接收到的数据重新编码,否则会再次变成乱码。new String()方法适用于无法修改服务器配置、参数少的情况。如果tomcat服务器允许修改,则修改tomcat的配置。
上机练习
- 制作QQ注册页面如下图所示
- 通过表单提交注册信息
- 在提交信息处理页面使用request对象获取表单提交的数据
- 将获取的数据输出在浏览器中显示
request其他方法
获得客户端信息
- getRequestURL():返回客户端发出请求时的完整URL。
- getRequestURI():返回请求行中的资源名部分。
- getQueryString ():返回请求行中的参数部分。
- getPathInfo():返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
- getRemoteAddr():返回发出请求的客户机的IP地址。
- getRemoteHost():返回发出请求的客户机的完整主机名。
- getRemotePort():返回客户机所使用的网络端口号。
- getLocalAddr():返回WEB服务器的IP地址。
- getLocalName():返回WEB服务器的主机名。
获得客户端请求头
- String getHeader(string name):获取单个请求头name对应的value值
- Enumeration getHeaders(String name):获取多个同名请求头对应的一组value值,因此返回枚举类型数据
- Enumeration getHeaderNames():获取请求头的所有name值,返回的数据也是一个枚举类型的数据,将枚举中的元素依次遍历出来,根据name获取对应的value值,即可得到Http请求头的所有信息
response
作用
响应客户请求并向客户端输出信息。
工作原理
常用方法
方法名称 |
说明 |
void addCookie(Cookie cookie) |
在客户端添加cookie |
void setContentType(String type) |
设置HTTP响应的contentType类型 |
void setCharacterEncoding(String charset) |
设置响应所采用的字符编码类型 |
void sendRedirect(String location) |
将请求重新定位到一个新的URL上 |
示例:登陆
构建了三个页面:login.jsp,dologin.jsp,welcome.jsp
其中登陆处理页面关键代码:
if("admin".equals(name)&&"admin".equals(pwd)){ response.sendRedirect("welcome.jsp"); }
问题:能否在welcome.jsp页面获得登陆用户名?如何解决?
解决:使用转发取代重定向实现页面跳转。
关键代码:
//将当前接收的用户请求,发送给服务器的其他资源使用 RequestDispatcher rd=request.getRequestDispatcher("welcome.jsp"); rd.forward(request,response);
转发和重定向
转发 |
重定向 |
转发是在服务器端发挥作用,通过forward()将提交信息在多个页面间进行传递。 |
重定向是在客户端发挥作用,通过请求新的地址实现页面转向。 |
客户端浏览器的地址栏不会显示出转向后的地址。 |
在地址栏中可以显示转向后的地址。 |
重定向的应用
超链接中使用重定向技术实现数传递。
- 选择喜欢的颜色,服务器如何读取颜色信息?
<a href="like.jsp?clor=蓝色">蓝色</a>
- 在邮件收件箱中,有一封邮件的超链接如下,服务器如何识别是哪一封邮件以及如何判断邮件的读取状态?
<a href="email.jsp?id=1008&read=0">新邮件</a>
- 服务器读取信息方式:GET方式读取
response其他方法
- addDateHeader(String name ,long date):向客户端添加一个时间值属性的响应头信息。
- addHeader(String name,String value):向客户端添加一个字符串值属性的响应头信息。
- addIntHeader(String name ,int value):向客户端添加一个字符串属性的响应头信息。
- containsHeader(String name):判断是否含有指定响应头信息字段。
- encodeURL(String name):用于url改写的功能的。
- setHeader(String name,String value)/setIntHeader(String name,int value)/setDateHeader(String name,long date):和addHeader方法是相对应的,唯一和addHeader不同的是,addHeader是向Response中添加一个响应头信息,而setHeader是修改一个响应头信息的。
- setStatus(int value):设置响应状态码,比如:200,304,404等。
- getOutputStream():获取一个字节流,然后可以向Response容器中写入字节数据,最后客户端从Response获取数据并显示。
- getWriter():获得一个字符流(PrintWriter),然后可以向Response容器中写入字符数据,最后客户端从Response获取数据进行显示。
- setContentLength():设置服务器向客户端返回的数据长度。
- setContentType():设置响应头content-type。
上机练习
实现网站邮箱登录验证功能
- 用户通过JSP页面输入用户名和密码,用户名为邮箱
- 如果用户名为tom@qq.com,密码为123456,在欢迎页面显示“你好:tom!”
- 如果验证登录失败,则返回登录页面重新登录
参考代码
控制器:
<%@page import="java.net.URLEncoder"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String account = request.getParameter("account").trim().toLowerCase();//账号 String pwd = request.getParameter("pwd").trim();//密码 if ("admin".equals(account) && "123".equals(pwd)) { RequestDispatcher rd = request.getRequestDispatcher("welcome3.jsp"); rd.forward(request, response); } else { //重定向传参 String message = "账号密码错误"; message = URLEncoder.encode(message, "UTF-8"); response.sendRedirect("login3.jsp?mess=" + message); //转发传参 //request.setAttribute("mess", "账号密码错误"); //request.getRequestDispatcher("login3.jsp").forward(request, response);//转发登录错误信息 } %>
视图参考代码
<form action="dologin3.jsp" method="post"> <p>账号:<input type="text" name="account"><span style="color:red;"><%=request.getParameter("mess")==null?"":request.getParameter("mess")%></span></p> <p>密码:<input type="password" name="pwd"></p> <p><input type="submit" value="登录"></p> </form>
session
无状态访问协议
协议的状态是指下一次传输可以“记住”这次传输信息的能力。
http是不会为了下一次连接而维护这次连接所传输的信息,为了保证服务器内存。
比如客户获得一张网页之后关闭浏览器,然后再一次启动浏览器,再登陆该网站,但是服务器并不知道客户关闭了一次浏览器。
会话
一次会话就是用户通过浏览器和服务器之间进行的多次请求、响应的过程。
JSP提供了session内置对象允许用户存储和提取会话状态信息。
session对象
- session是一种服务器端的机制,在服务器端使用类似于散列表(也称为哈希表,采用K-V方式进行数据的存储和访问)的结构保存信息。
- 当服务器接收到客户端的请求时,服务器首先判断客户端是否已经创建了session对象,如果已经创建,就利用这个session对象存储用户状态信息。如果没有创建,则创建session对象。
- 服务器端判断是否已经创建了session对象,是通过session对象的唯一标识sessionid来实现的。如果客户端请求包含了一个sessionid,服务器则判断已经给这个客户端创建了session对象,服务器就根据这个sessionid把session对象读取出来;否则就重新创建session对象,并生成一个与此session对象对应的sessionid,然后将sessionid响应给客户端保存。
- 客户端将sessionid保存在cookie中,保存sessionid的键名称是JSESSIONID,值是一窜复杂的字符串组成。
session对象常用方法
方法名称 |
说明 |
void setAttribute(String key,Object value) |
以key/value的形式保存对象值 |
Object getAttribute(String key) |
通过key获取对象值 |
void invalidate() |
设置session对象失效 |
String getId() |
获取sessionid |
void setMaxInactiveInterval(int interval) |
设定session的非活动时间 |
int getMaxInactiveInterval() |
获取session的有效非活动时间(以秒为单位) |
void removeAttribute(String key) |
从session中删除指定名称(key)所对应的对象 |
示例1:获取sessionid
- 在createSession.jsp页面中,关键代码:
session.setAttribute("test", "hello"); response.sendRedirect("getSessionId.jsp");
- 在getSessionId.jsp页面中,关键代码:
out.print("sessionid:"+session.getId());
- 在IE浏览器中输出结果和调试:
示例2:使用session实现访问控制
访问流程一:
访问流程二:
关键代码一:保存用户登录信息
//设置用户登录信息 session.setAttribute("login", name); //设置session过期时间 session.setMaxInactiveInterval(5);
关键代码二:页面访问权限控制
String login = (String) session.getAttribute("login"); if (login == null){ response.sendRedirect("index.jsp"); return; }
上机练习:实现新闻发布系统的访问控制
- 新闻发布系统只允许管理员进入后台操作页面。
- 普通用户只能浏览新闻和发布评论的权限。
- 数据库驱动拷贝到WEB-INF/lib中
- 系统采用三层架构:数据访问层、业务逻辑层、表示层。
- JSP作为系统表示层。
session对象的失效
- 超时失效
通过setMaxInactiveInterval( )方法,单位是秒
session.setAttribute("username","admin"); session.setMaxInactiveInterval(600); response.sendRedirect("admin.jsp");
通过设置项目的web.xml或Tomcat目录/conf/web.xml 文件,单位是分钟。
<session-config> <session-timeout>10</session-timeout> </session-config>
- 手动失效:invalidate()
手动失效主要用在注销场合,如果只是想清空session中的某个对象,则可以调用session.removeAttribute(String key)的方法,清除指定对象。保留session。
include指令
如果商城系统中有很多的二级页面同样需要权限控制,如果在不同功能的页面编写以下代码便可以实现,但是如何解决代码重复的问题?
String login = (String) session.getAttribute("login"); if (login == null){ response.sendRedirect("index.jsp"); return; }
解决方案:编写一个权限控制JSP文件,把权限控制代码放在其中,然后再需要使用权限控制页面引用它即可。
如何引入?
<%@ include file="文件路径" %>
例如:
<%@ include file="control.jsp" %> <!-- 引入权限控制文件 -->
上机练习:新闻发布系统的页面采用include指令重构
需求描述:
- 静态模型采用的是iframe进行页面的重用。在JSP中所有页面对iframe进行修改,改为include指令。
- 修改完成后检测每个链接的跳转是否正常。