java web之Servlet技术

 Java_Servlet技术文档

 

作    者:阿苏是也

创建日期:2015-08-17

修改日期:2015-08-24

当前版本:1.1v

一、文档控制

文档版本

 

文档主题

本文针对Web项目结构,Servlet基本概念,对Servlet体系结构,通过实例讲解Servlet,servlet配置,servlet上下文,监听器,过滤器等等。

六、Servlet技术说明

主要介绍,是什么servlet,有什么作用,servlet生命周期怎么样的,技术怎么实现。

通过实例来介绍

6.1、基本概念

6.1.1、基本概念

什么是servlet?

Servlet是运行在服务器端的java程序,是一种动态加载的模块,为来自客户端的请求提供服务。可做为CGI替代品。

 

Servlet实现了为每个请求提供服务,并返回响应结果。

我为什么要使用Servlet,它有什么优势呢?

1、性能高效

每一个请求由一个java线程处理(CGI是系统进程来处理),在多线程处理中,只需要一份servlet类代码即可实现。

2、功能强大

能自动解析和解码HTML表单数据,读取和写入HTTP头信息,处理Cookie,跟踪会话状态,及能在各个程序之间共享数据,数据库连接池和线程池很容易实现。

3、可移值性好

Servlet是用java编写的,几乎所有主流的服务器都能直接或通过插件支持servlet,比如Apache,IIS或Tomcat等。

 

6.1.2、生命周期

Servlet生命周期是伴随web容器,服务启动开始,服务停止而结束。

Servlet生命周期经过上面四个过程。

1实例化

在服务启动后,根据项目的web.xml指定servlet进行实例化。调用servlet类中构造方法。

2初始化

在用户第一次请求时会唯一一次初始化操作,用于加载配置文件或其他资源。调用init方法

3、服务

为每次请求提供服务,servlet会获取用户信息,并进行处理后返回数据。调用server,doPost,doGet,doPut等方法

 

4、销毁

当服务关闭后,会执行servlet销毁,用于释放资源数据。调用destroy方法。

 

提示:init方法,可以用于加载数据库链接配置,用于日志配置加载,或其他系统资源配置的加载。

 

 

6.1.3、servlet Api体系

由于servlet是JDK一个扩展,因此JDK本身是不包含servlet-api.jar,

可以从servlet容器中获取到。在tomcat_home/lib目录存放。

因此在web项目需要加载apache tomcat的jar包。

 

servlet-api.jar主要包含javax.servlet和javax.servlet.http两个软件包。这两个软件包基本实现所有servlet相关的类和接口。

 

Servlet ApI结构图

在java servlet中,两个主要的类是GenericServlet和HttpServlet,其中GenericServlet实现servlet,ServeltConfig,Serializable接口的类。HttpServlet继承GenericServlet而来的。

 

我们可以通过servlet接口,或GenericServlet和httpServlet类来实现servlet的功能。

 

Servlet版本和web容器版本(Tomcat)相关的。

存在多个版本的有2.5,3.0,3.1

其中3.1只能在tomcat8.0v运行,tomcat7.0v不支持,但是低版本servlet可以在tomcat8.0中运行

 

Servlet版本可以在项目web.xml文件中看到,也可以在eclipse创建动态web项目时看到。

 

6.2、Web认识

一个完整web项目都需要哪些东西,又如何在web容器中来运行。

Java Web 存放在Web容器中来执行的。要执行Servlet,jsp,那就放在servlet容器,JSP容器,这个Tomcat容器都是支持的。当然如果要支持EJB,那么需要支持EJB的容器,比如JBOSS,Weblogic等等

 

6.2.1、Web项目的目录结构

 

 

META-INF

    相当于一个信息包,目录中的文件和目录获得Java 2平台的认可与解释,用来配置应用程序、扩展程序、类加载器和服务,manifest.mf文件,在用jar打包时自动生成

WEB-INF

 

/WEB-INF/web.xml

      Web应用程序配置文件,这是一个XML文件,其中描述了 servlet 和其他的应用组件配置及命名规则;

 

/WEB- INF/classes/

      包含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中。子目录是更新包来生成的。

     

/WEB- INF/lib/

       存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件

 

以上是一个servlet必须有的,也是web项目必须有的。

可以添加配置文件目录,资源文件目录

 

/WEB- INF/config/

存放各种配置文件,比如sys.properties, db.properties,log4j.properties等等配置文件。

 

若要支持jsp可以,创建如下目录

/WEB- INF/tags/

存放标签库

 

/WEB- INF/jsps/

存放jsp代码

 

 

可以手工方式来实现创建项目目录及编写项目文件代码来完成一个web项目,但通过开发工具可以事半功倍。下面通过tomcat来如何实现一个web项目。

6.2.2、Tomcat如何实现Web目录

通过Eclipse 和Tomcat7.0v 怎么来实现 Java Web能

 

新建Dynamic Web Project,这里以HelloWorldServlet来说明

 

共包含六个节点

1、JAX-WS Web Services

和webservice 技术相关的这里不做介绍

2、Deploymentdescription:HelloServlet

主要是描述web.xml文件可以支持属性,及目前已经配置的属性。

1、       Java Resource

包含自行开发的Java代码及JAR包(tomcat,JRE,Web app需要的,EAR包)

2、       JavaScript Resource

存放javascript的资源

3、       build

项目build出的结果

4、       webcontent

为项目的根结构目录,存放lib/web.xml文件。

 

若我们通过tomcat运行,则会在工作台(wp_eclipseluna44)目录下生成一个临时运行的目录

wp_eclipseluna44\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\HelloServlet

生成HelloServlet的web项目运行代码。

 

 

经常出现的异常

1、java类找不到

若运行报错:

java.lang.ClassNotFoundException: org.apache.log4j.PropertyConfigurator

是因为lib目录下缺少jar包,通过把log4j1.2.7.jar包拷贝过去,就不会报错了。

最直接方法是把需要的web app jar包,拷贝到工作台web项目lib目录

例如:(wp_eclipseluna44\HelloServlet\WebContent\WEB-INF\lib)

然后tomcat重新运行后,会自动将jar拷贝到tomcat临时运行目录中

当然为了能正常编程,将项目lib目录的jar加载带项目中(项目属性-javabuild path).

 

 

6.3、servlet技术实现-HelloServlet

我们使用servlet3.0版本,tomcat7.0v或8.0v

 

新建DynamicWeb Project,这里以HelloServlet项目来说明

实现功能:

1、       HelloServlet类,实现输出Hello Servlet

2、       JdbcServlet类,读取servlet的参数,用于数据库连接。

3、       PropertiesServlet类,读取servlet指定配置文件中参数

4、       Log4jServlet类,读取servlet指定log4j.properties配置文件。

项目如下:

 

 

导入war结构如下

 

6.3.1、HelloServlet类

编写service方法

 

配置web.xml

添加servlet

若启动时报错,则

java.util.concurrent.ExecutionException:org.apache.catalina.LifecycleException: Failed to start

出现这样的错误,web.xml servlet类配置的有问题

修改如下,就可以正常运行


(我用的是3.0版,按如上配置,早期版本使用相同名称,未去验证)

 

 

6.3.2、JdbcServlet类

JdbcServlet代码

 

Web.xml配置

6.3.3、PropertiesServlet类

在servlet,初始化时加载配置文件,代码如下

 

Web.xml配置


sys.properties配置


路径参考:项目HelloServlet的目录图

6.3.4、Log4jServlet类

将log4j-1.2.17.jar和ojdbc5-11.2.0.jar拷贝到WEB-INF/lib目录下。

 

在初始化时加载log4j.properties配置文件,并且修改配置参数到web容器中

在请求时,记录日志

 

 

 

Web.xml 配置


 

Log4j.properties配置

数据库配置

       其中sql值为:

insert into LOG4J_DBMDL(IPaddress,Rhashcode,Class,Mothod,createTime,LogLevel,MSG) values('%X{IPaddress}','%X{Rhashcode}','%C','%M','%d{yyyy-MM-dd HH:mm:ss}','%p','%m')

 

6.4、servlet配置和上下文

6.4.1、servlet配置

Servlet配置对象(ServletConfig):每一个servlet对象对应一个配置对象,它用来加载web.xml文件中servlet的参数.

 

Servlet初始化时,容器调用其init(ServletConfig)方法,传递该对象。

 

1、获得对象方法:

 

(1)、直接使用getServletConfig()方法:

ServletConfig config = getServletConfig();

 

(2)、覆盖Servlet的init()方法,把容器创建的ServletConfig对象保存到一个成员变量中:

 

public void init(ServletConfig config){

super.init(config);

this.config = config;

}

提示在3.0v版本中,已经无需覆盖servlet的init()方法,可以直接使用。

 

2、ServletConfig的4个常用方法:

 

(1)、public String getInitParameter(String name):返回指定名称的初始化参数值;

 

(2)、public Enumeration getInitParameterNames():返回一个包含所有初始化参数名的Enumeration对象;

 

(3)、public String getServletName():返回在DD文件中<servlet-name>元素指定的Servlet名称;

 

(4)、public ServletContext getServletContext():返回该Servlet所在的上下文对象;

 

 

实例代码参考:JdbcServlet 和PropertiesServlet

6.4.2、servlet上下文

Servlet上下文对象(ServletContext):每个Web应用程序在被启动时都会创建一个唯一的上下文对象,Servlet可通过其获得Web应用程序的初始化参数或Servlet容器的版本等信息,也可被Servlet用来与其他Servlet共享数据。

 

ServletContext共享的对象在整个Web应用程序启动的生存周期中可以被访问;

HttpSession共享的对象仅在会话的生存周期中可以被访问;

ServletRequest共享的对象仅在请求的生存周期中可以被访问;

 

 

1、获得ServletContext应用:

(1)、直接调用getServletContext()方法

Super.init(config);

ServletContext context = getServletContext();

(2)、使用ServletConfig应用,再调用它的getServletContext()方法

ServletContext context = getServletConfig.getServletContext();

 

2、获得应用程序的初始化参数:

 

(1)、public String getInitParameter(String name):返回指定参数名的字符串参数值,没有则返回null;

 

(2)、public Enumeration getInitParameterNames():返回一个包含多有初始化参数名的Enumeration对象;

Web.xml 上下文参数配置

<context-param>

<param-name>admin</param-name>

<param-value>zhenyun.su</param-value>

</context-param>

 

3、通过ServletContext对象获得资源

 

(1)、public URl getResource(String path):返回由给定路径的资源的URL对象,以“/”开头,为相对路径,相对于Web应用程序的文档根目录;

 

(2)、public InputStream getResourceAsStream(String path):从资源上获得一个InputStream对象,等价于getResource(path).oprenStream();

 

(3)、public String getRealPath(String path):返回给定的虚拟路径的真实路径;

 

4、登陆日志:使用log()方法可以将指定的消息写到服务器的日志文件中

 

(1)、public void log(String msg):参数msg为写入日志文件消息

 

(2)、public void log(String msg,Throwable throwable):将msg指定的消息和异常的栈跟踪信息写入日志文件

 

5、使用RequestDispatcher实现请求转发

 

(1)、RequestDispatcher getRequestDiapatcher(String path):必须以"/"开头相对于应用程序根目录,而ServletRequest可以传递一个相对路径

 

(2)、RequestDipatcher getNamedDiapatcher(String name):参数name为一个命名的Servlet对象

 

6、使用ServletContext对象存储数据

 

(1)、public void serAttribute(String name,Object object):将给定名称的属性值对象绑定到上下文对象上;

 

(2)、public Object getAttribute(String name):返回绑定到上下文对象的给定名称的属性值;

 

(3)、public Enumeration getAttributeNames():返回绑定到上下文对象上的所有属性名的Enumeration对象;

 

(4)、public void removeAttribute(String name):删除绑定到上下文对象指定名称的属性;

 

7、检索Servlet容器的信息

 

(1)、public String getServletInfo():返回Servlet所运行容器的名称和版本;

 

(2)、public int getMajorVersion():返回容器所支持的Servlet API的主版本号;

 

(3)、public int  getMinorVersion():返回容器所支持的Servlet API的次版本号;

 

(4)、public String getServletContext():返回ServletContext对应的web应用程序名称<display-name>元素定义的名称;

 

6.4.3、ContextServlet类

新增ContextServlet类,若要单独使用this.getServletContext(),则需要继承super.init(config)方法。

 

 

Web.xml配置

 

输出如下:

 

实例代码参考:HelloServlet项目中ContextServlet类

6.4.4、Servlet的多线程

 

1、当涉及到Servlet需要共享资源是,需保证Servlet是线程安全的

 

2、注意事项:

 

(1)、用方法的局部变量保持请求中的专有数据;

(2)、只用Servlet的成员变量来存放那些不会改变的数据;

(3)、对可能被请求修改的成员变量同步(用Synchronized关键字修饰);

(4)、如果Servlet访问外部资源,那么需要同步访问这些资源;

 

3、实现SingleThreadModel接口的Servlet在被多个客户请求时一个时刻只能有一个线程运行,不推荐使用。

 

4、如果必须在servlet使用同步代码,应尽量在最小的范围上(代码块)进行同步,同步代码越少,Servlet执行才能越好,避免对doGet()或doPost()方法同步。

 

 

 

 

6.5、servlet过滤器

6.5.1、过滤器概念

过滤器可以对客户端的web请求在请求处理前及响应回客户端前进行

拦截和处理。

 

过滤器有什么用呢,他设计出来为解决什么样的问题?

1、可用来设置请求内容和响应内容的编码

2、可以用于web的日志记录

3、用户认证和授权管理

4、实现数据的压缩和数据加解密。

5、实现数据格式转换xml或json

 

 

 

6.5.2、过滤器类

通过javax.servlet.filter接口来实现的。    

主要用于对HttpServletRequest进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。

 

过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题。

 

Filter的作用描述

1、在HttpServletRequest到达Servlet 之前,拦截客户的HttpServletRequest 。根据需要检查HttpServletRequest也可以修改HttpServletRequest 头和数据。

2、在HttpServletResponse到达客户端之前,拦截HttpServletResponse。 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

 

filter如何注册

在 web应用程序启动时,web 服务器将根据 web.xml 文件中的配置信息来创建每个注册的 Filter 实例对象,并将其保存在服务器的内存中

filter方法介绍

init()  Init 方法在 Filter 生命周期中仅执行一次,web 容器在调用 init 方法时

destory()  在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

doFilter()Filter 链的执行

 

FilterChain接口

1.如何实例化

代表当前Filter 链的对象。由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中

2.作用

调用过滤器链中的下一个过滤器

下面通过编码过滤器和日志过滤器进行介绍。

6.5.3、EncodingFilter 和LogFilter

在HelloServlet项目中新建EncodingFilter和LogFilter类继承Filter

EncodingFilter代码如下:

public classEncodingFilter implements Filter {

    private String sEncoding;

       public void destroy() {

              // TODO Auto-generated method stub

              System.out.println("EncodingFile destroy");

              sEncoding = null;

       }

 

       public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException {

              // TODO Auto-generated method stub

              // place your code here

              System.out.println("begin encoding"+sEncoding+" to EncodingFilter");

              // pass the request along the filter chain

       request.setCharacterEncoding(sEncoding);

              chain.doFilter(request, response);

              System.out.println("after encoding"+sEncoding+" to EncodingFilter");

             

       }

 

       public void init(FilterConfig fConfig) throws ServletException{

              // TODO Auto-generated method stub

              this.sEncoding = fConfig.getInitParameter("Encoding");

              System.out.println("EncodingFile init for loadencode "+sEncoding);                    

       }

 

}

 

LogFilter代码如下:

public class LogFilterimplements Filter {

    FilterConfig config;

    public LogFilter() {

        // TODO Auto-generated constructor stub

    }

 

       public void destroy() {

              // TODO Auto-generated method stub

              System.out.println("LogFile destroy");

              config = null;        

       }

       public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException {

              // TODO Auto-generated method stub

              // place your code here

        ServletContext  context= config.getServletContext();

        context.log("begin do filter toLogFilter");

              // pass the request along the filter chain

              chain.doFilter(request, response);

        context.log("after do filter toLogFilter");

       }

 

       public void init(FilterConfig fConfig) throws ServletException{

              // TODO Auto-generated method stub

              this.config = fConfig;

              System.out.println("LogFilter init ");                              

       }

 

 

 

 

Web.xml 配置

添加EncodingFilter

  <filter>

   <filter-name>EncodingFilter</filter-name>

   <filter-class>com.demo.Filter.EncodingFilter</filter-class>

   <init-param>

     <param-name>Encoding</param-name>

     <param-value>utf-8</param-value>

    </init-param>

  </filter>

 <filter-mapping>

   <filter-name>EncodingFilter</filter-name>

   <url-pattern>/*</url-pattern>

 </filter-mapping>

添加LogFilter

  <filter>

   <filter-name>LogFilter</filter-name>

   <filter-class>com.demo.Filter.LogFilter</filter-class>

  </filter>

 <filter-mapping>

   <filter-name>LogFilter</filter-name>

   <url-pattern>/*</url-pattern>

 </filter-mapping> 

 

 

启动服务器结果

LogFilter init

EncodingFile init for load encode utf-8

EncodingFile init for load encode null

LogFilter init

 

执行请求:http://localhost:8080/HelloServlet/Hello

beginencoding utf-8 to EncodingFilter

八月 24,2015 6:19:01下午 org.apache.catalina.core.ApplicationContext log

信息:begin do filter to LogFilter

八月 24,2015 6:19:01下午 org.apache.catalina.core.ApplicationContext log

信息:after do filter to LogFilter

afterencoding utf-8 to EncodingFilter

 

代码参考:HelloServlet项目

 

 

6.6、servlet监听器

6.6.1、监听器概念

监听器就是一个实现特定接口的java程序,用于监听java对象的创建、销毁及方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

 

在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为SerlvetConext,HttpSession和ServletRequest这三个域对象。

 

Servlet规范针对这三个对象上的操作,又把这多种类型的监听器划分三种类型:

 

1>监听三个域对象创建和销毁的事件监听器

2>监听域对象中属性的增加和删除的事件监听器

3>监听绑定到HttpSession域中的某个对象的状态的时间监听器。

 

应用场景:

 

1>在ServletContextLintener监听器的contextInitialized方法中,进行应用级的资源初始化以便提高效率,在contextDestroyed方法中对应用级的资源进行释放。

 

2>那么如何统计在线人数话,如何显示出当前登录的用户呢。如何踢出某些已登录的用户呢。就可以通过HttpSessionAttributeListener监听器的attributeAdded方法。

 

 

6.6.2、监听器类

Servlet API提供了针对三个ServletContext,HttpSessionServletRequest对象的8个监听器接口,他们分别是:

针对ServletContext对象

   ●  ServletContextListener:应用上下文生命周期监听器。用于监听ServletContext对象的创建和销毁。

   ●  ServletContextAttributeListener:应用上下文属性事件监听器。用于监听WEB应用上下文中的属性改变的事件。

针对HttpSession对象

   ●  HttpSessionListener:会话生命周期监听器。用于监听会话的创建和销毁时间。

   ●  HttpSessionActivationListenerListener:会话激活和钝化事件监听器。用于监听会话的激活和钝化的事件。

   ●  HttpSessionAttributeListener:会话属性事件监听器。用于监听会话中的属性改变的事件。

   ●  HttpSessionBindingListener:会话绑定事件监听器。这是唯一不需要在web.xml中设定的Listener。

针对ServletRequest对象

   ●  ServletRequestListener:请求生命周期监听器。用于监听请求的创建和销毁事件。

   ●  ServletRequestAttributeListener:请求属性事件监听器。用于监听请求中的属性改变的事件。

        每个监听器接口中都定义了一些回调方法,当对应的事件发生前或发生后,WEB容器会自动调用对应监听器实现类中的相应方法。

    Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext, HttpSessionServletRequest这三个域对象。

 

a、监听三个域对象创建和销毁的事件监听器

ServletContextListener

void contextDestroyed(ServletContextEvent sce)

void contextInitialized(ServletContextEvent sce) 

 

HttpSessionListener

void sessionCreated(HttpSessionEvent se)

void sessionDestroyed(HttpSessionEvent se) 

 

ServletRequestListener

void requestDestroyed(ServletRequestEvent sre) 

void requestInitialized(ServletRequestEvent sre)

 

web.xml 配置

<listener>

<listener-class>com.test.listener.MyHttpSessionAttributeListener</listener-class>

<listener-class>com.test.listener.MyServletContextAttributeListener</listener-class>

</listener>

 

6.6.3、LifecycleListener类

在项目HelloServlet下,

新建com.demo.Listener包下LifecycleListener类,并实现Listener接口


 

Web.xml配置,添加Listener监听器

  <listener>

    <listener-class>com.demo.Listener.LifecycleListener</listener-class>

  </listener>

 

控制台输出

 

6.6.4、AttributeListener类

在项目HelloServlet下,

新建com.demo.Listener包下AttributeListener类,并实现Listener接口

 

 

 

Web.xml配置,添加Listener监听器

  <listener>

    <listener-class>com.demo.Listener.LifecycleListener</listener-class>

  </listener>

  <listener>

   <listener-class>com.demo.Listener.AttributeListener</listener-class>

  </listener>

控制台输出

 

九、变更记录&常见问题&参考资料

9.1、变更记录

9.2、常见问题

9.3、参考资料

 

 

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值