1、Servlet介绍:
Servlet是运行在服务端的Java程序,是sun公司提供的一套规范,用来处理客户端的请求,响应给浏览器的动态资源。
2、Servlet规范简介,Web框架如何注入到Servlet当中:
Web框架一般是通过一个Servlet提供统一的请求入口,将指定的资源映射到这个servlet上,然后在这个servlet中进行框架的初始化配置,访问Web页面中的数据,进行逻辑处理后,将结果数据与表现层相融合并展现给用户。WEB框架想要在符合Servlet规范的容器中运行,同样也要符合Servlet规范。
将一个WEB框架注入到一个servlet中,主要涉及到Servlet规范中以下部分:部署描述符; 映射请求到Servlet;Servlet生存周期;请求分发;
部署描述符:
部署描述符就是位于WEB应用程序的/WEB-INF目录下的web.xml的XML文件,是WEB应用程序不可分割的部分,管理着WEB应用程序的配置。部署描述符在应用程序开发人员,应用程序组装人员,应用程序部署人员之间传递WEB应用程序的元素和配置信息。
XML声明:DTD约束
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
根据DTD约束典型的Servlet声明格式:
<servlet> <servlet-name>catalog</servlet-name> <servlet-class>com.mycorp.CatalogServlet</servlet-class> <init-param> <param-name>catalog</param-name> <param-value>Spring</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>catalog</servlet-name> <url-pattern>/catalog/*</url-pattern> </servlet-mapping>
通过上面方法,我们就声明了一个名称为catalog的Servlet,它的实现类为com.mycorp.CatalogServlet,并且带有一个catalog参数,参数值为Spring,所有向/catalog/*的请求都被映射到名称为catalog的Servlet。
映射请求到Servlet:
接收到一个请求后,WEB容器要确定转到哪一个WEB应用程序。被选择的应用程序的最长的上下文路径必须和请求的URL开始部分匹配。URL匹配的部分是映射到Servlet的上下文路径。WEB容器下一步必须按照下面的程序定位处理请求的Servlet。
用来映射到Servlet的路径是请求对象的URL减去上下文的路径。下面的URL路径映射规则按顺序执行,容器选择第一个成功的匹配并且不在进行下一个匹配:
Ø 容器试着对请求的路径和Servlet的路径进行精确匹配,如果匹配成功则选择这个Servlet。
Ø 容器会循环的去试着匹配最长的路径前缀:把’/’当作路径分隔符,按照路径树逐级递减的完成,选择最长匹配的Servlet。
Ø 如果这个URL路径的最后有扩展名(比如.jsp),Servlet容器会试着匹配处理这个扩展名的Servlet。
Ø 如果前面的没有与前面三条规则相匹配的Servlet,容器会试着为资源请求提供适当的资源,如果有“默认”的Servlet定义给这个应用程序,那么这个Servlet会被使用。
WEB容器允许显式的声明隐含映射以获得优先级,例如,*.shtml的隐含映射可以在服务器上被映射为包含功能。
映射实例:
path pattern
servlet
/foo/bar/*
servlet1
/baz/*
servlet2
/catalog
servlet3
*.bop
servlet4
下面是实际请求映射的结果:
incoming path
servlet handling request
/foo/bar/index.html
servlet1
/foo/bar/index.bop
servlet1
/baz
servlet2
/baz/index.html
servlet2
/catalog
servlet3
/catalog/index.html
“default” servlet
/catalog/racecar.bop
servlet4
/index.bop
servlet4
请注意/catalog/index.html 和/catalog/racecar.bop这两种情况,因为是精确匹配,所以并没有映射到处理/catalog的servlet。
2、Servlet的生命周期:指Servlet的对象从被创建到被销毁的过程。
a:Servlet接口
在介绍Servlet的生存周期之前需要先介绍一下javax.servlet.Servlet接口。所有的Servlet必须实现或者间接实现这个接口,我们通常可以通过继承javax.servlet.GenericServlet或者javax.servlet.http.HttpServlet.类来实现这个接口。HttpServlet继承了GenericServlet;
b:Servlet接口中五个方法:
void init(ServletConfig config) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest req, ServletResponse rsp) throws ServletException, IOException; String getServletInfo(); void destroy();
构造器:
- Servlet第一次处理请求时,会调用构造器,来创建Servlet实例(服务器创建,例如Tomcat)。
- 只会调用一次,Servlet是单例模式,他是以多线程的方式调用service()方法.
- Servlet不是线程安全,所以尽量不要再service()方法中操作全局变量。
init(ServletConfig config)方法:`
构造器调用之后马上被调用,用来初始化Servlet,init方法在容器装入Servlet 时执行,Servlet容器在实例化后只调用一次init方法, init方法必须在servlet接收到任何请求之前完成。这个方法通常用来进行一些资源的管理和初始化。读取配置文件中的配置数据,由Tomcat服务器创建ServletConfig对象,将ServletConfig对象传到init()方法中,进行Servlet的初始化。作用:从配置文件读取配置数据,读取初始化参数,初始化缓冲迟等一次性的操作。
getServletConfig()方法:
getServletConfig方法返回一个 ServletConfig 对象,该对象用来返回这个Servlet的初始化信息和启动参数。返回的是传递到init方法中的参数信息的对象ServletConfig。
Service(ServletRequest req, ServletResponse rsp)方法:
Servlet每次处理请求时服务器都会创建一个新的线程,访问service()方法,用来处理请求,会调用多次,在Service方法中决定调用get请求,还是post请求,然后响应的调用doXxx方法。Service方法是应用程序逻辑的进入点,是servlet方法的核心,WEB容器调用这个方法来响应进入的请求,只有servlet成功被init()方法初始化后,Service方法才会被调用。
getServletInfo()方法:
这个方法返回一个字符串对象,提供有关servlet 的信息,如作者、版本等。
destroy()方法:
Servlet对象销毁前(WEB项目关闭时,或者从服务器移除时)调用,用来做一些收尾工作,释放资源,destroy方法在容器移除Servlet 时执行,同样只执行一次。这个方法会在所有的线程的service()方法执行完成或者超时后执行,调用这个方法后,容器不会再调用这个servlet的方法,也就是说容器不再把请求发送给这个Servlet。 这个方法给servlet释放占用的资源的机会,通常用来执行一些清理任务。
c:执行顺序:
默认情况,当用户第一次发送请求,Servlet被服务器容器(Tomcat)创建(一种类型的Servlet只会创建一次!)!读取配置文件数据,服务器创建ServletConfig对象,对数据进行封装传递到init方法中,接着会调用init(ServletConfig config)方法来完成初始化!在整个Servlet生命周期中,该方法只会被调用一次!然后调用service(ServletRequest req,ServletResponse resp)方法来处理用户的请求,该方法在整个Servlet生命周期中会被调用
多次(用户发送一次请求就调用一次)!当我们正常关闭服务器的时候(关闭之前),会调用destroy()方法来进行销毁!该方法在整个Servlet生命周期中会被调用一次。
3、请求分发:
请求分发可以让一个Servlet把请求分配到另外一个资源,RequestDispatcher接口提供了实现他的机制。可以通过下面两种方式从ServletContext中获得一个实现了RequestDispatcher接口的对象:
方法一:getRequestDispatcher(String url );接受一个指向目标资源的URL路径,
方法二:getNamedDispatcher(String name );接受一个Servlet名称,这个名称是在部署描述符中<servlet-name>元素指定的那个名称。
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //获取具有处理请求分发能力的实现了RequestDispatcher接口的对象 RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher("/catlog");//指定一个url requestDispatcher.forward(request, response); RequestDispatcher catlog = getServletContext().getNamedDispatcher("catlog");//指定名称 catlog.forward(request, response); }
RequestDispatcher接口有两个方法,允许你在调用的servlet完成初步处理后把请求响应分配到另外一个资源;
void forward(ServletRequest req, ServletResponse rsp) throws ServletException, IOException; void include(ServletRequest req, ServletResponse rsp) throws ServletException, IOException;
forward方法上让你把请求转发到另外的Servlet或者jsp或者html等资源,由这个资源接下来负责响应。
include方法让你的Servlet响应中包含另外一个资源生成内容。
4、Servlet体系结构及Servlet运行流程:
1、Servlet简介: > Server + let,意为:运行在服务器端的小程序。
> Servlet实际上是一个接口。
- 狭义上的Servlet,指的就是Servlet接口
- 广义上的我们认为凡是实现Servlet接口的类,我们都称他是一个Servlet
> Servlet的作用:
1:接收用户发送的请求
2:调用其他的java程序来处理请求
3:根据处理结果,返回给用户一个页面
> Servlet的Demo
1:创建一个类并实现Servlet接口,或继承一个已经实现了Servlet的类,example:HttpServlet
2:在web.xml文件中对Servlet进行配置,配置具有处理请求能力的Servlet类,配置映射关系。
> Servlet的三个名字:
<servlet-name>
- Servlet的别名,通过别名对Servlet进行配置
<servlet-class>
- Servlet的全类名,服务器通过全类名来创建Servlet的实例
<url-pattern>
- Servlet映射的请求地址,用户通过该地址访问Servlet
2、Servlet的生命周期:
> Servlet的生命周期,指Servlet的对象从被创建到被销毁的过程。
> Servlet的生命周期方法:
1.构造器:
- Servlet第一次处理请求时,会调用构造器,来创建Servlet实例。
- 只会调用一次,Servlet是单例模式,他是以多线程的方式调用service()方法.
- Servlet不是线程安全,所以尽量不要再service()方法中操作全局变量。
2.init()方法:
- 构造器调用之后马上被调用,用来初始化Servlet,只会调用一次。
3.service()方法:
- Servlet每次处理请求时都会调用service()方法,用来处理请求,会调用多次。
4.destroy()方法:
- Servlet对象销毁前(WEB项目卸载时)调用,用来做一些收尾工作,释放资源。
3、相关对象:
①ServletConfig:Servlet容器使用的Servlet配置对象,该对象在初始化期间将信息传递给Servlet。
代表:当前Servlet的配置信息,每一个Servlet都有其唯一对应的ServletConfig。
<servlet> <servlet-name>AServlet</servlet-name> <servlet-class>com.atguigu.servlet.AServlet</servlet-class> <init-param> <param-name>user</param-name> <param-value>root</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>123123</param-value> </init-param> </servlet>
//获得指定初始化参数的值(需要在web.xml文件中去配置!) String getInitParameter(String name) //获得所有的初始化参数名称(需要在web.xml文件中去配置!) Enumeration getInitParameterNames() //获得ServletContext对象(整个应用的上下文对象!) ServletContext getServletContext() //获得当前Servlet的名称! String getServletName()
获取:ServletConfig对象由Tomcat服务器创建,配置信息最终作为参数传递到init(ServletConfig conf)方法中,我们可以在init()方法直接使用。当我们通过继承HttpServlet创建Servlet时,由于父类已经实现ServletConfig接口,所以我们可以在Servlet中直接调用ServletConfig的方法。
功能:
【1】 获取Servlet的别名
【2】 获取当前Servlet的初始化参数。
【3】 获取当前WEB应用的ServletContext对象。
②ServletContext
代表:当前的WEB应用,一个WEB应用对应一个唯一的ServletContext对象,ServletContext对象在项目启动时创建,在项目卸载时销毁。
获取:通过ServletConfig的getServletContext()方法获取。
功能:
【1】 可以获取整个WEB应用的初始化参数
【2】 可以获取资源的真实路径(物理路径),主要在文件的上传和下载时使用。
【3】 可以作为一个域对象在不同的web资源之间共享数据。
<context-param> <param-name>phone</param-name> <param-value>1388888888</param-value> </context-param>
4、GenericServlet:
- 通用Servlet的父类
- 相比Servlet接口GenericServlet更加简单一些,但是我们最终实际上使用的HttpServlet
5、HttpServlet:两个service方法。参数不同。
- HttpServlet继承了GenericServlet,而GenericServlet实现Servlet接口,所以我们可以同构继承HttpServlet来创建一个Servlet。
- HttpServlet重写service()方法:
1:在该方法中先将ServletRequest和ServletResponse,强转为了HttpServletRequest和HttpServletResponse。
2:然调用重载的service()方法,并将刚刚强转得到对象传递到重载的方法中。
3:重载service(HttpServletRequest request , HttpServletResponse response)
1:在方法中获取请求的方式(get或post)
2:在根据不同的请求方式去调用不同的方法:
如果是GET请求,则调用doGet(HttpServletRequest request , HttpServletResponse response)
如果是post请求,则调用doPost(HttpServletRequest request , HttpServletResponse response)
- 结论:
当通过继承HttpServlet来创建一个Servlet时,我们只需要根据要处理的请求的类型,来重写不同的方法。
处理get请求,则重写doGet()
处理post请求,则重写doPost()
6、HttpServletRequest:
代表:浏览器发送给服务器的请求报文。
获取:该对象由Tomcat服务器创建,最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用。
功能:
【1】获取用户发送的请求参数
request.getParameter("username");
【2】获取项目的名字(用来设置绝对路径)
request.getContextPath();
【3】作为一个域对象,在不同的WEB资源之间共享数据。
【4】请求的转发(相对路径)
request.getRequestDispatcher("target.html").forward(request, response);
7、HttpServletResponse:
代表:服务器发送给浏览器的响应报文。
获取:该对象由Tomcat服务器创建,最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用。
功能:
【1】响应给浏览器一个网页或者是网页片段(设置的是响应报文的响应体)
response.getWriter("响应到页面");
【2】请求的重定向(绝对路径)
response.sendRedirect("target.html");
转发和重定向:
转发 重定向
请求的次数: 1 2
发生的位置: 服务器内部 浏览器
浏览器地址栏: 不改变 改变
浏览器的感知: 未感知 感知
8、字符编码:
> 当用户通过表单向Servlet发送中文请求参数时,Servlet获取到内容会产生乱码,当Servlet向浏览器响应中文内容时,也会产生乱码。
> 浏览器和服务器之间通信时,中文内容时不能直接发送的,需要对中文进行编码。
> 编码:
- 将字符转换为二进制码的过程叫编码。
> 解码:
- 将二进制码转换为普通字符的过程叫解码。
> 编码和解码所采用的规则我们称为字符集。常见的字符集:
- ASCII、ISO8859-1、GBK、GB2312、UTF-8
> 产生乱码问题的根本原因:
编码和解码所采用的字符集不同。
> 解决方法:
统一编码和解码的字符集为UTF-8。
> 请求编码
- 请求是浏览器发送给服务器的。浏览器 --> 服务器,浏览器的会自动使用网页的字符集对参数进行编码
UTF-8的张三:%E5%BC%A0%E4%B8%89
GBK的张三:%D5%C5%C8%FD
- 所以我们只需要统一网页的字符集为UTF-8即可。
> 服务器解码
tomcat7以上的版本,对于path的内容,会自动用utf-8去解码。其也可以在server.xml中去配置。
而tomcat7以及以下的版本,默认的字符集依然是iso-8859-1。因此需要通过对应的格式去decode。
post请求
> request解码时默认字符集时iso8859-1,但是iso压根就不支持中文
> post请求在servlet中解码,所以我们只需要指定request的字符集即可。
> 我们可以通过如下方法,来设置request的字符集:
request.setCharacterEncoding("utf-8");
> 注意:
该方法要在request.getParameter()第一次调用之前调用
get请求
> get请求是通过url地址传递请求参数,url中的请求参数将会被Tomcat服务器自动解码。
> Tomcat的默认编码是iso8859-1,但是iso压根就不支持中文,所以必然乱码。
> 只需要修改Tomcat的解码的默认字符集,修改配置文件server.xml
> 在server.xml的Connector标签中(改端口号的那个标签)添加如下属性:
URIEncoding="utf-8"
> 修改完配置文件以后,get请求的编码就不用再处理的,但是post请求还是老样子。
> 响应编码
- 响应是服务器发送给浏览器 - 服务器 --> 浏览器
> 指定服务器的编码字符集为UTF-8。
> 指定response的字符集
response.setCharacterEncoding("utf-8");
> 虽然我们已经指定了response的字符集为utf-8,但是浏览器并不是用utf-8解码。
浏览器默认使用gb2312解码的,所以依然乱码,只不过没有那么乱。
> 浏览器 解码
> 浏览器的解码字符集可以通过浏览器来设置(不靠谱)
> 我们可以通过服务器来告诉浏览器,我们的内容的编码格式为utf-8
> 我们可以通过一个响应头来告诉浏览器,内容的编码格式:
Content-Type:text/html;charset=utf-8
> 通过response的方法,来设置响应头:
response.setHeader("Content-Type", "text/html;charset=utf-8");
解决方案:
1.设置响应头
response.setHeader("Content-Type", "text/html;charset=utf-8");
2.设置response的编码格式
response.setCharacterEncoding("utf-8");
> 当我们设置Content-Type这个响应头时,服务器会自动使用响应头中的字符集为内容编码
> 最终方案:
response.setContentType("text/html;charset=utf-8");
<<总结>>
post请求:
- 在request.getParameter()方法第一次调用之前,调用如下代码:
request.setCharacterEncoding("utf-8");
get请求:
- 修改server.xml配置文件
- <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
响应:
- 设置一个Content-Type响应头
response.setContentType("text/html;charset=utf-8");
10、路径问题:
> URI和URL
- URL是URI的一种实现,也是URI最常见的实现方式。
- URI有两种实现方式URL和URN,URN用的很少
- 我们说URL和URI实际上可以理解为一个意思
> URL地址的格式
http://主机名:端口号/项目名/资源路径/资源名
①相对路径和绝对路径
> 相对路径:所谓的相对路径指相对于当前资源所在路径:
http://主机名:端口号/项目名/资源路径/
- 由于转发的出现,相对路径会经常发生变化,容易出现错误的链接
所以在开发中我们一般不使用相对路径,而是使用绝对路径。
> 绝对路径:- 绝对路径使用/开头,
- 由浏览器解析的绝对路径中的/代表的是服务器的根目录:
http://主机名:端口号/项目名/
注意:需要加上项目名
- 由服务器解析的绝对路径中的/代表的项目的根目录:
http://主机名:端口号/
注意:不要加项目名
- 转发的路径由服务器解析,设置绝对路径时不需要加项目名
- 重定向的路径由浏览器解析,设置绝对路径时需要加上项目名
②常见的路径:
url-pattern:
- url-pattern和转发中的路径都是由服务器解析的,
根目录是项目的根目录:
http://主机名:端口号/
- 所以这两个路径不需要加项目名
重定向的路径:
- 重定向和页面中的路径(HTML标签中的路径),由浏览器解析的,
根目录是服务器的根目录:
http://主机名:端口号/项目名
- 所以这个两个路径必须加上项目名
11、运行流程:
12、HttpServlet:
部分转自:http://www.cnblogs.com/libingbin/,修改,理解。