Servlet概述
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
简单的说,Setvlet就是应用在服务端的java程序
Servlert的作用
- 读取客户端(浏览器)发送的显式数据。包括网页上的HTML表单,或者也可以是来自applet或自定义的HTTP客户端程序的表单
- 读取客户端(浏览器)发送的隐式的Http请求数据。包括cookies,session等
- 处理数据并生成结果。这一阶段可能需要访问数据库,访问Web服务,或者直接计算得出对应的响应
- 发送显式的数据到客户端(浏览器)。例如文本文件(HTML或XML),二进制文件(GIF图像),Excel等
- 发送隐式的HTTP响应到客户端(浏览器)。例如Cookies或者缓存参数
Servlet程序入门
创建一个maven web项目
点击File,新建Project项目
选中Maven,勾上Creater from archetype选项,按照体重蓝色选中后点击Next按钮即可
依次填写groupid和artifactid后点击next即可
选中提前配置好的maven,点击next
输入项目名称Spring,点击Finish即可
这样就创建好了一个名称为Spring的maven项目,结构如下图:
实现Servlet接口
- 创建MyServlet类实现Servlet接口,重写5个方法,有init(初始化),service(服务),destory(销毁),getServletInfo(Servlet信息),getServletConfig(Servlet配置)
/**
* 实现Servlet接口编写Servlet程序
*/
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("ServletConfig");
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service");
}
@Override
public String getServletInfo() {
System.out.println("getServletInfo");
return null;
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
- 编辑service方法,向浏览器输出Hello~~~~
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service");
servletResponse.getWriter().write("hello~~~");
}
- 配置web.xml文件为最新的
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.cn.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
<web-app>
- 关于上面的配置信息:
每创建一个Servlet,我们都需要在web.xml文件中添加两个标签,和(可以将这两个标签看做是一组标签)
两个标签内都会有标签,内容可以修改,但是必须保证两个标签更改后的内容必须保持一致
用于配置servlet的全路径名
用于配置浏览器以什么路径去访问该Servlet类,默认的路径名为/类名
例如:MyServlet类配置的标签为/MyServlet,因此我们在浏览器上的访问路径就是
http://主机名/web项目访问路径/MyServlet
5.部署都Tomct中,
- 点击右上角的配置按钮,在下拉框中选中Edit Configurations
- 在弹出的Configurations界面中,按照图中标识的序号选中
- 点击地址栏旁边的按钮,选中需要的Tomcat版本号
- 点击Deployment,按照图中序号进行操作
在弹出的窗口上选中MyServlet:war 或者MyServlet:war exploded
最后一步,依次点击apply, ok按钮,到此我们的项目就已经部署到了Tomcat服务器上
启动服务器,访问自己配置的MyServlet程序
Servlet的调用过程
思考:上一节我们通过浏览器访问服务器中的MyServlet,可以在页面上看到MyServlet类返回的结果,那么这个Servlet是如何被调用的呢?Servlet又是怎么被执行的?
- 浏览器发送请求
- 浏览器发送http请求后,根据请求行中的资源路径获知浏览器访问的是哪一个WEB应用,哪一个资源
- 然后在web.xml中进行匹配,匹配真实的路径
- 服务器创建对象
- 服务器根据真实的路径,通过反射创建Servlet实例,也就是MyServlet类
- 调用init()方法
- MyServlet实例创建后首先要执行init()方法,进行初始化
- 如果我们还需要新增一些功能,可以重写该方法
- 调用service()方法
- 然后服务器会先创建两个对象,ServletRequest请求对象和ServletResponse响应对象,用来封装浏览器的请求数据和封装向浏览器的响应数据
- 执行完service()方法内的业务后,将响应数据放在ServletResponse响应对象发送给浏览器
- 浏览器做出响应
- 服务器从ServletResponse响应对象中获取要发送给浏览器的数据,按照HTTP协议规定的方式(格式)组织成响应信息,再发给浏览器,调用过程完成
Servlet的生命周期
- 加载Servlet
- 当我们在浏览器第一次访问Servlet的时候,Tomcat会负责创建该Servlet的实例
- 初始化
- 当Servlet实例化后,Tomcat会立即调用init()方法初始化对象
- 处理请求服务
- 当浏览器访问Servlet的时候,Tomcat会调用service()方法处理请求
- 销毁
- 当Tomcat关闭或者检测到Servlet从Tomcat中删除的时候会自动调用destroy()方法,让该实例释放所占用的空间
- 卸载
- 当Servict调用完destroy()方法后,会等待垃圾回收。如果有需要再次使用这个Servict,service()方法就会再次被调用
继承HttpServlet类
在上面我们是实现了Servlet接口后,需要实现5个方法这样太麻烦了
而接下来我们要介绍的是HttpServlet这个类,它实现了Servlet接口的所有方法,并且还在原有的基础上添加了与HTTP协议处理的一些方法,比Servlet接口更为强大
因此我们在编写Servlet的时候,只需要继承HttpServlet这个类,也就是间接的实现了Servlet接口,我们关注的只是重新我们需要的方法即可
- 一般我们在开发的时候都是重写doGet()和doPost()方法
public class Demo1 extends HttpServlet {
/**
* 在我们开发的过程中,通常我们使用doGet,doGet来处理请求,
* 但是不论是哪一种方法,处理方式都是一样的
* 因此我们可以在doGet方法时,重新调用会doPost方法进行处理
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello~~~");
}
}
Servlet细节
一个已经被注册的Servlet可以被多次映射
同一个Servlet被映射在多个URL上
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.cn.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> <!--多次映射--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet1</url-pattern> </servlet-mapping>
无论我访问的是http://localhost:8080/MyServlet还是http://localhost:8080/MyServlet1,被调用的全部都是MyServlet这个类
Servlet映射的URL可以使用通配符
两种格式:
- * . 扩展名
- / *
匹配所有
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.cn.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
匹配扩展名为.jsp的
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.cn.MyServlet</servlet-class> <!--<load-on-startup>1</load-on-startup>--> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping>
Servlet是单例的
上述的Servlet生命周期介绍过,如果浏览器多次对Servlet的请求,一般情况下服务器只创建一个对象,并保存在内存中,为后续的请求做准备
对于每次访问请求,Servlet都会创建一个新的HttpServletRequest对象和HttpServletResponse对象,然后将这两个对象作为参数传递给它的service()方法,service()方法再根据请求的方式调用它的doGet()或者doPost()方法
而当多个用户访问共享的Servlet的时候,服务器会为每个用户创建一个线程,因此一起访问的时候就会出现线程安全问题,对于这种情况我们可以加同步机制synchronized (对象){};
- load-on-startup
在元素中配置这样一个标签,那么在Web应用程序启动时,服务器就会加载并创建Servlet的实例,并且调用它的初始化init()方法
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.cn.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
作用:可以实现一些定时任务(定时写日志,定时备份数据等)
ServletConfig对象
作用
Web容器为每一个Servlet创建了一个ServletConfig对象。该对象用于从web.xml文件中获取配置信息。
也就是说当Servlet配置了初始化参数后,Web容器在创建Servlet实例对象时,会自动的将这些初始化的参数封装到创建的ServletConfig对象中,并在调用init()方法时将ServletConfig对象传递给Servlet
测试(获取Servlet的初始化参数)
在web.xml文件中为Servlet配置初始化参数
<!--测试ServletConfig对象--> <servlet> <servlet-name>Demo2</servlet-name> <servlet-class>com.cn.config.Demo2</servlet-class> <init-param> <param-name>name</param-name> <param-value>juzi</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Demo2</servlet-name> <url-pattern>/Demo2</url-pattern> </servlet-mapping>
测试代码
/** * ServletConfig对象 */ public class Demo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig config = this.getServletConfig(); String name = config.getInitParameter("name"); resp.getWriter().write(name); } }
输出结果
ServletContext对象
作用
Tomcat容器在启动时,会为每个WEB应用程序创建一个ServletContext对象,代表着当前的WEB应用
由于一个WEB应用中所有的Servlet都共享着同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯
ServletContext对象通常也被称为context域对象
测试(获取web应用的初始化参数)
在web.xml文件中为Servlet配置初始化参数
测试代码,Demo3代码
/** * ServletContext对象 */ public class Demo3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); context.setAttribute("name","juzi"); } }
测试代码,Demo4代码
/** * ServletContext对象 */ public class Demo4 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); Object name = context.getAttribute("name"); System.out.println(name); } }
输出结果,先访问请求Demo3,再访问请求Demo4