一. HTTP协议

1.1 HTTP协议概念

·HTTP协议(HyperText Transfer Protocol,超文本传输协议)是由W3C(万维网联盟)组织制定的一种应用层协议,是用来规范浏览器与Web服务器之间如何通讯的数据格式,主要涉及浏览器的发请求格式和服务器的响应格式
·HTTP协议通常承载于TCP协议之上,而承载于TLS或SSL协议层之上的协议就是常说的HTTPS协议
Servlet_02 - 图5·HTTP默认的端口号为80,HTTPS默认的端口号为443

1.2 HTTP请求的格式

客户端发送一个HTTP请求, 请求的数据格式主要包括:请求行、请求头、和请求体
·请求行
作用: 用来说明请求类型和要访问的资源以及所使用的HTTP版本
格式: 请求类型 请求的路径 协议的版本(1.1)
·请求头
作用: 用来说明服务器要使用的附加信息
格式: 格式 (key:value)如下: 主机 请求长度
·请求体
作用: 客户端传递给服务器的数据
格式: 比如:表单使用post方式提交的数据、上传文件数据等
例如:

POST /servlet_demo01/login.html HTTP/1.1
Host: localhost:8088
Content-Length: 21
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)
name=scott&pwd=123456

1.3 HTTP响应的格式

通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息,主要包括:响应行、响应头、响应体
·响应行
作用: 用来说明HTTP协议版本号和状态码以及状态消息
格式: 协议的版本(1.0 1.1) 状态码 (200 成功 404 路径错误 500 服务错误) 状态信息
·响应头
作用: 用来说明客户端要使用的一些附加信息
格式: 格式(key:value)
·响应体
作用: 用来服务器返回给客户端的文本信息
例如:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 588
Date: Thu, 08 Sep 2021 12:59:54 GMT

M/head>

这是一个页面

1.4 HTTP协议特点

·短连接(HTTP/1.1支持长连接)
http特点: http/1.1版本之前都是短链接 (发送请求, 响应回来 结束)
每次请求一次,释放一次连接。所以无连接表示每次连接只能处理一个请求。优点就是节省传输时间,实现简单。我们有时称这种无连接为短连接。对应的就有了长链接,长连接专门解决效率问题。当建立好了一个连接之后,可以多次请求。但是缺点就是容易造成占用资源不释放的问题。当HTTP协议头部中字段Connection:keep-alive表示支持长链接
·无状态
HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。为了解决HTTP协议无状态,于是,两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,而另一个则是Session

二. Servlet中常用的对象

2.1 ServletRequest对象

1) 基本概念
·javax.servlet.ServletRequest对象主要用于向servlet提供客户端请求信息,可以从中获取到任何请求信息
·Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法
Servlet_02 - 图62) 常用方法

2.2 HttpServletRequest对象

1) 基本概念
·javax.servlet.http.HttpServletRequest对象是ServletRequest接口的子接口,主要用于提供HTTP 请求信息的功能
·发送HTTP请求时,HTTP请求头直接由浏览器设置
·可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据
2) HttpServletRequest对象的生命周期
当有请求到达Tomcat时,Tomcat会创建HttpServletRequest对象,并将该对象通过参数的方式传递到我们Servlet的方法中,当处理请求处理完毕并产生响应后该对象生命周期结束
3) 常用方法
·获取请求信息(如: 请求的项目名, 请求方式, 请求协议类型等)
·获取请求头信息
·获取请求数据(发送请求携带的参数)
4) 使用示例
获取请求信息

@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
String contextPath = req.getContextPath();//请求的项目名
_String method = req.getMethod**
()**;//请求方式
String scheme = req.getScheme**()**;//请求协议类型
String protocol = req.getProtocol**()**;//请求协议类型/版本号
StringBuffer requestURL = req.getRequestURL**()**;//请求的完整URL
String requestURI = req.getRequestURI**()**;//请求行中指定资源部分
String remoteAddr = req.getRemoteAddr**()**;//请求客户机的IP地址
String localAddr = req.getLocalAddr**()**;//请求WEB服务器的IP地址
int localPort = req.getLocalPort**()**;//请求WEB服务器的端口**}_**

获取请求头信息

protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//根据请求头中的 key 获取 value
_String header = req.getHeader**
(“Connection”);
System.
_out
.println(header);
System.
out.println(“—————“);
_//获取所有请求头中的key
_Enumeration
<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()){
__
_//获取每一个key
_String key = headerNames.nextElement
();
_// 根据key 或取 values
_String value = req.getHeader
(key);
System.
out.println(key + “: “+ value);
}
__}
**

获取请求数据

  1. 获取的参数值只有一个(如: 用户名, 密码, 生日, 单选框, 下拉列表, 大文本框) | String p = req.getParameter(“参数名”); | | —- |

2) 获取的参数值大于一个(如: 复选框)

String[] ps = req.getParameterValues(“参数名”);

3) 获取所有的参数名

Enumeration<String> parameterNames = req.getParameterNames();

html

<_form action=”servlet1” method=”get”>
_
姓名:<_input type=”text” name=”username” value=”aaa”/><_br_>
_
爱好:
<_input type=”checkbox” name=”hobby” value=”1”/>_篮球
<_input type=”checkbox” name=”hobby” value=”2”/>_足球
<_input type=”checkbox” name=”hobby” value=”3”/>_音乐
<_input type=”checkbox” name=”hobby” value=”4”/>_看书
<_input type=”checkbox” name=”hobby” value=”5”/>_看报纸
<_br/>
_
星期
<_input type=”radio” name=”week” value=”1”/>_
<_input type=”radio” name=”week” value=”2”/>_
<_input type=”radio” name=”week” value=”3”/>_
<_input type=”radio” name=”week” value=”4”/>_
<_input type=”radio” name=”week” value=”5”/>_
<_input type=”radio” name=”week” value=”6”/>_
<_input type=”radio” name=”week” value=”7”/>_
<_br/>
_
籍贯:
<_select name=”pro”>
_ <_option value=”1”>_
吉林</_option>
_ <_option value=”2”>_
黑龙江</_option>
_ <_option value=”3”>_
辽宁</_option>
_ <_option value=”4”>_
内蒙古</_option>

<_br_>
_
介绍
<_textarea name=”introduce” >_aaa</_textarea>
<_input type="submit" value="提交数据"_>
_

Servlet

public class TestServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException { //设置请求编码 req.setCharacterEncoding(“utf-8”); //获取用户名
_String username = req.getParameter**
(“username”)**;
//获取爱好
String**[] hobbies = req.getParameterValues(“hobby”)**;
//获取星期
String week = req.getParameter**(“week”)**;
//获取省份
String pro = req.getParameter**(“pro”)**;
//获取自我介绍
String introduce = req.getParameter**(“introduce”)**;
//获取所有的参数名
Enumeration**<_**String**_> parameterNames = req.getParameterNames();
while
(parameterNames.hasMoreElements()){
String key = parameterNames.nextElement();
String value = req.getParameter
(key);
System.
_out
.println(key+“: “+value);
_}
}
_}**

2.3 ServletResponse对象

1) 基本概念
· javax.servlet.ServletResponse对象用于定义一个对象 向客户端发送响应
· Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法, 在service方法中借助该对象完成向客户端的响应

Servlet_02 - 图72.4 HttpServletResponse对象

1) 基本概念
· javax.servlet.HttpServletResponse接口用于定义一个对象向客户端发送响应
· Servlet容器创建HttpServletResponse对象,并将其作为参数传递给servlet的service方法, 在service方法中借助该对象完成Http请求的客户端响应
Servlet_02 - 图82) 常用方法

3) 使用示例

protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应的编码格式
_resp.setCharacterEncoding**
(“utf-8”);
resp.setContentType
(“text/html;charset=utf-8”)**;
//获取响应输出流
PrintWriter writer = resp.getWriter**()**;
//输出html页面
writer.println**(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(

你好啊!

);
writer.println
(““);
writer.println
(““);}_**

2.5 ServletConfig对象

1) 基本概念
· javax.servlet.ServletConfig对象用于描述Servlet本身的相关配置信息,在初始化期间用于将信息传递给Servlet配置对象
Servlet_02 - 图9· 在Servlet中通过this.getServletConfig()方法可以父类中获得ServletConfig对象
2) 常用方法

3) 使用示例
web.xml

<_servlet>
_ <_servlet-name>_
servlet4</_servlet-name>
_ <_servlet-class>_
com.bjsxt.servlet.TestServlet</_servlet-class>
<_init-param_>
<_param-name_>_
username</_param-name>
<_param-value_>zs


<_servlet-mapping_>
_ <_servlet-name>_
servlet4</_servlet-name>
_ <_url-pattern>_
/testServlet</_url-pattern>
_</_servlet-mapping>_

servlet

public class TestServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//从父类中获取ServletConfig对象
_ServletConfig servletConfig = this.getServletConfig**
()**;
//获取当前servlet的初始化参数
String username= servletConfig.getInitParameter**(“username”)**;
//设置响应的编码格式
resp.setCharacterEncoding**(“utf-8”);
resp.setContentType
(“text/html;charset=utf-8”)**;
//获取响应输出流
PrintWriter writer = resp.getWriter**()**;
//输出
writer.println**(“获取当前servlet的初始化参数 username: “+ username);
}
_}**

2.6 ServletContext对象

1) 基本概念
· javax.servlet.ServletContext对象主要用于定义一组方法,Servlet使用这些方法与它的Servlet容器通信
· 服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象,用于实现多个Servlet之间的信息共享和通信
· 在Servlet中通过this.getServletContext()方法可以父类中获得ServletContext对象
2) ServletContext对象生命周期
当容器启动时会创建ServletContext对象并一直缓存该对象,直到容器关闭后该对象生命周期结束。ServletContext对象的生命周期非常长,所以在使用全局容器时不建议存放业务数据, 存放的数据为整个项目需要共享的数据
Servlet_02 - 图103) 常用方法

4) 使用示例
web.xml

<_context-param>
_ <_param-name>_
charset</_param-name>
_ <_param-value>_
utf-8</_param-value>
_</_context-param>_

servlet(当前项目中所有的servlet共享)

protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//从父类中获取ServletContext对象
_ServletContext servletContext = this.getServletContext**
()**;
//获取全局初始化参数
String charset = servletContext.getInitParameter**(“charset”)**;
//设置响应编码格式
resp.setCharacterEncoding**(charset);
resp.setContentType
(“text/html;charset=”+charset)**;
//获取响应输出流
PrintWriter writer = resp.getWriter**()**;
//输出
writer.println**(“获取当前项目共享的初始化参数 charset: “+ charset);}_**

2.7 常见对象总结

  1. HttpServletRequest对象:

作用:
专门处理Http的请求

  1. 可以获取请求相关参数(请求数据[参数], 请求信息, 请求头信息)
  2. 可以存储数据, 获取存储的数据(一次请求有效)

发送请求开始, 响应结束 一次请求
setAttribute(key,value) getAttribute(key)
3. 可以完成请求的转发
生命周期: 当有请求到达Tomcat时,Tomcat会创建HttpServletRequest对象,并将该对象通过参数的方式传递到我们Servlet的方法中,当处理请求处理完毕并产生响应后该对象生命周期结束

  1. HttpServletResponse对象:

作用:
向客户端发送响应
1. 可以向页面响应内容
2. 可以完成请求的重定向
3) ServletContext对象:
作用:
实现多个Servlet之间的信息共享和通信, 一个项目只有一个ServletContext对象, 所有servlet都共享该对象

  1. 可以获取全局初始化参数(当前项目共享) getInitParameter(key)
  2. 可以存储数据, 获取数据(当前项目共享)

setAttribute(key,value) getgetAttribute(key)
4) ServletConfig对象:
作用: 描述Servlet本身的相关配置信息
1. 可以获取当前Servlet的初始化参数(当前Servlet有效)

三. 请求转发和重定向

3.1 请求转发

3.1.1转发的概述
· 一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续处理,服务器内部跳转, 转发的各个组件会共享Request和Response对象
Servlet_02 - 图11
3.1.2 转发的特点
· 转发之后浏览器地址栏的URL不会发生改变
· 转发过程中共享Request对象(一次请求有效)
· 转发的URL不可以是其它项目工程
3.1.3转发的实现
Servlet_02 - 图12

3.1.4案例
·需求1
访问AServelt, 在AServelt中将请求转发到BServlet, 实现使用request对象传数据
·需求2

  1. 在queryServlet中查询所有的用户(模拟数据库查询)
  2. 将所有用户的集合存储到request对象中
  3. 跳转到showServlet
  4. showServlet将用户集合进行遍历, 把每一个用户信息通过响应输出流, 输出到浏览器(输出html页面)

·思路分析

  1. 访问queryServlet
  2. queryServlet中查询所有用户(模拟查询数据库), 将用户集合设置到request对象 中 req.setAttribute(key,value)
  3. 需要传递数据, 使用请求转发

将请求转发到showServelt req.getRequestDispather.forward(req,resp)

  1. showServlet中获取用户集合并遍历用户集合, 将每一条用户信息通过响应输出流 输出到浏览器(输出html)

代码实现
QueryServlet

/查询数据的Servlet/public class QueryServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.获取在loginServlet中通过request对象存储的username
String username = **(String) req.getAttribute(“username”)**;
//2.模拟数据库查询
User zs = new User**(1, “zs”, “111111”, 18);
User ls =
new User
(2, “ls”, “111111”, 19);
User ww =
new User
(3, “ww”, “111111”, 20);
ArrayList
<_**User**_> list = new ArrayList<>();
list.add
(zs);
list.add
(ls);
list.add
(ww)**;
//3.将数据存储到request对象中(一次请求有效)
req.setAttribute**(“list”, list)**;
//4.请求转发到ShowServlet(转发到向浏览器响应数据的Servlet) 共享request对象
req.getRequestDispatcher**(“/showServlet”).forward(req, resp);
}
_}**

ShowServlet

/向浏览器响应数据的Servlet/public class ShowServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//1.获取request对象中存储的值(list)
_List**
<_**User**_> list = (List<_**User**_>) req.getAttribute(“list”)**;
//2.获取响应输出流
PrintWriter writer = resp.getWriter**();
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
for
(User user : list) {
writer.println(“编号: “+user.getId()+“用户名: “+user.getName()+“密码: “+user.getPassword()+“年龄: “+user.getId());
writer.println
(
);
}
writer.println(登出);
writer.println
(““);
writer.println
(““);
}
_}**

web.xml


<_servlet>
_ <_servlet-name>_
queryServlet</_servlet-name>
_ <_servlet-class>_
com.bjsxt.servlet.QueryServlet</_servlet-class>

<_servlet-mapping_>
_ <_servlet-name>_
queryServlet</_servlet-name>
_ <_url-pattern>_
/queryServlet</_url-pattern>
_</_servlet-mapping>_

<_servlet>
_ <_servlet-name>_
showServlet</_servlet-name>
_ <_servlet-class>_
com.bjsxt.servlet.ShowServlet</_servlet-class>

<_servlet-mapping_>
_ <_servlet-name>_
showServlet</_servlet-name>
_ <_url-pattern>_
/showServlet</_url-pattern>
_</_servlet-mapping>_

3.2 重定向

3.2.1重定向概述
·首先客户端浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客 户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location 地址,服务器根据此请求寻找资源并发送给客户
Servlet_02 - 图13

3.2.2重定向的特点
·重定向之后,浏览器地址栏的URL会发生改变。
·重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象。
·重定向的URL可以是其它项目工程。
3.2.3重定向的实现
Servlet_02 - 图14·实现重定向需要借助javax.servlet.http.HttpServletResponse接口中的以下方法:

注意事项:
重定向的路径必须为 /项目名+/资源名
3.2.4案例
·需求1: 访问CServlet, 在CServlet中重定向到DServlet, 响应输出一句话
由CServlet重定向到DServlet, 地址栏发生变化(两次请求), 不能使用request传递参数
·需求2: 用户访问登录页面
用户名或密码错误, 响应输出一句话 登录失败
用户名和密码正确, 跳转到queryServlet查询所有用户, 跳转到showServlet向浏览器输出每一条用户信息(输出 html)
·思路分析:

  1. 用户名密码正确, 重定向到queryServlet(不需要传递任何数据)
  2. queryServlet和showServlet处理过程和上个案例相同
  3. (回顾)queryServlet将用户集合设置到request对象, 请求转发到showServlet(需要传递数据), 响应输出用户的每一条信息

代码实现

/登录的Servlet/public class LoginServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.接受请求参数 username passwrod
String username = req.getParameter**(“username”);
String password = req.getParameter
(“password”);
System.
_out
.println(username+“—-“+password);
_//2.模拟数据库查询判断
_PrintWriter writer = resp.getWriter
(); //获取响应流
if(“zs”.equals(username) && “111”.equals(password)){
__
_//3.重定向到queryServlet (重定向需要 /项目名/资源名)
_resp.sendRedirect
(“/servletdemo/queryServlet”);
}else{
**//3.响应
writer.println**(“登录失败”);
}
}
_}**

web.xml

<_servlet>
_ <_servlet-name>_
loginServlet</_servlet-name>
_ <_servlet-class>_
com.bjsxt.servlet.LoginServlet</_servlet-class>

<_servlet-mapping_>
_ <_servlet-name>_
loginServlet</_servlet-name>
_ <_url-pattern>_
/loginServlet</_url-pattern>
_</_servlet-mapping>_

3.3 转发和重定向的总结

Servlet_02 - 图15·请求转发(需要传递数据 如: 查询):
请求转发一次请求,Tomcat服务器内部的行为,共享同一个Request对象
一次请求就将用户的需求完整的处理完毕。 一般用户发起的查询功能会使用请求转发来完成请求的处理以及结果的响应。而增,删,改的请求,因为请求转发的地址栏信息是不改变的,容易造成用户刷新一次页面就重新增,删,改了一次(造成表单重复提交)
·重定向(不需要传递数据 如: 增,删,改):
多次次请求,地址栏改变,经常处理增,删,改的请求, 增删改请求处理完, 一般不需要响应任何的数据
可以保护第一次的请求,避免用户因为刷新页面造成数据的重复提交

  1. Servlet线程安全

线程不安全, 只会实例化一次, 默认第一次被调用, load-on-startup配置tomcat启动时servlet创建
1) 服务器在收到请求之后,会启动一个线程来进行相应的请求处理
2) 服务器为每个Servlet只创建一个实例。 当多个请求访问同一个Servlet时,有多个线程访问同一个Servlet对象,使用成员变量会出现线程安全问题, 所以尽量使用局部变量

四. 状态管理

·Web程序基于HTTP协议通信,而HTTP协议是”无状态”的协议,一旦服务器响应完用户的请求之后,就断开连接,而同一个用户的下一次请求又会重新建立网络连接
·服务器程序有时是需要判断是否为同一个用户发出的请求,比如用户的多次选购商品, 因此,有必要跟踪同一个用户发出的一系列请求
·把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理
·多次交互的数据状态可以在客户端保存,也可以在服务器端保存
·状态管理主要分为以下两类:
客户端管理:将状态保存在客户端。基于Cookie技术实现
服务器管理:将状态保存在服务器端。基于Session技术实现

  1. Cookie技术

    4.1 Cookie概念

    ·Cookie本意为饼干的含义,在这里表示客户端以“key-value”形式进行保存的技术
    ·浏览器向服务器发送请求时,服务器将数据以Set-Cookie消息头的方式响应给浏览器,然后浏览器会将这些数据保存起来
    ·当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器

    4.2 Cookie相关方法

    Servlet_02 - 图166.2.1 设置cookie并响应给客户端

Servlet_02 - 图176.2.2 获取请求中的Cookie

Servlet_02 - 图184.3 Cookie的生命周期

4.4 Cookie的路径问题

Servlet_02 - 图19

4.5 Cookie的特点

Cookie技术不适合存储所有数据,程序员只用于存储少量、非敏感信息,原因如下:

  1. 将状态数据保存在浏览器端,不安全
  2. 保存数据量有限制,大约4KB左右
  3. 只能保存字符串信息
  4. 可以通过浏览器设置为禁止使用

    4.6 案例

    需求1:
    访问servlet, 在servlet中向浏览器添加cookie, 并设置生存的时间以及作用范围, 通过响应输出流输出 测试cookie已经创建
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//1.创建Cookie并设置值
_Cookie cookie = new Cookie**
(“testCookie”, “myCookie”)**;
//2.设置作用范围 /整个项目有效 aServlet 只有AServelt有效
cookie.setPath**(“/“)**;
//3.设置存货时间 单位为秒
cookie.setMaxAge**(60)**;
//4.将Cookie添加到响应对象
resp.addCookie**(cookie)**;
//4.通过响应输出流输出
resp.getWriter**().println(“测试cookie已经创建”);}_**

需求2:
重定向案例基础上, 实现记住哪个人查询了数据

思路分析:

  1. 登录成功后, 记录哪个人查询了数据
  2. 将登录成功的用户信息添加到Cookie, 并将Cookie响应到浏览器保存
  3. 访问查询时, 请求中携带着用户信息的Cookie
  4. 将Cookie中的用户信息取出

LoginServlet

/登录的Servlet/public class LoginServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.接受请求参数 username passwrod
String username = req.getParameter**(“username”);
String password = req.getParameter
(“password”)**;
//2.模拟数据库查询判断
PrintWriter writer = resp.getWriter**()**; //获取响应流
**if(“zs”.equals(username) && “111”.equals(password)){
**//3.将登陆成功的用户信息添加到Cookie
Cookie cookie = new Cookie**(“username”, username);
//4.将Coookie添加到resp中
resp.addCookie
(cookie)**;
//5.重定向到queryServlet 重定向需要 /项目名/资源名
resp.sendRedirect**(“/servlet_demo/queryServlet”);
}else{
**//3.响应
writer.println**(“登录失败”);
}
}
}_**

QueryServlet

/查询数据的Servlet/public class QueryServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.取出Cookie中的所有数据
Cookie**[] cookies = req.getCookies();
for
(Cookie cookie : cookies) {
**//2.获取Cookie中的所有key
String name = cookie.getName**();
System.
_out
.println(name);
//3.取出key为username的值
if(“username”.equals(name_)){
System._out.println(“username: “+cookie.getValue()+“查询了数据”);
}
__ }
_//4.模拟数据库查询
_User zs =
new User(1, “zs”, “111111”, 18);
User ls =
new User(2, “ls”, “111111”, 19);
User ww =
new User(3, “ww”, “111111”, 20);
ArrayList
<User> list = new ArrayList<>();
list.add
(zs);
list.add
(ls);
list.add
(ww);
_//5.将数据存储到request对象中(一次请求有效)
_req.setAttribute
(“list”, list);
_//6.请求转发到ShowServlet(转发到向浏览器响应数据的Servlet) 共享request对象
_req.getRequestDispatcher
(“/showServlet”).forward(req, resp);
}
__}
**

ShowServlet

向浏览器响应数据的Servlet/public class ShowServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//1.获取request对象中存储的值(list)
_List**
<_**User**_> list = (List<_**User**_>) req.getAttribute(“list”)**;
//2.获取响应输出流
PrintWriter writer = resp.getWriter**();
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
writer.println
(““);
for
(User user : list) {
writer.println(“编号: “+user.getId()+“用户名: “+user.getName()+“密码: “+user.getPassword()+“年龄: “+user.getId());
writer.println
(
);
}
writer.println(登出);
writer.println
(““);
writer.println
(““);
}
_}**

web.xml

//…
<_url-pattern>_/loginServlet</_url-pattern>_
//…
<_url-pattern>_/queryServlet</_url-pattern>_
//…
<_url-pattern>_/showServlet</_url-pattern>_

五. HttpSession技术

5.1 HttpSession概念

·Session本意为”会话”的含义,是用来维护一个客户端和服务器关联的一种技术
·浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一个Session对象,该对象有一个id属性且该值唯一,我们称为SessionId,并且服务器会将这个 SessionId以Cookie方式发送给浏览器存储
·浏览器再次访问服务器时会将SessionId发送给服务器,服务器可以依据SessionId查找相对应的Session对象

Servlet_02 - 图205.2 HttpSession相关方法

Servlet_02 - 图21


5.3 HttpSession实现原理

HttpSession对象的创建是通过request.getSession()方法来创建的。 客户端浏览器在请求服务端资源时,如果在请求中没有JSESSIONID,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个JSESSIONID,在响应中通过Cookie写回给客户端浏览器,如果在请求中包含了JSESSIONID,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象,因为 jsp 里有内置对象,内置对象就是和 Server 交互的产物,所以如果你的首页是个 jsp 页的话, 即便没有HttpServletRequest.getSession(true),Session 也会创建

Servlet_02 - 图225.4 HttpSession的生命周期

Servlet_02 - 图23
Servlet_02 - 图24

5.5 HttpSession的特点

·数据比较安全
·能够保存的数据类型丰富,而Cookie只能保存字符串
·能够保存更多的数据,而Cookie大约保存4KB
·数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能

5.6 案例

需求1:
访问servlet, 在servlet中获取session, 显示sessionId, 是否为新创建的session, session的存活时间

protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//1.获取session(session不存在创建新的session, sessionId会添加到Cookie
存在根据JSEESIONID获取对应的session)
_HttpSession session = req.getSession**
()**;
//2.获取session的唯一标识(JSEESIONID)
String id = session.getId**();
System.
_out
.println(“JSessionId: “+id);
//3.session是否为新创建
boolean aNew = session.isNew();
System.
out.println(“session是否为新创建: “+aNew);
_//4.向session中设置数据
_session.setAttribute
(“username”,“zs”);
_//5.通过响应输出流, 输出一句话
_resp.getWriter
().println(“Hello!”);
}**

需求2:
重定向案例基础上, 实现记住哪个人查询了数据

思路分析:
1. 登录成功后, 记住哪个人查询了数据
2. req.getSession()
session不存在, 创建session, 并会自动将JSessionId存储到Cookie
session存在, 会自动根据请求中的JSessionId获取对应的session

  1. 将登录成功的用户信息添加到session
  2. 访问查询时, 根据JSESSIONID获取对应的session
  3. 将session中的用户信息取出

LoginServlet

/登录的Servlet/public class LoginServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.接受请求参数 username passwrod
String username = req.getParameter**(“username”);
String password = req.getParameter
(“password”)**;
//2.模拟数据库查询判断
PrintWriter writer = resp.getWriter**()**; //获取响应流
**if(“zs”.equals(username) && “111”.equals(password)){
**//3.将登陆成功的用户信息添加到session
req.getSession**().setAttribute(“username”,“zs”)**;
//4.重定向到queryServlet 重定向需要 /项目名/资源名
resp.sendRedirect**(“/servlet_demo/queryServlet”);
}else{
**//3.响应
writer.println**(“登录失败”);
}
}
}_**

QueryServlet

/查询数据的Servlet/public class QueryServlet extends HttpServlet {
__
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp_) _throws ServletException, IOException {
__
//设置响应对象 resp 响应数据的编码为UTF-8
_resp.setCharacterEncoding**
(“UTF-8”)**;
//设置Content-Type响应 头 告知浏览器以UTF-8解析信息
resp.setContentType**(“text/html;charset=UTF-8”)**;
//设置请求的编码格式
req.setCharacterEncoding**(“utf-8”)**;
//1.取出session中的用户信息
String username = **(String) req.getSession().getAttribute(“username”);
System.
_out
.println(“username: “+username+“查询了数据”);
_//2.模拟数据库查询
_User zs =
new User(1, “zs”, “111111”, 18);
User ls =
new User(2, “ls”, “111111”, 19);
User ww =
new User(3, “ww”, “111111”, 20);
ArrayList
<User> list = new ArrayList<>();
list.add
(zs);
list.add
(ls);
list.add
(ww);
_//3.将数据存储到request对象中(一次请求有效)
_req.setAttribute
(“list”, list);
_//4.请求转发到ShowServlet(转发到向浏览器响应数据的Servlet) 共享request对象
_req.getRequestDispatcher
(“/showServlet”).forward(req, resp);
}
__}
**

showServlet

//…

六. HttpSession与Cookie总结

HttpSession与Cookie的区别:

  • cookie数据存放在客户的浏览器或系统的文件中,而HttpSession中的数据存放在服务器中
  • cookie不安全,而HttpSession是安全的
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个域名保存cookie的数量。而HttpSession没有容量以及数量的限制

HttpSession的使用建议:
HttpSession对象是保存在服务端的,所以安全性较高。我们可以在HttpSession对象中存储数据,但是由于HttpSession对象的生命周期不固定,所以不建议存放业务数据。一般情况下我们只是存放用户登录信息

七. 注解开发

Servlet_02 - 图25