Servlet、Request,Response,Session、Cookie
Servlet
概念
Servlet是运行在WEB服务器中的一小段Java程序,
它能够通过WEB服务器接受并处理浏览器发送的http请求,
并能够通过WEB服务器将动态生成的结果应答给客户端,
从而实现动态网页的功能
第一:Servlet是一个运行在web服务端的java小程序
第二:它可以用于接收和响应客户端的请求
第三:要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet
第四:每次请求都会执行service方法
第五:Servlet还支持配置
Servlet的特征
-
必须运行在WEB服务器内部。
由于web服务器为Servlet的运行提供了环境,所以web服务器也被称作web容器,或应用服务器 如Tomcat,JBOSS等等。 Servlet不会主动执行,必须由WEB服务器调用。
操作步骤
1、创建一个web工程
2、配置Tomcat
3、创建一个类继承Servlet类或者他的子类(HttpServlet,GenericServlet),
并重写都doGet,doPost、service方法
4、配置servlet可以使用注解配置,也可以使用xml文件配置
xml文件配置:
<!--配置servlet名称和对应的类-->
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.entor.servlet.TestServlet</servlet-class>
</servlet>
<!--配置servlet名称和对应的请求地址-->
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
注解配置:
@WebServlet("/test")
public class TestServlet extends HttpServlet {
servlet三种实现方式
第一种:实现Servlet接口,接口中的方法必须全部实现。
使用此种方式,表示接口中的所有方法在需求方面都有重写的必要。此种方式支持最大程度的自定义。
第二种:继承GenericServlet,service方法必须重写,其他方可根据需求,选择性重写。
使用此种方式,表示只在接收和响应客户端请求这方面有重写的需求,而其他方法可根据实际需求选择性重写,
使我们的开发Servlet变得简单。但是,此种方式是和HTTP协议无关的。
第三种:继承HttpServlet,它是javax.servlet.http包下的一个抽象类,是GenericServlet的子类。
如果我们选择继承HttpServlet时,只需要重写doGet和doPost方法,不用覆盖service方法。
使用此种方式,表示我们的请求和响应需要和HTTP协议相关。也就是说,我们是通过HTTP协议来访问的。
那么每次请求和响应都符合HTTP协议的规范。请求的方式就是HTTP协议所支持的方式
HTTP协议支持7种请求方式:
(GET POST PUT DELETE TRACE OPTIONS HEAD )。
Servlet的生命周期
出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,就放到内存中。
活着:服务器提供服务的整个过程中,该对象一直存在,每次只是执行service方法。
死亡:当服务停止时,或者服务器宕机时,对象消亡
由此可看出servlet是单例模式,所以存在线程安全,所以为了解决这问题,尽量将变量定义在方法中
三种映射方式
第一种:/Test1servlet
具体的一个servlet路径名称
第二种:/servlet/*
/开头+通配符的方式
第三种:*.do
通配符+固定格式结尾
三种映射方式的优先级为:第一种>第二种>第三种。
多路径映射Servlet
<!--配置ServletDemo7-->
<servlet>
<servlet-name>servletDemo7</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo7</servlet-class>
</servlet>
<!--映射路径1-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/demo7</url-pattern>
</servlet-mapping>
<!--映射路径2-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/servletDemo7</url-pattern>
</servlet-mapping>
<!--映射路径3-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
启动时创建Servlet时机
配置项的取值只能是正整数(包括0),数值越小,表明创建的优先级越高
<load-on-startup>1</load-on-startup>
它的映射路径是<url-pattern>/<url-pattern>
,我们在发送请求时,首先会在我们应用中的web.xml中查找映射配置,找到就执行,这块没有问题。但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。所以,一切都是Servlet。
ServletConfig
它是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。
所以,每个Servlet都一个自己的ServletConfig。
它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。
重写的init方法里的参数就是servletConfig对象
<servlet>
<servlet-name>servletDemo8</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
<!--配置初始化参数-->
<init-param>
<!--用于获取初始化参数的key-->
<param-name>encoding</param-name>
<!--初始化参数的值-->
<param-value>UTF-8</param-value>
</init-param>
<!--每个初始化参数都需要用到init-param标签-->
<init-param>
<param-name>servletInfo</param-name>
<param-value>This is Demo8</param-value>
</init-param>
</servlet>
常用方法
//1.输出ServletConfig
System.out.println(servletConfig);
//2.获取Servlet的名称
String servletName= servletConfig.getServletName();
System.out.println(servletName);
//3.获取字符集编码
String encoding = servletConfig.getInitParameter("encoding");
System.out.println(encoding);
//4.获取所有初始化参数名称的枚举
Enumeration<String> names = servletConfig.getInitParameterNames();
//遍历names
while(names.hasMoreElements()){
//取出每个name
String name = names.nextElement();
//根据key获取value
String value = servletConfig.getInitParameter(name);
System.out.println("name:"+name+",value:"+value);
}
//5.获取ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println(servletContext);
ServletContext
ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。
它可以实现让应用中所有Servlet间的数据共享(可以把它看成一个大容器,用来装程序运行期间的资源)
生命周期
出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。
(Servlet和ServletContext都是单例的)
活着:只要应用一直提供服务,该对象就一直存在。
死亡:应用被卸载(或者服务器挂了),该对象消亡。
域对象概念
域对象的概念,它指的是对象有作用域,即有作用范围。
域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。
在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。
它也是我们接触的第一个域对象。 它是web应用中最大的作用域,叫application域。
每个应用只有一个application域。它可以实现整个应用间的数据共享功能。
配置
ServletContext既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,
而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。
配置的方式,需要在`<web-app>`标签中使用`<context-param>`来配置初始化参数。
<!--配置应用初始化参数-->
<context-param>
<!--用于获取初始化参数的key-->
<param-name>servletContextInfo</param-name>
<!--初始化参数的值-->
<param-value>This is application scope</param-value>
</context-param>
<!--每个应用初始化参数都需要用到context-param标签-->
<context-param>
<param-name>globalEncoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
ServletContext常用方法
//获取ServletContext对象
ServletContext context = getServletContext();
//获取全局配置的globalEncoding
String value = context.getInitParameter("globalEncoding");
System.out.println(value);
//获取应用的访问虚拟目录
String contextPath = context.getContextPath();
System.out.println(contextPath);
//根据虚拟目录获取应用部署的磁盘绝对路径
//获取b.txt文件的绝对路径
String b = context.getRealPath("/b.txt");
System.out.println(b);
//获取c.txt文件的绝对路径
String c = context.getRealPath("/WEB-INF/c.txt");
System.out.println(c);
//获取a.txt文件的绝对路径
String a = context.getRealPath("/WEB-INF/classes/a.txt");
System.out.println(a);
//向域对象中存储数据
context.setAttribute("username","zhangsan");
//移除域对象中username的数据
//context.removeAttribute("username");
Request
客户端相应对象,跟请求相关的内容都封装在此对象中
常用方法:
authenticate (HttpServletResponse response)
使用为ServletContext配置的容器登录机制来验证当前用户的请求, Servlet3.0规范中的新方法。
changeSessionId()
改变当前请求对应的会话ID,它只会改变session的ID,不会新创建HttpSession对象。Servlet3.1版本加入的新方法
getAuthType()返回用于保护servlet的验证方法名称。
所有servlet容器都支持basic,form和client_ certificate验证, 并粗可能还支持digest验证。
getContextPath()
获取当前项目访问的URI。就是我们在IDEA里面部署项目时配置的虚拟目录
getCookies()
获取当前请求所携带的所有Cookie对象。
getDateHeader (String nane)
根据消息头的名称,获取日期类型的请求消息头的值。得到的是一个从1970年开始计算的毫秒值。
getHeader (String name)
根据名称,获取字符串类型的请求消息头的值
getHeaderMames()
获取请求消息头名称的枚举。返回的是所有请求消息头的名称。
getHeaders(String nane)
根据消息头名称,获取消息头的值。它和getHeader的区别是,它是一个消息 头对应多个值。
getHttpServletMappingp()
返回当前请求所在的Servlet的HttpServletMapping.
getIntHeader(String name)
根据消息头名称,返回int类型的消息头的值
getmehod()
返回请求的方式。例如;GET,POST,PUT等等。
getPart(String nane)
根据给定的名称,获取多部分表单数据的内容。如果没有指定名称的内容,则返回null。它是Servlet3.0规范加入的。
getParts()
获取多部分表单数据中的所有part的集合。要求表单的enctype取值为: multipart/form-data
ge tPathInfo()
返回与客户端发出此请求时发送的URL相关联的任何额外路径信息。
getPathTranslated()
返回servlet名称之后、查询字符串( QueryString )之前的任何额外路径信息,并将其转换为实际路径。
getQueryString()
获取请求URL中携带参数的字符串,包括参数名称以及参数的值。
getRemoteUser()
如果用户已通过身份验证,则返回发出此请求的用户的登录名;如果用户未通过身份验证,则返回null。
ge tReques tedSessionId(
获取当前请求关联的会话ID。
ge tRequestURI()
获取当前请求的URI,获取的是此部分内容,如果配置了项目的访问路径,那么也会获取到。
getRequestURL.()
获取当前请求的URL。
getServletPath()
获取Servlet的映射路径。就是url-pattern标签配置的内容,或者@WebServlet注解的value属性的取值。
getSession(
获取当前请求关联的会话对象,如果没有的话就创建一个新的会话。
getSession(boolean create)
如果参数是true,它和getSession()方法是一样的。如果参数是false ,在当前请求没有关联的会话时,直接返回null。
getTrailerFields ()
获取HTTP中Trailer报头信息。
getUserPrincipal ()
返回包含当前已验证用户名称的iava.securitv.Principal对象。
isRequestedSessi onIdFromCookie()
检查请求的会话ID是否作为cookie传入
isRequestedSessi onIdFxomURL. ()
检查请求的会话ID是否作为请求URL的一部分传入。
isRequestedSessi onIdValid()
检查当前请求关联的会话1ID是否仍然有效。
isTrailerFieldsReady()
指示是否可以使用getTraileFields0读取Trailer字段,默认值是false ,不允许。
isUserInRole(String role)
用于判断认证后的用户是否属于逻辑role中的成员
login(String username, String pas sword)
验证提供的用户名和密码.然后将已验证的用户与请求关联。
logout()
从请求中移除认证成功的用户。它是Servlet3.0规范加入的方法。
newPushBuilder()
获取推送器对象。以从当前请求发出服务器推送响应。
upgrade (C1 ass<T> handlerClass)
为给定类创建HttpUpgradeHandler实例,并将其用于http协议升级处理。
主要功能
获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
1. String getParameter(String name):根据参数名称获取参数值
2. String[] getParameterValues(String name):根据参数名称获取参数值的数组
3. Enumeration<String> getParameterNames():获取所有请求的参数名称
4. Map<String,String[]> getParameterMap():获取所有参数的map集合
根据表单的name值获取
中文乱码问题:
* get方式:tomcat 8 已经将get方式乱码问题解决了
* post方式:会乱码
* 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
请求转发:一种在服务器内部的资源跳转方式
1. 步骤:
1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
2. 特点:
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部资源中。
3. 转发是一次请求
共享数据:
* 域对象:一个有作用范围的对象,可以在范围内共享数据
* request域:代表一次请求的范围,一般用于请求转发的多个资源*享数据
* 方法:
1. void setAttribute(String name,Object obj):存储数据
2. Object getAttitude(String name):通过键获取值
3. void removeAttribute(String name):通过键移除键值对
4. 获取ServletContext:
* ServletContext getServletContext()
Response
服务端相应对象,跟响应相关的内容都封装在此对象中
协议无关的对象标准是:ServletResponse接口
协议相关的对象标准是:HttpServletResponse接口
这个对象的实现类是由Tomcat提供的,不用我们自定义。同时它还会帮我们把对象创建出来并传入doGet和doPost方法中。
常用方法
addCookie(Cookie cookie) 在响应中添加一个指定的cookie
addDateHeader(String name, long date) 添加日期类型的响应消息头,name是头的名称,date是日期的毫秒值,从1970年开始
addHeader(String name, String value) 添加字符串类型的响应消息头
addIntHeader(String name, int value) 添加整形的响应消息头
containsHeader(String name) 判断是否包含指定名称的消息头
encodeRedirectURL(String url) URL重写方法,用于重定向目的地禁用cookie的会话保持
encodeURL(String url) URL重写方法,用于浏览器禁用cookie的会话保持
getHeader(String name) 根据名称,获取消息由的内容
getHeaderNames() 获取响应消息头名称的集合
getHeaders(String name) 根据名称获取全部消息头内容,适用于一个消息头,多个值的情况
getStatus() 获取当前响应码状态
sendError(int sc) 向客户端发送指定状态码的错误响应,并清除缓冲区
sendError(int sc, String msg) 向客户端发送指定状态的错误响应,同时携带错误描述,他也会清除缓冲区
sendRedirect(String location) 把客户端浏览器地址栏重新定向到一个新的地址上,清除缓冲器区,(重定向方法)
setDateHeader(String name, long date) 设置日期类型的消息头,name是头的名称,date是日期的毫秒值,从1970年开始
setHeader(String name, String value) 设置字符串类型消息头
setIntHeader(String name, int value) 设置整形消息头
setStatus(int sc) 设置响应状态码
常用状态码:
200 执行成功
302它和307一样,都是用于重定向的状态码。只是307目前已不再使用
304请求资源未改变,使用缓存。
400请求错误。最常见的就是请求参数有问题
404请求资源未找到
405请求方式不被支持
500服务器运行内部错误
常用操作
1. 获取输出流
* 字符输出流:PrintWriter getWriter()
* 字节输出流:ServletOutputStream getOutputStream()
2. 使用输出流,将数据输出到客户端浏览器
* 通过流对向调用write方法将数据写入到页面
路径写法:
1. 路径分类
1. 相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html
* 不以/开头,以.开头路径
* 规则:找到当前资源和目标资源之间的相对位置关系
* ./:当前目录
* ../:后退一级目录
2. 绝对路径:通过绝对路径可以确定唯一资源
* 如:http://localhost/day15/responseDemo2 /day15/responseDemo2
* 以/开头的路径
* 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
* 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
* 建议虚拟目录动态获取:request.getContextPath()
* <a> , <form> 重定向...
* 给服务器使用:不需要加虚拟目录
* 转发路径
乱码问题解决
//简单的形式,设置编码,是在获取流之前设置
response.setContentType("text/html;charset=utf-8");
forward跟include区别
forward是自己完成不了,给别人来做,只能写一次,后面代码无意义
include是自己单独完成不了,需要别的servlet来帮忙,可以由多个
会话技术
-
会话:一次会话中包含多次请求和响应。 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
-
功能:在一次会话的范围内的多次请求间,共享数据
-
方式: 1. 客户端会话技术:Cookie 2. 服务器端会话技术:Session
Cookie
概念
它是客户端浏览器的缓存文件,里面记录了客户浏览器访问网站的一些内容。
同时,也是HTTP协议请求和响应消息头的一部分
它可以保存客户浏览器访问网站的相关内容(需要客户端不禁用Cookie)
从而在每次访问需要同一个内容时,先从本地缓存获取,使资源共享,提高效率。
可以看成是一个容器(钥匙),当请求资源时传给服务器,然后服务器就可以获得里面的session(锁)的jssessionid值找到对应的session对象
Cookie的属性
value cookie的值(不能是中文)
path cookie的路径
domain cookie的域名
maxAge cookie的生存时间。
name cookie的名称
version cookie的版本号。
comment cookie的说明。
Cookie有大小,个数限制。每个网站最多只能存20个cookie,且大小不能超过4kb。同时,所有网站的cookie总数不超过300个。
当删除Cookie时,设置maxAge值为0。当不设置maxAge时,使用的是浏览器的内存,当关闭浏览器之后,cookie将丢失。设置了此值,就会保存成缓存文件(值必须是大于0的,以秒为单位)。
Cookie的常用方法
//创建cookie对象
Cookie username = new Cookie("username", "zhangsan");
Cookie password = new Cookie("password", "123456");
//设置有效时间,单位是秒,默认不设置,有效期是-1,关闭浏览器则删除cookie
username.setMaxAge(60);
//把cookie写入浏览器,返回给客户端,只有当服务器响应成功之后cookie才写入到浏览器
resp.addCookie(username);
resp.addCookie(password);
//获取浏览器的cookie
Cookie[] cookies = req.getCookies();
Arrays.stream(cookies).forEach(cookie -> {
System.out.println(cookie.getName()+"="+cookie.getValue());
});
cookie的细节
-
可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可
-
默认情况下,当浏览器关闭后,Cookie数据被销毁 持久化存储: setMaxAge(int seconds) 1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效 2. 负数:默认值 3. 零:删除cookie信息
-
假设在一个tomcat服务器中,部署了多个web项目,这些web项目中cookie的共享问题 * 默认情况下cookie不能共享 * setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录 * 如果要共享,则可以将path设置为"/"
-
不同的tomcat服务器间cookie共享问题 * setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享 * setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
session
是Servlet规范中提供的一个接口。该接口的实现由Servlet规范的实现提供商提供。
HttpSession接口的实现由Tomcat提供。
服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中
原理
HttpSession,它虽然是服务端会话管理技术的对象,但它本质仍是一个Cookie。
是一个由服务器自动创建的特殊的Cookie,Cookie的名称就是 JSESSIONID,Cookie的值是服务器分配的一个唯一的标识。
当我们使用HttpSession时,浏览器在没有禁用Cookie的情况下,都会把这个Cookie带到服务器端,
然后根据唯一标识去查找对应的HttpSession对象,找到了,我们就可以直接使用了。
HttpSession的获取
通过HttpServletRequest接口中的两个方法获取
getSession(Boolean create)参数为true意思是找不到到跟cookie匹配的session就创建,false是找不到就返回null
getSession()
HttpSession的常用方法
getAttribute(String name) 根据名称从会话域中获取数据
getAttributeNames() 获取会话域中所有属性的名称
getCreationTime() 获取httpSession对象的创建时间 ,他是从1970年开始的毫秒值
getId() 获取会话的唯一标识,也就是jssessionid的值
getLastAccessedTime() 获取httpsession对象最后访问时间,他也是从1970年开始的毫秒值
getMaxInactiveInterval() 获取最大间隔时间
getServletContext() 获取servletcontent对象
invalidate() 让httpSession立即失效
isNew() 判断会话是否是新的,当客户端不加入会话或者不知道有此会话时,返回true
removeAttribute(String name) 根据名称移除会话域中的数据
setAttribute(String name, Object value) 把名称和值设置到会话域中
setMaxInactiveInterval(int interval) 设置最大间隔时间
HttpSession的钝化和活化
-
持久态
把长时间不用,但还不到过期时间的HttpSession进行序列化,写到磁盘上。 HttpSession持久态也叫做钝化。(与钝化相反的,我们叫活化。)
HttpSession的持久化由服务器来负责管理,我们不用关心。
只有实现了序列化接口的类才能被序列化,否则不行。
细节
-
当客户端关闭后,服务器不关闭,两次获取session是否为同一个? * 默认情况下。不是。 * 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。 Cookie c = new Cookie("JSESSIONID",session.getId()); c.setMaxAge(60*60); response.addCookie(c);
-
客户端不关闭,服务器关闭后,两次获取的session是同一个吗? * 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作 * session的钝化: * 在服务器正常关闭之前,将session对象系列化到硬盘上 * session的活化: * 在服务器启动后,将session文件转化为内存中的session对象即可。
-
session什么时候被销毁? 1. 服务器关闭 2. session对象调用invalidate() 。 3. session默认失效时间 30分钟 选择性配置修改 <session-config> <session-timeout>30</session-timeout> </session-config>
-
session的特点 1. session用于存储一次会话的多次请求的数据,存在服务器端 2. session可以存储任意类型,任意大小的数据
-
session与Cookie的区别: 1. session存储数据在服务器端,Cookie在客户端 2. session没有数据大小限制,Cookie有 3. session数据安全,Cookie相对于不安全
上一篇: java web之路 jsp状态管理 cookie在登陆中的应用
下一篇: 爆逗,都是高人!高的很!
推荐阅读
-
Yii框架中用response保存cookie,用request读取cookie的原理解析
-
javaWeb核心技术第七篇之HTTP、Tomcat、Servlet、Request和Response
-
Laravel框架Request、Response及Session操作示例
-
JSP中Servlet的Request与Response的用法与区别
-
Yii框架中用response保存cookie,用request读取cookie的原理解析
-
JavaWeb--Servlet过滤器Filter和SpringMVC的HandlerInterceptor(Session和Cookie登录认证)
-
request+response+session
-
struts2的action中获得request response session
-
struts2的action中获得request response session
-
Request、Response、JSP、session概述