本篇主要记录下,对GenericServlet的作用理解,及其与Servlet/HttpServlet之间的关系。
- 示例完成业务:
1、新建一个login.jsp页面,要求改页面能输入username,password,login.jsp提交页面,对应的处理servlet为LoginServlet;
2、在J2EE环境下,新建一个Dynamic Web Project工程,之后给该工程创建一个LoginServlet servlet类;
3、LoginServlet 完成业务为,获取全局初始化参数信息:username,password的值,那这两个值与从login.jsp页面获取到的值就行对比,如果context-param:username=form:username且context-param:password=form:password,则向客户端返回:
context-param:username:xxx
context-param:password:yyy
form:username:xxx
form:password:yyy
ok!
否则,返回:
context-param:username:xxx
context-param:password:yyy
form:username:xx
form:password:zzz
error!
思路:以前我们都是要写LoginServlet实现Servlet接口类的函数,那现在我们想把LoginServlet代码变得更简洁,我们把一些不常用的代码放在一个抽象Servlet类中,我们的LoginServlet来继承该抽象Servlet类。
1、定义一个MyGenericServlet类,并将该类实现Servlet接口:
1 public abstract class MyGenericServlet implements Servlet{ 2 private ServletConfig servletConfig; 3 4 public MyGenericServlet() { 5 } 6 7 @Override 8 public void destroy() { 9 } 10 11 @Override 12 public ServletConfig getServletConfig() { 13 return this.servletConfig; 14 } 15 16 @Override 17 public String getServletInfo() { 18 return ""; 19 } 20 21 @Override 22 public void init(ServletConfig servletConfig) throws ServletException { 23 this.servletConfig = servletConfig; 24 this.init(); 25 } 26 27 public void init() throws ServletException { 28 } 29 30 @Override 31 public abstract void service(ServletRequest request, ServletResponse response) throws ServletException, IOException; 32 }
2、把service方法修改为一个抽象函数,因为不管哪个继承该类的servlet类都要进行与客户端进行交互(接收客户端信息,响应客户端信息),而service方法是servlet与客户端进行交互的唯一生命周期方法。
3、如果把service方法变为抽象类,我们必须要把这个类变为一个抽象类。
4、为了让子类LoginServlet更好的使用上下文函数,我们实现了getServletConfig()方法:定义一个局部变量,并在init(ServletConfig servletConfig)方法中给该局部变量赋值,这样我们就可以在getServletConfig()中返回这个局部变量即可。
备注:为什么我们要实现servletConfig()方法呢?------在我们业务中提到我们要获取web.xml的全局初始化参数信息,那么我们必须找到ServletContext对象,而找到ServletContext对象,在servlet交互过程中,我们可以通过ServletConfig的getServletContext()方法获取ServletContext对象。
5、添加一个init()函数,为什么添加呢?
比如说我在LoginServlet中要对servlet初始化时,进行一些工作,那么我就会覆盖init(ServletConfig servletConfig)方法,如果这是我又不知道父类干了什么工作,就想当然的把父类实现给注释掉:
1 2 @Override 3 public void init(ServletConfig servletConfig) throws ServletException { 4 //super.init(servletConfig); 5 }
这是在运行程序就会抛出 一个空指针异常。
因为如果覆盖了父类的init(ServletConfig servletConfig)方法时,把supper.init(servletConfig)给注释了,那么在父类的init(ServletConfig servletConfig)函数中的给局部变量servletConfig赋值部分就不会执行了,那么当我们使用ServletConfig对象(调用getServletConfig()方法获取到的)时,就会抛出空指针错误。
为了避免这种情况,我们就自定义了一个init()方法,让MyGenericServlet的init(ServletConfig servletConfig)方法调用它,当子类需要在初始化时做的事情,就可以通过覆盖init()方法使用。
6、从上边业务上来说我们能推断出在LoginServlet的service(ServletRequest request,ServletResponse response)方法中,获取全局初始化参数时,需要这样写:
1 ServletContext servletContext=getServletConfig().getServletContext(); 2 String username=servletContext.getInitParameter("username"); 3 String password=servletContext.getInitParameter("password");
那如果是获取servlet局部初始化变量时,我们需要这样写:
String username=getServletConfig().getInitParameter("username");
String password=getServletConfig().getInitParameter("password");
那么,如果我们让抽象类MyGenericServlet实现接口ServletConfig,我们是不是在LoginServlet中就可以这样获取局部初始化变量:
String username=this.getInitParameter("username"); String password=this.getInitParameter("password");
这样代码是不是会更简洁呢.
因此我们修改后的MyGenericServlet类,是这个样子:
1 package com.dx.hiservlet; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 6 import javax.servlet.Servlet; 7 import javax.servlet.ServletConfig; 8 import javax.servlet.ServletContext; 9 import javax.servlet.ServletException; 10 import javax.servlet.ServletRequest; 11 import javax.servlet.ServletResponse; 12 13 public abstract class MyGenericServlet implements Servlet,ServletConfig { 14 private ServletConfig servletConfig; 15 16 public MyGenericServlet() { 17 } 18 19 @Override 20 public void destroy() { 21 } 22 23 @Override 24 public ServletConfig getServletConfig() { 25 return this.servletConfig; 26 } 27 28 @Override 29 public String getServletInfo() { 30 return ""; 31 } 32 33 @Override 34 public void init(ServletConfig servletConfig) throws ServletException { 35 this.servletConfig = servletConfig; 36 this.init(); 37 } 38 39 public void init() throws ServletException { 40 } 41 42 @Override 43 public abstract void service(ServletRequest request, ServletResponse response) throws ServletException, IOException; 44 45 @Override 46 public String getInitParameter(String arg0) { 47 return this.getServletConfig().getInitParameter(arg0); 48 } 49 50 @Override 51 public Enumeration<String> getInitParameterNames() { 52 return this.getServletConfig().getInitParameterNames(); 53 } 54 55 @Override 56 public ServletContext getServletContext() { 57 return this.getServletConfig().getServletContext(); 58 } 59 60 @Override 61 public String getServletName() { 62 return this.getServletConfig().getServletName(); 63 } 64 65 }
login.jsp:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 7 <title>Insert title here</title> 8 </head> 9 <body> 10 <form action="LoginServlet" method="POST"> 11 username:<input type="text" name="username" /> 12 <br /> 13 password:<input type="text" name="password" /> 14 <br /> 15 <input type="submit" value="submit" /> 16 </form> 17 </body> 18 </html>
LoginServlet类
1 package com.dx.hiservlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletConfig; 7 import javax.servlet.ServletContext; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 12 public class LoginServlet extends MyGenericServlet { 13 public LoginServlet() { 14 } 15 16 @Override 17 public void init() { 18 System.out.println("init...."); 19 } 20 21 @Override 22 public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { 23 ServletContext servletContext = this.getServletContext(); 24 String username = servletContext.getInitParameter("username"); 25 String password = servletContext.getInitParameter("password"); 26 27 String formUserName = request.getParameter("username"); 28 String formPassword = request.getParameter("password"); 29 30 PrintWriter writer = response.getWriter(); 31 32 writer.println("context-param:username:"+username); 33 writer.println("context-param:password:"+password); 34 35 writer.println("form:username:"+formUserName); 36 writer.println("form:password:"+formPassword); 37 38 if (username.equals(formUserName) && password.equals(formPassword)) { 39 writer.println("ok!"); 40 } else { 41 writer.println("error!"); 42 } 43 } 44 45 }
web.xml配置映射,全局初始化参数“:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 5 id="WebApp_ID" version="3.0"> 6 <context-param> 7 <param-name>username</param-name> 8 <param-value>111</param-value> 9 </context-param> 10 <context-param> 11 <param-name>password</param-name> 12 <param-value>111</param-value> 13 </context-param> 14 15 <servlet> 16 <servlet-name>loginServlet</servlet-name> 17 <servlet-class>com.dx.hiservlet.LoginServlet</servlet-class> 18 </servlet> 19 <servlet-mapping> 20 <servlet-name>loginServlet</servlet-name> 21 <url-pattern>/LoginServlet</url-pattern> 22 </servlet-mapping> 23 24 </web-app>
测试地址:http://localhost:8080/MyGenericServlet001/login.jsp
我们为什么定义一个这样的MyGenericServlet呢,目的是为了学习GenericServlet,从GenericServlet源代码中,我们可以发现我们上边写的这个MyGenericServlet与GenericServlet基本相同,我们把LoginServlet继承类改为GenericServlet,运行结果一样。
那么GenericServlet与Servlet之间的关系,相信我们都清楚了,那么GenericServlet与HttpServlet之间是什么关系呢?
我们去查看下HttpServlet的源代码:
1 public abstract class HttpServlet extends GenericServlet 2 implements Serializable 3 { 4 。。。 5 }
但从Servlet API上来看,HttpServlet要比Servlet,GenricServlet内容更多,具有大量http相关的信息。
具体细节,请参考Servlet Api.
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。