Servlet
什么是Servlet?
Servlet是由SUN公司提供的一门动态Web资源开发技术
Servlet本质上是一段Java程序,和之前的Java程序不同的是,Servlet程序无法独立运行,需要将Servlet程序放在服务器中(比如tomcat服务器),由服务器调用才可以执行。
Servlet: 服务器端的Java程序.
Servlet是运行在服务器端的Java程序,其作用是什么?
其作用是对服务器接收过来的请求进行处理(作用为处理请求)
相关的接口与类
-
Servlet
接口初始化
init(ServletConfig config);
调用
service(ServletRequest Request, ServletResponse Response);
销毁
destroy();
-
GenericServlet
抽象类实现了Servlet接口中的部分方法
(init,destroy)
-
HttpServlet
抽象类
继承了GenericServlet
,实现了service
方法.
Servlet常用方法
返回值 | 方法 | 说明 |
---|---|---|
void |
doGet(略) |
处理get请求的方法 |
void |
doPost(略) |
处理post请求的方法 |
void |
init(略) |
初始化servlet方法 |
void |
destroy() |
销毁servlet方法 |
void |
service(略) |
servlet的核心方法, 能同时处理get和post请求 |
一个简单的servlet代码
servlet class, 需要继承HttpServlet
类
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 响应格式
response.setContentType("text/html;charset=utf-8");
// post提交使用utf-8, 否则会乱码(默认为iso8859-1)
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter(); // 获取输出流
// 获取提交参数
// request.getParameter("参数名"); // 返回String类型
// 如果一个参数名有多个参数值(多选框等), 则使用以下方法
// request.getParameterValues("参数名"); // 返回String[]
out.write("测试成功!"); // 以响应格式返回到浏览器
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
web.xml
<servlet>
<servlet-name>Test</servlet-name><!--servlet名字(可以随意命名)-->
<servlet-class>com.test.Test</servlet-class><!--servlet包名+类名, 不写.java后缀-->
</servlet>
<servlet-mapping>
<servlet-name>Test</servlet-name><!--servlet名字(和上面对应)-->
<url-pattern>/Test</url-pattern><!--访问的url-->
</servlet-mapping>
url-pattern有三种写法:
-
精确匹配:
即请求资源路径除掉应用名之后的值必须等于url-pattern的值。(比如这儿,请求资源路径除掉应用名之后是"/abc.html",url-pattern的值正好也是"/abc.html",这样就匹配了)
-
通配符匹配:
使用
*
匹配任意的零个或者多个字符。比如:
<url-pattern>/*</url-pattern> <url-pattern>/demo/*</url-pattern>
-
后缀匹配:
使用
*.
开头,然后接一个后缀(后缀就是一个字符串)。比如:
<url-pattern>*.do</url-pattern> 以上配置,会匹配所有以.do结尾的请求。 <url-pattern>*.action</url-pattern>
如果没有找到匹配的Servlet,则会找对应位置的文件.
@WebServlet注解
tomcaat7(servlet3.0)以及之后的版本, 有了一个注解, 可以省去web.xml的编写
@WebServlet
注解属性:
属性名 | 类型 | 描述 |
---|---|---|
name | String | 指定Servlet 的 name 属性,等价于 |
value | String[] | 该属性等价于 urlPatterns 属性。两个属性不能同时使用。 |
urlPatterns | String[] | 指定一组 Servlet 的 URL 匹配模式。等价于 |
loadOnStartup | int | 指定 Servlet 的加载顺序,等价于 |
initParams | WebInitParam[] | 指定一组 Servlet 初始化参数,等价于 |
asyncSupported | boolean | 声明 Servlet 是否支持异步操作模式,等价于 |
description | String | 该 Servlet 的描述信息,等价于 |
displayName | String | 该 Servlet 的显示名,通常配合工具使用,等价于 |
request和response介绍
request是代表HTTP请求信息的对象,response是代表HTTP响应信息的对象。
当浏览器发请求访问服务器中的某一个Servlet时,服务器将会调用Servlet中的service方法来处理请求。在调用service方法之前会创建出request和response对象。
其中request对象中封装了浏览器发送给服务器的请求信息(请求行、请求头、请求实体等),response对象中将会封装服务器要发送给浏览器的响应信息(状态行、响应头、响应实体),在service方法执行完后,服务器再将response中的数据取出,按照HTTP协议的格式发送给浏览器。
每次浏览器访问服务器,服务器在调用service方法处理请求之前都会创建request和response对象。(即,服务器每次处理请求都会创建request和response对象)
在请求处理完,响应结束时,服务器会销毁request和response对象。
Servlet的生命周期
什么是Servlet的声明周期?
容器如何创建Servlet实例,如何对其进行初始化处理,如何对其方法来处理请求,以及如何销毁其实例的整个过程.
生命周期分为那几个阶段
GenericServlet是HttpServlet的实现接口
-
实例化
什么是实例化?
容器调用Servlet的构造器,创建Servlet对象.
什么时候实例化?
- 默认情况下,容器收到请求之后,才会创建Servlet实例(容器只会创建一个实例!)
- 容器启动之后,立即创建Servlet实例(需要配置load-on-startup参数)
-
初始化
什么是初始化?
容器在实例化之后,会调用Servlet实例的
init
方法.(该方法只会执行一次!)GenericServlet已经提供了init方法的一个简单实现
所以,我们不写这个方法,也可以.
如果要实现自己的初始化处理逻辑,只需要override GenericSerlvet的init()方法.
-
调用(就绪)
什么是就绪?
容器收到请求之后,会调用Servlet实例的service方法来处理请求.
HttpServlet的service方法是这样实现的:
依据请求类型调用对应的doXXX方法.
比如 get 请求会调用doGet方法, post请求会调用doPost方法.
这些doXXX方法只是抛出来的异常.
-
销毁
什么是销毁?
容器在删除Servlet实例之前,会调用该实例的destroy方法.该方法只会调用一次.
GenericServlet已经实现了destroy方法.
Servlet的线程安全问题
为什么说Servlet会有线程安全问题?
容器只会创建一个Servlet实例
容器收到请求之后,会启动一个线程,由该线程来调用Servlet来处理请求. 这样一来,就有可能有多个线程同时去调用某个Servlet实例,就有可能发生线程安全问题. 比如,这些线程同时去修改Servlet实例的某个属性.
如何解决?
使用synchronized
对有可能产生线程安全问题的代码加锁.
注意,加锁会影响性能.