欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

javaweb之servlet详解

程序员文章站 2022-06-03 09:15:08
...

Servlet

1.1什么是servlet

    Servletweb程序中的小应用程序,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执行过程

javaweb之servlet详解

如上图所示,浏览器请求服务,服务找到对应的servlet应用,通过地址栏里面的urlweb.xml

中配置的url-mapping映射找到对应的servlet类,并实例化,tomcat会依次调用servletinitservice方法,完成后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(适配器模式)

javaweb之servlet详解

4.3继承javax.servlet.http.HttpServlet类(模板方法设计模式)

javaweb之servlet详解

如上图所示

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去移除数据

javaweb之servlet详解

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 获取资源路径

javaweb之servlet详解
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);
	
}

servlet相关对象关系

javaweb之servlet详解