现在学习Servlet,我的主要目的是做整体了解,作为学习SSM的热身,所以本篇的目的是以一篇文章实现对servlet的基本概括。
简介
java servlet是运行在Web 服务器或应用服务器上的程序,是一个中间层,介于web浏览器(HTTP客户端)——HTTP服务器上的数据库或应用程序之间
本质上,servlet是运行在web服务器上的java类,Servlet 可以使用 javax.servlet 和 javax.servlet.http 包创建
任务
Servlet主要执行以下任务:
- 读取B/C发送的HTTP请求数据(表单、cookies等)
- 处理请求生成结果,通过访问数据库、计算、远程调用等方式产生结果
- 发送给B/C相关的HTTP答复
生命周期
-
init()
进行Servlet初始化,方法只被调用一次;
Servlet创建于用户第一次调用对应该Servlet的URL,当然也可以指定Servlet在服务器第一次启动时即加载;
用户调用一个Servlet时,就会创建一个Servlet实例,每次请求都会产生一个新的线程,适当的时候交给doGet或doPost
-
service()
执行任务的主要方法,容器调用service()处理客户端请求并将格式化的响应返回客户端;
一个Servlet请求会有一个线程,线程内会调用本方法检查HTTP请求类型,并在适当时候调用doGet、doPost等方法
-
destroy()
在此Servlet将终止,使得Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动,仅被调用一次;
调用此方法后,Servlet对象被标记为垃圾回收
-
回收
Servlet由JVM的GC进行垃圾回收
- 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器
- Servlet 容器在调用 service() 方法之前加载 Servlet
- Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
Servlet部署
默认情况下,Servlet 应用程序位于路径 <Tomcat-installation-directory>/webapps/ROOT 下,且类文件放在 <Tomcat-installation-directory>/webapps/ROOT/WEB-INF/classes 中
举个例子,把aaa.class放入./ROOT/WEB-INF/classes中,并在位于./WEB-INF/下的web.xml中创建如下条目:
<web-app>
<servlet>
<servlet-name>aaa</servlet-name> 当前servlet的名字
<servlet-class>aaa</servlet-name> 对应的aaa.class
</servlet>
<servlet-mapping>
<servlet-name>aaa</servlet-name>
<url-pattern>/AAA</url-pattern> URL(表示需要在输入的网址的末尾添加/AAA标志特定的URL)
</servlet-mapping>
</web-app>
在aaa.class类之前需要加上@WebServlet("/AAA")
使用Servlet读取表单数据
-
getParameter()
调用 request.getParameter()来获取表单参数的值。
-
getParameterValues()
如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
-
getParameterNames()
调用该方法可以得到当前请求中的所有参数的完整列表
举个例子:
前端:
<form action="FormTest" method="GET">
名:<input type="text" name="name">
<br />
手机:<input type="text" name="url" />
<input type="submit" value="提交" />
分别输入:aaa 5656456
经get后的URL为:
.../URL?name=aaa&url=5656456
后台:
使用request.getParameter("name")获取name
Servlet过滤器
-
使用过滤器的目的:
- 客户端请求到达时,拦截请求
- 服务器的响应发回客户端前,处理响应
过滤器通过Web部署描述符web.xml中的XML标签来声明,然后映射到应用程序的部署描述符中的Servlet名称或URL模式
当Web容器启动Web应用程序时,它会为web.xml中声明的每一个过滤器创建一个实例,Filter的执行顺序与在web.xml配置文件中filter-mapping的配置顺序一致,一般把Filter配置在所有的Servlet之前
seq | 方法&描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器(调用其doFilter()方法往后传)。 |
2 | public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能(filter对象只会创建一次,init方法也只会执行一次)。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
3 | public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:
seq | 方法&描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器(调用其doFilter()方法往后传)。 |
2 | public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能(filter对象只会创建一次,init方法也只会执行一次)。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
3 | public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
关于使用filterConfig举个例子
web.xml中:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.kindol.test</filter-class> test为相应的实现Filter接口的类
<init-param>
<param-name>testYo</param-name>
<param-value>abc</param-value>
</init-param>
</filter>
在test类(实现Filter接口)中的init方法:
public void init(FilterConfig filterConfig)
{
String testYo = config.getInitParameter("testYo");
System.out.println("testYo: " + testYo);
}
在整个web.xml中配置如下
<web-app>
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.kindol.test</filter-class> test为相应的实现Filter接口的类
<init-param>
<param-name>testYo</param-name>
<param-value>abc</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern> 设置 filter 所拦截的请求路径,/*表示适合所有Servlet,可以指定特定Servlet路径(此时将url-pattern改为servlet-name)
<dispatcher>REQUEST</dispatcher> 没有配置dispatcher就是默认request方式
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>myServlet</servlet-name> 类名
<servlet-class>com.kindol.myServlet</servlet-class> 所在的包
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/TomcatTest/myServlet</url-pattern> url对应的所访问的网址
</servlet-mapping>
</web-app>
web.xml配置各节点说明
- <filter>指定一个过滤器
- <filter-name>过滤器的名字
- <filter-class>过滤器的完整的限定类名
- <init-param>初始化参数,子元素<param-name>指定参数的名字,<param-value>指定参数的值
- </filter>
- <filter-mapping>设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
- <filter-name>设置filter的注册名称,该值必须是在<filter>元素中声明过的过滤器的名字
- <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
- <servlet-name>指定过滤器所拦截的Servlet名称(与上面的二选一)
- <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是以下四种方式之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截
- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器;若通过如下两种方法访问则不调用此过滤器
- INCLUDE:目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用
- FORWARD:目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用
- ERROR:目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用
Servlet异常处理(未看)
Servlet Cookie处理
Servlet Cookie 处理需要对中文进行编码与解码,方法如下:
String str = java.net.URLEncoder.encode("中文","UTF-8"); //编码
String str = java.net.URLDecoder.decode("编码后的字符串","UTF-8"); // 解码
Cookie通常设置在HTTP头消息中,比如下方:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=runoob.com
Connection: close
Content-Type: text/html
当中,Set-Cookie 头包含了一个名称值对、一个GMT日期、一个路径和一个域。名称和值会被 URL 编码。expires 字段是一个指令,告诉浏览器在给定的时间和日期之后"忘记"该 Cookie
在浏览器这边,如果浏览器被配置为存储 Cookie,它将会保留此信息直到到期日期。如果用户的浏览器指向任何匹配该 Cookie 的路径和域的页面,它会重新发送 Cookie 到服务器。
Servlet 通过请求方法 request.getCookies() 访问 Cookie,该方法返回一个 Cookie 对象的数组
部分Servlet操作Cookie的方法列表
seq | 方法 & 描述 |
---|---|
1 | public void setDomain(String pattern) 该方法设置 cookie 适用的域,例如 runoob.com。(与之对应的还有getDomain()方法取得cookie适用的域) |
2 | public void setMaxAge(int expiry) 该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。(与之对应的还有getMaxAge(),如果返回-1则表示cookie将持续下去直到浏览器关闭) |
3 | public String getName() 该方法返回 cookie 的名称。名称在创建后不能改变。 |
4 | public void setValue(String newValue) 该方法设置与 cookie 关联的值。(与之对应的有getValue()获取与cookie关联的值) |
5 | public void setPath(String uri) 该方法设置 cookie 适用的路径。如果不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。 |
6 | public void setSecure(boolean flag) 该方法设置cookie表示其是否在加密的(即 SSL)连接上发送 |
7 | public void setComment(String purpose) 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用(与之对应的getComment()可以获得cookie的注释) |
删除Cookie:
先获得所要删除的cookie(可以通过getName判断是否为所要的cookie),通过setMaxAge()方法将cookie的年龄设为0,将cookie添加到响应头
Servlet Session跟踪
Servlet 提供了 HttpSession 接口,而且,在向客户端发送任何文档内容之前调用 request.getSession()
一些常用方法
使用request.getSession()得到HttpSession对象,当中可以设置参数true表示如果没有创建则创建一个HttpSession对象
seq | 方法 & 描述 |
---|---|
1 | public Object getAttribute(String name) 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。(对应removeAttribute()删除指定名称的对象、setAttribute(String name, Object value)在session绑定一个对象到指定名称中) |
2 | public Enumeration getAttributeNames() 该方法返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。 |
3 | public long getCreationTime() 该方法返回该session会话被创建的时间,以毫秒为单位 |
4 | public String getId() 该方法返回一个包含分配给该session会话的唯一标识符的字符串。 |
5 | public long getLastAccessedTime() 该方法返回客户端最后一次发送与该 session 会话相关的请求的时间,以毫秒为单位。 |
6 | public int getMaxInactiveInterval() 该方法返回Servlet容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位(对应setMaxInactiveInterval(int interval)设置时间)。 |
7 | public void invalidate() 该方法指示该session会话无效,并解除绑定到它上面的任何对象 |
8 | public boolean isNew() 如果客户端还不知道该session会话,或者如果客户选择不参入该 session 会话,则该方法返回 true |
删除Session会话数据:
- 移出特定属性:removeAttribute(String name)
- 删除整个session会话:invalidate()
- 设置会话过期时间:setMaxInactiveInterval(int interval)
- web.xml配置(使用Tomcat时)
<session-config>
<session-timeout>15</session-timeout> Tomcat默认为30min,但此处可以覆盖
</session-config>
Servlet网页重定向
使用如下方法
public void HttpServletResponse.sendRedirect(String location) throws IOException
也可以通过 setStatus() 和 setHeader() 达到一个效果
String site = "www.a.com";
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
原本的URL访问http://abc.com/本servlet过滤器后,URL会变成www.a.com
Servlet点击计数器
步骤如下:
- 在 init() 方法中初始化一个全局变量
- 每次调用 doGet() 或 doPost() 方法时,都增加全局变量
- 如果需要,使用一个数据库表来存储全局变量的值在 destroy()中。在下次初始化 Servlet 时,该值可在 init() 方法内被读取
- 如果只想对一个 session 会话计数一次页面点击,那么使用 isNew() 检查该 session 会话是否已点击过相同页面
Servlet自动刷新页面
比如股票市场等,都需要自动刷新页面
Servlet中,使用此函数
public void setIntHeader(String header, int headerValue)
此方法把头信息 "Refresh" 连同一个表示时间间隔的整数值headerValue(以秒为单位)发送回浏览器
Servlet包
涉及到 WEB-INF 子目录的 Web 应用程序结构是所有的 Java web 应用程序的标准,并由 Servlet API 规范指定。给定一个顶级目录名 myapp,目录结构如下所示:
/myapp
/images
/WEB-INF
/classes 包含了所有的Servlet类和其他类文件
/lib
WEB-INF 子目录中包含应用程序的部署描述符(即web.xml)。所有的 HTML 文件都位于顶级目录 myapp 下。对于 admin 用户,会发现 ROOT 目录是 myApp 的父目录
WEB-INF/classes 目录包含了所有的Servlet类和其他类文件,类文件所在的目录结构与他们的包名称匹配。例如,如果有一个完全合格的类名称 com.myorg.MyServlet,那么这个 Servlet 类必须位于以下目录中:
/myapp/WEB-INF/classes/com/myorg/MyServlet.class
Servlet调试
- println()
- 消息日志(log4J)
- log()——Servlet API提供的简单输出信息的方式,记录在Servlet容器的日志文件中,例子如下
ServletContext context = getServletContext( );
if (par == null || par.equals(""))
context.log("No message received:",
new IllegalStateException("Missing parameter")); // 通过 Throwable 参数记录版本
else
context.log("Here is the visitor's message: " + par);
- 查看原始HTTP请求与相应
- 使用注释
参考:
Servlet-菜鸟教程