JavaWeb之Servlet详解-爱代码爱编程
一,什么是Servlet
Servlet字面意思即服务端小程序
Servlet是一组接口、一组规范、一个协议;用于开发Web项目
一个工程的搭建通常由各模块组成;各个模块分工协作、相互配合可以高效率地构建大型项目。各个模块之间需要一组规范来连接,Servlet就是这样一组规范
B/S架构中涉及到的协议、标准、规范:
- 浏览器和Web服务器之间的请求和响应遵循HTTP协议
- WEB服务器和web项目的开发者(我们)之间有一些规范,例如:Servlet、JSP规范
- Web项目的开发者(我们)和数据库服务器之间有一个规范,叫做JDBC规范
二,Servlet
1,Servlet是如何起作用的
每一个url都对应着互联网中的一个资源,分为静态资源和动态资源,例如:
- http://202.108.251.34:8080/egov/login.html请求路径对应着一个html网页资源
- http://202.108.251.34:8080/oa/delete?empno=7369请求路径对应着一个动态资源、一段程序
这段程序就是Servlet程序,当浏览器发送某个请求时,服务器找到该请求对应的servlet程序并执行servlet对象的service()方法。请求路径与servlet程序的对应信息配置在web.xml文件中,如图:
2,Servlet接口中的方法
javax.servlet.Servlet接口
public interface Servlet {
/**
初始化方法,servlet对象创建之后会执行该方法;servlet对象为单例对象,故该方法只执行一次
*/
void init(ServletConfig config) throws ServletException;
/**
获取servletConfig对象,该对象由服务器创建并传入
*/
ServletConfig getServletConfig();
/**
主体方法,用于处理业务逻辑,服务器通过请求路径找到对应的servlet对象并执行该方法;由服务器传入请求和响应对象
*/
void service(ServletRequest request, ServletResponse response) throws ServletException, IOException;
/**
返回有关servlet的信息,例如作者,版本和版权
*/
String getServletInfo();
/**
销毁前的准备,servlet对象销毁前会执行该方法
*/
void destroy();
}
3,Servlet对象的生命周期
Servlet对象从最初的创建,方法的调用,到最后被销毁,都是由web容器来管理的,javaweb程序员无权干涉
具体过程:
- Web容器启动,解析web.xml文件,将请求路径与对应的servlet类名放到一个map集合中,如图:
大多数web容器还会维护一个请求路径与对应的servlet对象的集合,如图:
默认情况 下,servlet对象在Web容器启动阶段不会被实例化,而是在接收到第一次请求之后实例化;若想要在web容器启动时实例化,可进行如下配置: - 浏览器发送请求,web容器截取请求路径,通过请求路径在Map<String, Servlet>中查找对应的servlet对象;
如果没有找到对应的servlet对象,则:
1,通过请求路径在Map<String, String>找到对应的servlet全类名
2,通过反射机制加载该类并调用无参构造方法完成servlet对象实例化
3,调用servlet对象的init()方法完成初始化
4,调用servlet对象的service()方法提供服务
若找到了对应的servlet对象,则调用该对象的service()方法提供服务 - servlet对象销毁:web容器关闭的时候、webApp重新部署的时候、该servlet对象长时间没有用户访问的时候,web容器会将servlet对象销毁,在销毁servlet对象前,会调用对象的destroy()方法进行销毁前的准备
注意:servlet对象是单例,web容器为每个Servlet类只创建一个servlet对象
三,ServletConfig
1,什么是ServletConfig
- ServletConfig指javax.servlet.ServletConfig接口
- 【了解】Apache Tomcat服务器实现了Servlet规范,Tomcat服务器写了一个ServletConfig接口的实现类,实现类的完整类名是
org.apache.catalina.core.StandardWrapperFacade
- ServletConfig对象封装了Servlet对象的配置信息,每个Servlet对象对应着一个ServletConfig对象;在web.xml中,ServletConfig对象对应着
<servlet>
标签中的所有内容,例如: - ServletConfig对象由服务器创建并在servlet对象初始化时传入:
void init(ServletConfig servletConfig) throws ServletException;
- 在service()方法体中,可以通过getServletConfig()方法获取ServletConfig对象:
2,ServletConfig中的方法
public interface ServletConfig {
//获取servletName: <servlet-name>servletName</servlet-name>
String getServletName();
//获取ServletContext对象,ServletContext为Servlet的上下文环境,下章节讲
ServletContext getServletContext();
/**
获取初始化参数name对应的value
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.driver</param-value>
</init-param>
*/
String getInitParameter(String paranmae);
/**
获取初始化参数的name集合的枚举(类似迭代器):
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
通过name集合循环遍历拿出name,通过name获取value
while (initParameterNames.hasMoreElements()) {
String name = initParameterNames.nextElement();
String value = servletConfig.getInitParameter(name);
}
*/
Enumeration<String> getInitParameterNames();
}
三,ServletContext
1,什么是ServletContext
-
ServletContext指javax.servlet.ServletConfig接口
-
ServletContext对象由服务器创建,Tomcat服务器对ServletContext接口的实现类完整类名是:
org.apache.catalina.core.ApplicationContextFacade
-
ServletContext意为servlet的上下文环境,servletContext对象对应着整个项目,该对象只有一个且被所有servlet共享,servletContext对象对应着web.xml文件,例如:
-
web.xml文件服务器启动阶段被解析,servletContext对象在服务器启动阶段被创建,在服务器关闭时被销毁
2 ,ServletContext中的常用方法
/**
根据参数的名称获取value,均为字符串
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.driver</param-value>
</context-param>
*/
String getInitParameter(String paraname);
//与ServletConfig中的方法作用相同
Enumeration<String> getInitParameterNames();
//向ServletContext对象中添加数据
void setAttribute(String name, Object obj);
//根据name从ServletContext对象中获取数据
Object getAttribute(String name);
//从ServletContext对象中移除数据
void removeAttribute(String name);
//获取文件绝对路径
String getRealPath(String path);
3,ServletContext与ServletConfig的区别与联系
- 每一个servlet对象对应着一个servletConfig对象;所有的servlet对象共同对应着一个servletContext对象
- servletConfig中包含了所对应的servlet的参数配置信息;servletContext中包含了整个项目的参数配置信息,所有的servlet共享该配置信息
- servletConfig和servletContext对应的参数配置信息均在web.xml文件中,位置如下:
4,servletContext共享数据
由于所有的servlet共同对应着一个servletContext,不同的servlet、不同的用户可以通过一下两个方法共享数据
//向ServletContext对象中添加数据
void setAttribute(String name, Object obj);
//根据name从ServletContext对象中获取数据
Object getAttribute(String name);
四,GenericServlet(适配器)
1,什么是GenericServlet
GenericServlet即通用Servlet,是一个抽象类,实现了Servlet接口
2,GenericServlet的设计目的
- GenericServlet的设计采用了适配器设计模式
- 在GenericServlet没有出现之前,我们编写的Servlet类需要直接实现Servlet接口,但是这个接口中有些方法是目前不需要的,有些操作又是每个Servlet类必备的,例如在init()方法中给config成员赋值,我们大多数情况只需要编写不同的service()方法。直接实现Servlet接口的代码丑陋,有必要在中间添加一个适配器,以后所有的Servlet类不再直接实现Servlet接口,而而是去继承GenericServlet
- GenericServlet中只含有一个抽象方法,即service(),子类必须实现,编写业务逻辑
- GenericServlet中提供了一个重载的无参数的init()方法,若想在servlet初始化时执行一段特殊的代码,建议重写此无参数的
init()
方法 - 除了让代码变得优雅之外,GenericServlet中又提供了一些额外的方法,例如:
public String getInitParameter(String name);
、public ServletContext getServletContext();
子类继承之后,可以在子类中直接使用,方便编程
五,HttpServlet
1,什么是HttpServlet
HttpServlet是一个模板类、抽象类,继承于GenericServlet
2,HttpServlet的设计目的
- HttpServlet是针对于HTTP协议的,为了处理http请求和响应。不同类型的请求会由不同类型的Servlet处理,对于JavaWeb程序员,我们只需要关注HttpServlet即可
- 为了使前后端的请求方式相同,我们需要在后端获取请求方式,然后进行判断前端发送的请求是否为规定的请求方式,如果不是规定的请求方式,就会报错;
- 为了实现上述功能,需要在每一个GenericServlet的子类中编写实现此功能的代码,代码臃肿;为了解决这个问题,Sun公司提供了HttpServlet抽象类封装了实现上述功能的代码
3,HttpServlet执行流程
service(ServletRequest req, ServletResponse res)
方法将两个参数转化为HttpServletRequest和HttpServletResponse类型的service(HttpServletRequest request, HttpServletResponse response)
方法获取请求方法;判断,如果是Get请求就执行doGet()方法,如果是Post请求就执行doPost()方法- doGet()/doPost()执行业务代码
注意:HttpServlet提供的doGet()方法和doPost()方法是用来报错的、是用来让我们重写的
所以,我们编写的的Servlet类继承HttpServlet后,后端需要的是什么请求,那么我们就重写对应的doPost()/doGet()方法,方法内是我们的业务代码,并不需要重写service()方法
4,HttpServlet使用总结
- 我们的Servlet继承HttpServlet后,后端需要的是什么请求,那么我们就重写对应的
doPost()
/doGet()
方法 doPost()
/doGet()
方法内就是我们的业务代码,doXXX()
可以看作main()
方法- 代码不在
service()
内编写了,不需要重写service()
方法 - HttpServlet中重载的两个
service()
方法并不需要也没有理由去重写这两个方法 - 当浏览器发送的请求方式和后台处理方式不同时,会出现一个错误,代号:405
5,模板方法设计模式
模版方法设计模式属于行为行设计模式
模版方法有一个特点:doXXX()
模板方法设计模式的主要作用:
- 核心算法得到保护
- 核心算法得到复用
- 在不改变算法的前提下,却可以重新定义算法步骤的具体实现
模板方法设计模式的例子:
- Servlet规范中的HttpServlet
- HttpServlet就是一个典型的模板方法设计模式
- HttpServlet是一个模板类
- 其中的service(HttpServletRequest, HttpServletResponse)方法是典型的模板方法,该方法中定义了核心算法骨架,doGet()、doPost()…具体的实现细节延迟到子类中完成
六,HTTP协议
1,什么是HTTP协议
- 超文本传输协议
- 浏览器和服务器之间的一种通讯协议
- 该协议时W3C负责制定的,其本质上就是数据传送格式,提前指定好了的。浏览器和服务器都必须按照这种格式接收与发送数据
- HTTP协议是无连接、无状态的:请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束后,通道关闭;这样做的目的是降低服务器的压力
2,请求协议
请求协议包括四部分:
1,请求行
2,消息报头
3,空白行
4,请求体
请求行包括:请求方式 URI 协议版本号
空白行:专门用来分离消息报头和请求体的
2.1 Get请求
2.2 Post请求
3,响应协议
响应协议包括四部分:状态行、响应报头、空白行、响应体
状态行:协议版本号 状态码
空白行:是用来分离响应报头和响应体的
响应协议中重点掌握状态码:
- 200 响应成功正常结束
- 404 资源未找到
- 500 服务器内部错误
…
4,Get请求与Post请求区别
(1), 什么情况下浏览器发送的请求是GET请求,什么情况下浏览器发送的请求是POST请求?
只有当使用表单form,并且讲form的标签的method属性设置为method=“post”,才是POST请求方式,其余剩下的所有请求都是基于GET请求
(2), GET请求和POST请求有什么区别?
- GET请求在请求行上提交数据,格式
uri?name=value&name=value
,这种提交方式最终提交的数据会显示在浏览器地址栏上 - POST请求在请求体中提交数据,相对安全,提交格式
name=value&name=value
,这种提交方式最终不会显示在浏览器地址栏上 - POST请求在请求体中提交数据,所以POST请求提交的数据没有长度限制【POST可以提交大数据】
- GET请求在请求行上提交数据,所以GET请求提交的数据长度有限制
- GET请求只能提交字符串数据,POST请求可以提交任何类型的数据,包括视频…,所以文件上传必须使用POST请求
- GET请求最终的结果,会被浏览器缓存收纳,而POST不会被缓存收纳(为什么GET会被缓存?)
(3),GET请求和POST请求应该如何选择?
- 有敏感数据 POST
- 传送的数据不是普通字符串 POST
- 传送的数据非常多 POST
- 这个请求是为了修改服务器端资源 POST
- GET请求多数情况下是从服务器中读取资源,这个读取的资源在短时间内不会发送变化,所以GET请求最终的结果会被浏览器缓存起来
- POST请求是为了修改服务器端的资源,而每一次修改结果都是不同的,最终结果没有必要被浏览器缓存
5,缓存解决方案
浏览器将资源缓存后,缓存的资源是和某个特定的路径绑定在一起的,只要浏览器再发送这个相同的请求路径,这个时候浏览器就会去缓存中获取资源,不再访问服务器,以这种方式降低服务器的压力,提高用户体验。
但是有的时候我们并不希望走缓存,希望每一次后哦访问服务器,可以在请求路径后面添加时间戳,例如:http://ip:port/oa/system/logout?timetamp=1234564635423
七,HttpServletRequest和HttpServletResponse
1,HttpServletRequest接口
1.1 什么是HttpServletRequest
- HttpServletRequest是一个接口,继承于ServletRequest
- HttpServletRequest接口的实现类是由Web容器负责的,Tomcat服务器有自己的实现
- 每当浏览器发送一个请求,服务器接收到该请求并创建一个HttpServletRequest对象,httpServletRequest对象中封装了该请求的所有信息。在执行servlet的service()方法时将该对象传入
1.2 HttpServletRequest对象中的常用方法
表单提交的数据会封装在request对象的Map集合中,key是name,value是字符串类型的一个一维数组,如下:
/*获取浏览器提交的数据*/
String getParameter(String name) //获取name对应的一维数组的首元素
Map getParameterMap() //获取request对象中的Map集合
Enumeration getParameterNames() //返回name集合的枚举,与ServletConfig、ServletContext中的getInitParameterNames()作用相同
String[] getParameterValues(String name) //返回String数组,数组包含name对应的多个value值
/*获取路径、URL、URI、IP*/
String getContextPath() //获取上下文路径(web项目根路径),资源的根路径
String getMethod() //获取浏览器请求方式
String getRequestURI() //获取请求的URI
StringBuffer getRequestURL() //获取请求的URL
String getServletPath() //获取请求的ServletPath,即servlet对应的请求路径
String getRemoteAddr() //获取客户端IP地址
/*从一次请求对应的HttpServletRequest对象范围中增删查数据*/
Object getAttribute(String name) //从此次请求对应的request对象范围中获取数据
void setAttribute(String name, Object o) //从此次请求对应的request对象范围中存储数据
void removeAttribute(String name) //从此次请求对应的request对象范围中删除数据
/*请求转发器*/
RequestDispatcher getRequestDispatcher(String path) //获取请求转发器,用于请求转发
/*编码*/
void setCharacterEncoding(String env) //覆盖此请求正文中使用的字符编码的名称(针对post请求才起作⽤)
/**/
HttpSession getSession() //返回与此请求关联的当前会话,如果该请求没有会话,则创建一个并返回。
HttpSession session=request.getSession(true);//获取session对象,若没有获取到则新建session对象并返回;与getSession()作用相同
HttpSession session=request.getSession(false);//获取session对象,若没有获取到则返回null
Cookie[] getCookies() //返回一个Cookie数组,其中包含浏览器端发送过来的包含在请求中的所有cookie
//Cookie和Session下面章节讲
2,HttpServletResponse接口
2.1 什么是HttpServletResponse
- 与HttpServletRequest一样,HttpServletResponse是一个接口,继承于ServletResponse;HttpServletResponset接口的实现类是由Web容器负责的,Tomcat服务器有自己的实现
- 服务器接收到请求之后会作出响应,httpServletResponse对象封装了响应消息
2.2 HttpServletResponse对象中的常用方法
void addCookie(Cookie cookie) //给这个响应添加⼀个cookie
void sendRedirect(String s) //重定向,发送⼀条响应码,将浏览器跳转到指定的位置
PrintWriter getWriter() //获得字符输出流,通过字符流的write(String s)⽅法可以将字符串输出到response缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
void setContentType(String s) //设置响应内容的类型,例如:response.setContentType("text/html;charset=UTF-8");
3,请求转发与重定向
3.1 请求转发
步骤:
- 获取请求转发器对象
- 调用请求转发器的
forward()
方法即可完成转发
例如:
//请求转发到/b对应的Servlet
request.getRequestDispatcher("/b").forward(request,response);
特点: 在浏览器端进行一次请求,服务器端将请求从一个Servlet转发给另一个Servlet…,浏览器端的地址不变,但是实际上可能后台是好几个Servlet依次处理浏览器的请求,并响应给浏览器。请求转发可以使不同的servlet共享同一个request中的数据,通过以下方法:
Object getAttribute(String name) //从此次请求对应的request对象范围中获取数据
void setAttribute(String name, Object o) //从此次请求对应的request对象范围中存储数据
void removeAttribute(String name) //从此次请求对应的request对象范围中删除数据
3.2 重定向
服务器将请求路径反馈给浏览器,浏览器又向web服务器发送了一次全新的请求;例如:
response.sendRedirect(request.getContextPath() + "/b");
3.3 转发与重定向的异同
- 相同点:都可以完成资源的跳转、页面的跳转
- 不同点:
- 转发是request对象触发的,服务器内部进行转发
- 重定向是response对象触发的,要将重定向的路径响应给浏览器
- 转发是一次请求,浏览器地址栏上地址不变
- 重定向是两次请求,浏览器地址栏上的地址发生变化
- 重定向路径需要加项目名(webapp根路径web目录),因为该路径由浏览器解析
- 转发是在本项目内部完成资源的跳转
- 重定向可以完成跨网站跳转,例如可以跳转到
https://www.baidu.com
3.4 什么时候采用转发,什么时候采用重定向?
大部分情况下都使用重定向
- 若想完成跨app跳转,必须采用重定向
- 若在上一个资源中向request范围中存储了数据,希望在下一个资源中从request范围中取出,必须使用转发
- 重定向可以解决浏览器的刷新问题
3.5 重定向解决页面刷新问题
假设现在浏览器端发送向数据库中插入一条数据的请求,插入成功后跳转到成功页面
使用转发:
- 浏览器提交请求后,后台进行转发到access.html成功页面,浏览器只进行了一次请求,如果此时浏览器进行刷新,那么就会刷新最后一次提交表单的请求,会导致因为多次刷新而提交多次请求,导致后台执行多次Servlet,导致数据库插入多条重复记录
使用重定向:
- 浏览器提交请求后,后台通过重定向,将重定向的地址(/webapp17/access.html)发送给浏览器,浏览器会请求重定向的地址;这个过程中一共有两次请求;此时浏览器进行刷新,刷新的是最后一次重定向地址的请求,请求的资源是access.html,多次刷新就会多次请求access.html,并不会导致多次提交插入数据的请求!
八,Cookie
1,Cookie是什么?
- Cookie可以保存信息(保存在浏览器端上),其中保存了String类型的name-value(键值对)
- Cookie可以保存会话状态,这个会话状态是保留在客户端(浏览器端)上的; 只要Cookie清除,或者Cookie失效,这个会话状态就没有了【应用在Session中,请看下一章节】
- Cookie是保存在浏览器客户端上的
- Cookie默认保存在浏览器的缓存中,浏览器关闭Cookie消失
- Cookie可以保存在客户端硬盘文件中,浏览器关闭Cookie还在,除非Cookie消失(有效时长完结)
2,创建Cookie
服务器创建Cookie并发送给浏览器
//创建cookie
Cookie cookie = new Cookie(String name, String value);
//设置Cookie有效期
cookie.setMaxAge(60*60*60);
//设置Cookie绑定的路径
cookie.setPath("/webapp/user");
//将cookie发送给浏览器
response.addCookie(cookie);
3, Cookie绑定路径
Cookie未绑定路径时默认绑定的路径:
在默认情况下,未设置Cookie绑定路径的Cookie,会绑定当前访问路径的上一层路径(带"/"),如:
- 访问
/webapp/test/a
路径时,服务器发送的Cookie(此Cookie未人为设置绑定路径),那么此Cookie默认绑定的路径未/webapp/test
/,所以访问/webapp/test/、/webapp/test/···时都会将此Cookie发送给服务器
Cookie绑定路径:
cookie.setPath();
来设置此Cookie绑定的访问路径;当设置此Cookie绑定的路径时,浏览器只有访问此路径,以及此路径下的其他资源时,浏览器才会将此Cookie发送到服务器
如下:那么此Cookie只有浏览器访问/webapp19/user路径,以及/webapp/user/···等等其他此路径下的其他资源时,浏览器才会将此Cookie发送到服务器
cookie.setPath("/webapp/user");
4,浏览器何时发送Cookie
只有当浏览器访问Cookie绑定的路径以及此路径下的其他资源时,浏览器才会将Cookie发送给服务器
5,Cookie有效时长
通过方法cookie.setMaxAge(int expiry)
- 值为正数,以秒为单位指定Cookie的最长期限,Cookie存储在硬盘文件当中;
- 值为负数,则此Cookie在关闭此窗口页面后即失效;
- 如果为零,则删除此Cookie;
例如:以下设置Cookie有效期为24小时
cookie.setMaxAge(60*60*24);
6,Cookie的应用
例如:实现十天内免登录,将用户名和密码保存在cookie中,每当访问登录页面时发送给服务器,服务器验证
九,HttpSession
1,Session概述
- Cookie可以将会话状态保存在客户端,而HttpSession可以将会话状态保存在服务器端
- HttpSession对象是一个会话级别的对象,一次会话对应一个HttpSession对象
- 在会话进程中,web服务器一直为当前这个用户维护着一个会话对象HttpSession
- 在web容器中,维护了大量的HttpSession对象,这些对象放在一个Map集合中
2,获取Session对象
HttpSession session=request.getSession();//与getSession(true)作用相同
HttpSession session=request.getSession(true);//获取session对象,若没有获取到则新建session对象并返回;(无参数默认为true)
HttpSession session=request.getSession(false);//获取session对象,若没有获取到则返回null
3,Session实现原理
1,浏览器发送请求,服务器对应的Servlet首次调用request.getSession(true);
方法时获取Session对象:
- 服务器会创建一个Session对象,同时创建一个对应的Cookie对象,并且Cookie对象的name是JSESSIONID,Cookie的value是32位长度的字符串
- 服务器将Cookie的value和HttpSession对象绑定到session列表中(Map集合)
- 服务器将Cookie发送到客户端浏览器,浏览器将Cookie保存到缓存中
2, 浏览器再次发送请求,会自动提交Cookie(前提是同一个绑定路径下)
- 当服务器Servlet再次调用
request.getSession();
方法时获取Session对象 - 服务器接收到Cookie,验证Cookie的name为JSESSIONID,然后获取Cookie的value
- 通过Cookie的value去session列表(Map集合)中检索对应的HttpSession对象
4,Session对象生命周期
web系统中引入了session超时的概念,当很长一段时间(这个时间可以配置)没有用户再访问session对象,此时session对象超时,web服务器自动回收session对象
设置Session对象失效时间(两次请求之间的最大时间间隔),优先级 1 > 2 > 3
- 通过Java代码实现,单位秒
- 修改项目的web.xml文件,单位分钟
- 修改Tomcat默认配置,单位分钟,默认30分钟
5,HttpSession中的常用方法
void setAttribute(String name, Object value) //向会话范围中存储数据
Object getAttribute(String name) //从会话范围中获取数据
void removeAttribute(String name) //从会话范围中移除某个数据
void invalidate() //销毁session对象
void setMaxInactiveInterval(int interval) //设置session对象失效时间(浏览器向服务器两次请求之间最大时间间隔,超过最大设置时间间隔则销毁此session)
6,什么是一次会话?
- 一般可以这样理解:用户打开浏览器,在浏览器上发送多次请求,直到最终浏览器关闭,表示一次完整的回话。
- 本质上理解:Session对象创建到最终超时销毁,才是真正意义的一次会话;因为即使浏览器关闭,可以通过重写URL的方式从其他电脑其他浏览器同样使用这个Session对象。
7,HttpSession的应用
例如:报存用户登录状态,验证用户是否已登录
十,ServletContext、HttpServletRequest、HttpSession三者共享数据的区别
- ServletContext、HttpSession、HttpServletRequest对象都是范围对象。
- ServletContext是应用范围,整个项目、所有的Sevlet、所有的用户共享
- HttpSession是会话范围,同一个用户、同一个会话中多次请求共享
- HttpServletRequest是请求范围,单次请求共享(请求转发)
- 三者都可以通过
void setAttribute(String name, Object value) 和 Object getAttribute(String name)
方法共享数据 - application完成跨用户共享数据;
session完成跨请求共享数据,但是这些请求必须在同一个会话当中;
request完成跨Servlet共享数据,但是这些servlet必须在同一个请求当中(请求转发) - 使用原则:由小到大尝试,优先使用小范围
十一,乱码问题与路径问题总结
1,乱码问题
1.1 为什么出现请求乱码?
浏览器对请求数据的编码方式和服务器对请求数据的解码方式不同。Get请求的数据在URL中,属于URL编码;Post请求数据的编码方法即页面的编码方式
- 以Tomcat7.0为例,Tomcat会使用默认的ISO-8859-1进行解码,此时字符集可能与浏览器端编码的字符集不同而出现乱码
1.2 解决请求乱码的方法
(1)适用于Post请求和Get请求
//获取乱码字符
String value = request.getParameter("name");
//将乱码字符通过错误的ISO-8859-1编码方式重新还原回去
byte[] bytes = value.getBytes("ISO-8859-1");
//再通过正确的编码方式进行解码
value = new String(bytes, "UTF-8");
(2)仅支持Post请求
//设置字符编码方式
request.setCharacterEncoding("UTF-8");
//获取正确的字符
String value = request.getParameter("name");
(3)仅支持Get请求
注:Tomcat8之后针对于Get请求服务器会在程序中解决字符编码的问题;所以我们只需要处理Post请求的乱码问题即可
1.3 处理响应乱码
在获取输出流对象之前设置输出内容的类型和字符集,例如:
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
2,路径问题
2.1 Servlet中路径问题总结
web工程servlet中反斜杠"/"的表示含义:
如果路径是在浏览器端被解析,则"/"表示"http://ip地址:port/"
如果路径是在服务器端被解析,则"/"表示"http://ip地址:port/项目名/"
下面罗列了一些web工程中"/"的使用场景:
1,浏览器端被解析的场景:
- 设置项目资源的根路径,如果设置为"/",则浏览器端访问时不用写项目名,如下:
- 超链接:
<a href="/项目名/资源路径"</a>
- form表单:
<form action="/项目名/资源路径"</form>
- 重定向:
response.sendRedirect("/项目名/资源路径");
- 给Cookie绑定路径:
cookie.setPath("/项目名/资源路径");
2,服务器端被解析的场景:
-
Servlet路径:
-
请求转发:
request.getRequestDispatcher("/资源路径").forward(request,response);
-
获取资源的真实绝对路径:
context.getRealPath("/资源路径");
2.2 url-pattern的编写方式
- 一个Servlet可以编写多个url-pattern
- 精确匹配:
- 扩展匹配:
- 后缀匹配:
- 全部匹配:
十二,Servlet 3.0
从Servlet3.0开始,配置Servlet⽀持注解⽅式,同时保留了配置web.xml的⽅式。这降低了配置xml所花费的时间和精力。
服务器会在启动时读取注解
@WebServlet常⽤属性
例如:
注意:根元素web.xml中不能配置属性metadata-complete=“true”,否则⽆法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解,为Web应⽤程序构建有效的元数据;如果设置metadata-complete=“true”,会在启动时不扫描注解(annotation)。如果不扫描注解的话,⽤注解进⾏的配置就⽆法⽣效,例如:@WebServlet