Servlet 体系结构
Servlet的实现方式
1、实现 javax.servlet.Servlet 接口 ( 最底层,最原始 )
测试案例:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Servlet Life Cycle</title> </head> <body> <h3>Servlet的实现方式:</h3> <h5>1、实现 javax.servlet.Servlet 接口 ( 最底层,最原始 ) </h5> <form action="/Servlet/first" method="post"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <h5>2、继承 javax.servlet.GenericServlet 类,实现 service 方法</h5> <form action="/Servlet/second" method="post"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <form action="/Servlet/second/abc" method="post"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <form action="/Servlet/second/xyz/abc" method="post"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <h5>3、继承 javax.servlet.http.HttpServlet 类 ,重写 doGet 和 doPost 方法</h5> <form action="/Servlet/third" method="get"> GET: <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <form action="/Servlet/third" method="post"> POST: <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <h5>4、继承 javax.servlet.http.HttpServlet 类 ,重写 service( HttpServletRequest , HttpServletResponse ) 方法</h5> <form action="/Servlet/forth" method="get"> GET: <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> <form action="/Servlet/forth" method="post"> POST: <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <input type="submit" value="提交" > </form> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- 注册 --> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>ecut.lifecycle.FirstServlet</servlet-class> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/first</url-pattern> </servlet-mapping> <!-- 注册 --> <servlet> <servlet-name>SecondServlet</servlet-name> <servlet-class>ecut.lifecycle.SecondServlet</servlet-class> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>SecondServlet</servlet-name> <url-pattern>/second</url-pattern> <url-pattern>/second/*</url-pattern> </servlet-mapping> <!-- 注册 --> <servlet> <servlet-name>ThirdServlet</servlet-name> <servlet-class>ecut.lifecycle.ThirdServlet</servlet-class> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>ThirdServlet</servlet-name> <url-pattern>/third</url-pattern> </servlet-mapping> <!-- 注册 --> <servlet> <servlet-name>ForthServlet</servlet-name> <servlet-class>ecut.lifecycle.ForthServlet</servlet-class> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>ForthServlet</servlet-name> <url-pattern>/forth</url-pattern> </servlet-mapping> <!-- 注册 --> <servlet> <servlet-name>LifeCycleServlet</servlet-name> <servlet-class>ecut.lifecycle.LifeCycleServlet</servlet-class> <!-- 当容器 加载当前的WEB应用时就完成对 该 Servlet 的类加载、实例化、初始化操作 --> <!-- 数字代表加载优先级,默认值-1访问再加载 --> <load-on-startup>0</load-on-startup> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>LifeCycleServlet</servlet-name> <url-pattern>/cycle</url-pattern> </servlet-mapping> <!-- 注册 --> <servlet> <servlet-name>ConfigurationServlet</servlet-name> <servlet-class>ecut.lifecycle.ConfigurationServlet</servlet-class> <!-- 指定初始化参数 --> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>content-type</param-name> <param-value>text/html</param-value> </init-param> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>ConfigurationServlet</servlet-name> <url-pattern>/config</url-pattern> </servlet-mapping> </web-app>
package ecut.lifecycle; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class FirstServlet implements Servlet { @Override public void init(ServletConfig config) throws ServletException { System.out.println( "初始化" ); } @Override public void service(ServletRequest req , ServletResponse resp ) throws ServletException, IOException { System.out.println( "服务" ); req.setCharacterEncoding( "UTF-8" ); resp.setCharacterEncoding( "UTF-8" ); // 接受来自客户端的数据 String username = req.getParameter( "username" ); System.out.println( "username : " + username ); String password = req.getParameter( "password" ); System.out.println( "password : " + password ); // 向客户端生成响应数据 resp.setContentType( "text/html;charset=UTF-8" ); PrintWriter w = resp.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>你好 , " + username + " !</h1>" ); } @Override public void destroy() { System.out.println( "销毁" ); } @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; } }
运行结果如下:
信息: Server startup in 350 ms
初始化
服务
username : AmyZheng
password : 123456
2、继承 javax.servlet.GenericServlet 类,实现 service 方法
测试案例:
package ecut.lifecycle; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class SecondServlet extends GenericServlet{ private static final long serialVersionUID = -2575698410270033395L; @Override public void service(ServletRequest req , ServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding( "UTF-8" ); resp.setCharacterEncoding( "UTF-8" ); // 接受来自客户端的数据 String username = req.getParameter( "username" ); System.out.println( "username : " + username ); String password = req.getParameter( "password" ); System.out.println( "password : " + password ); // 向客户端生成响应数据 resp.setContentType( "text/html;charset=UTF-8" ); PrintWriter w = resp.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>你好 , " + username + " !</h1>" ); } }
运行结果如下:
username : AmyZheng
password : AmyZheng
username : AmyZheng
password : 125678
username : AmyZheng
password : 14789
3、继承 javax.servlet.http.HttpServlet 类 ,重写 doGet 和 doPost 方法
测试案例:
package ecut.lifecycle; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ThirdServlet extends HttpServlet{ private static final long serialVersionUID = -1117957788110702968L; @Override protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { System.out.println( "GET" ); request.setCharacterEncoding( "UTF-8" ); response.setCharacterEncoding( "UTF-8" ); // 接受来自客户端的数据 String username = request.getParameter( "username" ); System.out.println( "username : " + username ); String password = request.getParameter( "password" ); System.out.println( "password : " + password ); // 向客户端生成响应数据 response.setContentType( "text/html;charset=UTF-8" ); PrintWriter w = response.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>你好 , " + username + " !</h1>" ); } @Override protected void doPost( HttpServletRequest request , HttpServletResponse response ) throws ServletException, IOException { System.out.println( "POST" ); request.setCharacterEncoding( "UTF-8" ); response.setCharacterEncoding( "UTF-8" ); // 接受来自客户端的数据 String username = request.getParameter( "username" ); System.out.println( "username : " + username ); String password = request.getParameter( "password" ); System.out.println( "password : " + password ); // 向客户端生成响应数据 response.setContentType( "text/html;charset=UTF-8" ); PrintWriter w = response.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>你好 , " + username + " !</h1>" ); } }
运行结果如下:
GET username : AmyZheng password : 12589
POST
username : AmyZheng
password : AmyZhengf
4、继承 javax.servlet.http.HttpServlet 类 ,重写 service( HttpServletRequest , HttpServletResponse ) 方法
测试案例:
package ecut.lifecycle; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ForthServlet extends HttpServlet { private static final long serialVersionUID = -1403874146599150561L; @Override protected void service( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { request.setCharacterEncoding( "UTF-8" ); response.setCharacterEncoding( "UTF-8" ); // 接受来自客户端的数据 String username = request.getParameter( "username" ); System.out.println( "username : " + username ); String password = request.getParameter( "password" ); System.out.println( "password : " + password ); // 向客户端生成响应数据 response.setContentType( "text/html;charset=UTF-8" ); PrintWriter w = response.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>你好 , " + username + " !</h1>" ); } }
运行结果如下:
username : AmyZheng
password : AmyZheng1
username : AmyZheng
password : AmyZheng2
Servlet的生命周期
1、加载和实例化
- 容器通过反射加载相应的Servlet 类并实例化该类的一个实例。
- 对Servlet类的加载可能发生在引擎启动时,也可能是用户第一次访问相应的Servlet 时。
- 容器只为相应的Servlet初始化一个实例(容器里servlet对象只创建一个)。
2、初始化:调用init() 方法
- Servlet 第一次被调用时,调用init() 方法一次。
- 以后除非被reload 或者destory 后重新访问,才会重新调用该方法。
- 之所以重新调用是因为原有的Servlet 生命周期已结束,一个新的Servlet 生命周期开始。
3、处理请求:调用service() 方法
- 业务逻辑一般在该方法中完成,该方法可以被多次调用。
- 只要有一个用户访问当前Servlet,就会调用该方法(请求一次就服务,一个连接一个线程)。
4、服务结束:调用destory() 方法
- 有三种情况会调用destory 方法(只调用一次)
tomcat将重启
reload 该webapp
关闭或重启计算机(Servlet容器也随之关闭)
测试案例:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- 注册 --> <servlet> <servlet-name>LifeCycleServlet</servlet-name> <servlet-class>ecut.lifecycle.LifeCycleServlet</servlet-class> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>LifeCycleServlet</servlet-name> <url-pattern>/cycle</url-pattern> </servlet-mapping> </web-app>
package ecut.lifecycle;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class LifeCycleServlet implements Servlet {
static {
System.out.println( "加载并初始化LifeCycleServlet类" );
}
public LifeCycleServlet(){
System.out.println( "创建 LifeCycleServlet 类的实例" );
}
@Override
public void init( ServletConfig config ) throws ServletException {
System.out.println( "对 LifeCycleServlet 实例进行初始化" );
}
@Override
public void service( ServletRequest req , ServletResponse resp ) throws ServletException, IOException {
System.out.println( "LifeCycleServlet 的实例对外提供服务" );
resp.setCharacterEncoding( "UTF-8" );
resp.setContentType( "text/html;charset=UTF-8" );
// 向客户端生成响应数据
PrintWriter w = resp.getWriter();
w.println( "<h1 style='text-align:center;color:blue;'>Hello !</h1>" );
}
@Override
public void destroy() {
System.out.println( "准备销毁 LifeCycleServlet 的实例" );
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
运行结果如下:
信息: Server startup in 337 ms
加载并初始化LifeCycleServlet类
创建 LifeCycleServlet 类的实例
对 LifeCycleServlet 实例进行初始化
LifeCycleServlet 的实例对外提供服务
LifeCycleServlet 的实例对外提供服务
如下修改xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- 注册 --> <servlet> <servlet-name>LifeCycleServlet</servlet-name> <servlet-class>ecut.lifecycle.LifeCycleServlet</servlet-class> <!-- 当容器 加载当前的WEB应用时就完成对 该 Servlet 的类加载、实例化、初始化操作 --> <!-- 数字代表加载优先级,默认值-1访问再加载 --> <load-on-startup>0</load-on-startup> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>LifeCycleServlet</servlet-name> <url-pattern>/cycle</url-pattern> </servlet-mapping> </web-app>
指定当web 应用启动时,装载Servlet 的次序
- 在servlet 标签中使用<load-on-startup> 子标签设置
- 其中的数字含义如下:
如果这个数字是正数或0,则容器先加载数值较小的servlet,再加载数值稍大的
如果是负数或者没有设置,容器将在web 客户端首次访问该servlet 时才加载
运行结果如下:
加载并初始化LifeCycleServlet类
创建 LifeCycleServlet 类的实例
对 LifeCycleServlet 实例进行初始化
四月 08, 2018 7:07:00 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
四月 08, 2018 7:07:00 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-nio-8009"]
四月 08, 2018 7:07:00 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 346 ms
LifeCycleServlet 的实例对外提供服务
LifeCycleServlet 的实例对外提供服务
ServletConfig
1、ServletConfig接口:servlet容器在初始化期间将信息传递给servlet的servlet配置对象(用于描述一个Servlet 的配置信息)。
2、常用方法
- 获得当前Servlet 实例的名称
String getServletName()
- 获得当前Servlet 实例的初始化参数
String getInitParameter(String name)根据name 获取指定的初始化参数的值,如果name 对应的初始化参数不存在,返回null
Enumeration getInitParameterNames()返回当前Servlet 实例的所有的初始化参数的名称,注意返回类型是java.util.Enumeration
- 获得当前Servlet 实例所依赖的应用
ServletContext getServletContext()
测试案例:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- 注册 --> <servlet> <servlet-name>ConfigurationServlet</servlet-name> <servlet-class>ecut.lifecycle.ConfigurationServlet</servlet-class> <!-- 指定初始化参数 --> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>content-type</param-name> <param-value>text/html</param-value> </init-param> </servlet> <!-- 映射(发布) --> <servlet-mapping> <servlet-name>ConfigurationServlet</servlet-name> <url-pattern>/config</url-pattern> </servlet-mapping> </web-app>
package ecut.lifecycle; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class ConfigurationServlet implements Servlet { @Override public String getServletInfo() { return this.config.getServletName() ; } @Override public ServletConfig getServletConfig() { return this.config ; } private ServletConfig config ; @Override public void init( ServletConfig config ) throws ServletException { this.config = config ; System.out.println( "初始化" ); System.out.println( config ); System.out.println( "ServletName : " + config.getServletName() );//web.xm配置文件中的servlet名称 /* String encoding = config.getInitParameter( "encoding" ); System.out.println( "encoding : " + encoding ); */ Enumeration<String> initParamNames = config.getInitParameterNames(); while( initParamNames.hasMoreElements() ){ String name = initParamNames.nextElement() ; String value = config.getInitParameter( name ); System.out.println( name + " : " + value ); } } @Override public void service( ServletRequest req , ServletResponse resp ) throws ServletException, IOException { System.out.println( "对外提供服务" ); String ct = config.getInitParameter( "content-type" ) ; String en = config.getInitParameter( "encoding" ) ; String contentType = ct + ";charset=" + en ; // "text/html;charset=UTF-8" resp.setContentType( contentType ); PrintWriter w = resp.getWriter(); w.println( "<h1 style='text-align:center;color:blue;'>欢迎 !</h1>" ); } @Override public void destroy() { System.out.println( "销毁" ); } }
配置Servlet 的初始化参数
- 在servlet 标签中使用init-param 子标签配置
其中<param-name> 子标签用于设置初始化参数的名称
<param-value> 子标签用于设置指定参数的值
- 同一个servlet 中可以使用多个init-param 标签配置多个初始化参数
使用config.getInitParameter( name ) 可以获取指定名称的参数对应的值
使用config.getInitParameterNames() 可以获取所有的参数的名称
运行结果如下:
初始化 org.apache.catalina.core.StandardWrapperFacade@4c12c6a ServletName : ConfigurationServlet content-type : text/html encoding : UTF-8 对外提供服务
转载请于明显处标明出处