javaweb之servlet详解
一 Servlet
1.1什么是servlet
Servlet是web程序中的小应用程序,servlet通过http接收和相应来自客户端的请求。
1.2创建一个Servlet
步骤 1创建servlet
public class MyServlet implements Servlet {
private static final long serialVersionUID = 1L;
public MyServlet() {
super();
}
public void destroy() {
System.out.println("输出 输出....destroy ");
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("输出 输出....init ");
}
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("输出 输出.... service");
}
}
步骤 2 web.xml中配置servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>LServlets</display-name>
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>xiao.it.java.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/ser</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
1.3 servlet执行过程
如上图所示,浏览器请求服务,服务找到对应的servlet应用,通过地址栏里面的url与web.xml
中配置的url-mapping映射找到对应的servlet类,并实例化,tomcat会依次调用servlet的init与service方法,完成后servlet会把请求数据返回给客户端,tomcat再执行servlet的销毁工作。
1.4 servlet生命周期
实例化-->初始化-->服务-->销毁
出生:(实例化-->初始化)第一次访问Servlet就出生
活着:(服务)应用活着,servlet就活着,应用没有卸载的时候
死亡:(销毁)应用卸载了servlet就销毁.
//servlet是单实例的
public class MyServlet implements Servlet {
//第一次被访问的时候调用
public MyServlet(){
super();
}
//第一次被访问的时候调用
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("******** init ********");
}
//每一次访问的时候都调用
//这里是个多线程的
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("******** service ********");
}
//被销毁的时候调用
public void destroy() {
System.out.println("******** destroy ********");
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
}
如上面的代码所示,servlet是单例的,而service方法确实多线程的,当servlet第一次被访问的时候依次是构造函数,init()方法,然后接下来才是service的调用,从第一次以后访问servlet构造方法跟init()方法不再被调用,但是service()方法确实访问一次调用一次,最后卸载应用的时候servlet才会被销毁。
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>xiao.it.java.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
如上所示增加了load-on-startup可以在服务器启动的时候对servlet进行实例化与初始化。
二 Servlet的三种创建方式
4.1、实现javax.servlet.Servlet接口(参见:编写一个servlet程序:)
4.2、继承javax.servet.GenericServlet类(适配器模式)
4.3、继承javax.servlet.http.HttpServlet类(模板方法设计模式)
如上图所示
Servlet接口
public abstract interface Servlet
{
public abstract void init(ServletConfig paramServletConfig) throws ServletException;
public abstract ServletConfig getServletConfig();
public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
throws ServletException, IOException;
public abstract String getServletInfo();
public abstract void destroy();
}
servletConfig接口
public abstract interface ServletConfig
{
public abstract String getServletName();
public abstract ServletContext getServletContext();
public abstract String getInitParameter(String paramString);
public abstract Enumeration<String> getInitParameterNames();
}
GenericConfig 类
public abstract class GenericServlet
/* */ implements Servlet, ServletConfig, Serializable
/* */ {
/* */ private static final long serialVersionUID = 1L;
/* */ private transient ServletConfig config;
/* */ public GenericServlet() {}
/* */ public void destroy() {}
/* */ public String getInitParameter(String name)
/* */ {
/* 80 */ return getServletConfig().getInitParameter(name);
/* */ }
HttpServlet类
1主要service方法
public void service(ServletRequest req, ServletResponse res)
/* */ throws ServletException, IOException
/* */ {
/* */ HttpServletRequest request;
/* */ HttpServletResponse response;
/* */ try
/* */ {
/* 726 */ request = (HttpServletRequest)req;
/* 727 */ response = (HttpServletResponse)res;
/* */ } catch (ClassCastException e) {
/* 729 */ throw new ServletException("non-HTTP request or response");
/* */ }
/* 731 */ service(request, response);
/* */ }
/* */ }
2 自己实现的service方法
/ protected void service(HttpServletRequest req, HttpServletResponse resp)
/* */ throws ServletException, IOException
/* */ {
/* 617 */ String method = req.getMethod();
/* */
/* 619 */ if (method.equals("GET")) {
/* 620 */ long lastModified = getLastModified(req);
/* 621 */ if (lastModified == -1L)
/* */ {
/* */
/* 624 */ doGet(req, resp);
/* */ } else {
/* */ long ifModifiedSince;
/* */ try {
/* 628 */ ifModifiedSince = req.getDateHeader("If-Modified-Since");
/* */ }
/* */ catch (IllegalArgumentException iae) {
/* 631 */ ifModifiedSince = -1L;
/* */ }
/* 633 */ if (ifModifiedSince < lastModified / 1000L * 1000L)
/* */ {
/* */
/* */
/* 637 */ maybeSetLastModified(resp, lastModified);
/* 638 */ doGet(req, resp);
/* */ } else {
/* 640 */ resp.setStatus(304);
/* */ }
/* */ }
/* */ }
/* 644 */ else if (method.equals("HEAD")) {
/* 645 */ long lastModified = getLastModified(req);
/* 646 */ maybeSetLastModified(resp, lastModified);
/* 647 */ doHead(req, resp);
/* */ }
/* 649 */ else if (method.equals("POST")) {
/* 650 */ doPost(req, resp);
/* */ }
/* 652 */ else if (method.equals("PUT")) {
/* 653 */ doPut(req, resp);
/* */ }
/* 655 */ else if (method.equals("DELETE")) {
/* 656 */ doDelete(req, resp);
/* */ }
/* 658 */ else if (method.equals("OPTIONS")) {
/* 659 */ doOptions(req, resp);
/* */ }
/* 661 */ else if (method.equals("TRACE")) {
/* 662 */ doTrace(req, resp);
/* */
/* */
/* */ }
/* */ else
/* */ {
/* */
/* */
/* 670 */ String errMsg = lStrings.getString("http.method_not_implemented");
/* 671 */ Object[] errArgs = new Object[1];
/* 672 */ errArgs[0] = method;
/* 673 */ errMsg = MessageFormat.format(errMsg, errArgs);
/* */
/* 675 */ resp.sendError(501, errMsg);
/* */ }
/* */ }
如上图所示 我们配置多个路径,可以映射到同一个servlet上,也就是一个servlet可以映射多个路径。
servet映射细节2: 通配符* 代表任意字符串
url-pattern: *.do 以*.字符串的请求都可以访问 注:不要加/
url-pattern: /* 任意字符串都可以访问
url-pattern: /action/* 以/action开头的请求都可以访问
匹配规则:
优先级:从高到低
绝对匹配--> /开头匹配 --> 扩展名方式匹配
如果url-pattern的值是/,表示执行默认映射。所有资源都是servlet
实际开发的时候servlet的创建方式,就用最后一种方式。
三 servlet线程安全
解决servlet线程安全问题,尽量不要使用全局变量,因为servlet是单实例,多服务的所以,尽量使用局部变量,来解决并发资源共享的问题。
四 servlet配置与资源
4.1 ServletConfig
4.1.1获取配置信息
servlet配置
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>xiao.it.java.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/ser</url-pattern>
</servlet-mapping>
获取servlet配置
public class Hser extends HttpServlet{
private ServletConfig servconfig;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//方式一 获取配置信息
String encoding = servconfig.getInitParameter("encoding");
System.out.println(encoding);
//方式二 获取配置信息
String encoding1 = this.getServletConfig().getInitParameter("encoding");
System.out.println(encoding1);
//方式三 获取配置信息
String encoding2 = super.getInitParameter("encoding");
System.out.println(encoding2);
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.servconfig=config;
}
}
4.1.2获取servletContext
ServletContext servletContext = servconfig.getServletContext();
4.2 servletContext
创建方式
ServletContext servletContext = servconfig.getServletContext();
ServletContext servletContext2 = this.getServletContext();
ServletContext: 代表的是整个应用。一个应用只有一个ServletContext对象。单实例。
4.2.1 共享数据
常用方法:
void setAttribute(String name,object value);//向ServletContext对象的map中添加数据
Object getAttribute(String name);//从ServletContext对象的map中取数据
void rmoveAttribute(String name);//根据name去移除数据
4.2.2 获取全局配置
Web.xml中配置全局参数
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>LServlets</display-name>
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>xiao.it.java.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/ser</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
代码中获取全局参数
public class ServletContext extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String utf = this.getServletContext().getInitParameter("encoding");
System.out.println(utf);
}
}
4.2.3 获取资源路径
public void test1() throws FileNotFoundException, IOException{
String realPath = this.getServletContext().
getRealPath("/WEB-INF/a.properties");
Properties properties=new Properties();
properties.load(new FileInputStream(realPath));
}
public void test2() throws FileNotFoundException, IOException{
String realPath = this.getServletContext().
getRealPath("/WEB-INF/classes/b.properties");
Properties properties=new Properties();
properties.load(new FileInputStream(realPath));
}
public void test3() throws FileNotFoundException, IOException{
String realPath = this.getServletContext().
getRealPath("/WEB-INF/classes/xiao/it/java/c.properties");
Properties properties=new Properties();
properties.load(new FileInputStream(realPath));
}
4.2.4 请求转发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.getServletContext().getRequestDispatcher("/servlet2").forward(req, resp);
}