ITPub博客

首页 > IT职业 > IT职场 > JSP中的Servlet及Filter

JSP中的Servlet及Filter

IT职场 作者:youyouaq 时间:2021-09-09 09:11:30 0 删除 编辑

asp.net中,如果开发人员想自己处理http请求响应,可以利用HttpHandler来满足这一要求;类似的,如果要拦截所有http请求,可以使用HttpMoudle。java的web开发中,也有类似的处理机制,与HttpHandler应对的是HttpServlet,与HttpModule对应的则是Filter。

一、HttpServlet

先看一个简单的示例:

 1 package com.cnblogs.yjmyzz.servlet; 2  3 import java.io.IOException; 4  5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class SampleServlet extends HttpServlet {11 12     private static final long serialVersionUID = 7065409287377444221L;13 14     public SampleServlet(){15         System.out.println("SampleServlet is initialized!");16     }17     18     protected void doGet(HttpServletRequest request,19             HttpServletResponse response) throws ServletException, IOException {20 21         response.getWriter().append("

SampleServlet.doGet() is called!

");22 23     }24 25     protected void doPost(HttpServletRequest request,26             HttpServletResponse response) throws ServletException, IOException {27 28         response.getWriter()29                 .append("

SampleServlet.doPost() is called!

");30 31     }32 33 }

View Code

在HttpServlet中,程序员得自己控制所有要在页面上输出的内容,类似ASP.NET HttpHandler中Response.Write(...)一样。

自定义的Servlet必须在web.xml中注册才能使用,参考下面的配置片段:

1     2         Sample3         com.cnblogs.yjmyzz.servlet.SampleServlet4         15     6     7         Sample8         /A/*9     

View Code

第2行与第7行的servlet-name要一致;url-pattern表示该Servlet要拦截的url,如果写成"/*",则表示拦截所有url请求;load-on-startup是可选节点,如果该节点值>0时,webapp一启动就会自动实例化该Servlet,否则将延时到第一次访问被拦截的url时,才会被实例化。

如果web.xml中同时注册了多个Servlet,且都指定了load-on-startup,将按照load-on-startup节点值从小到大的优先级顺序,依次实例化所有注册的Servlet。

如果多个Servlet同时拦截了相同的url,则根据它们出现在web.xml中的顺序,仅最后出现的Servlet具有拦截处理权。

 

二、Filter

还是先来一个最基本的示例

 1 package com.cnblogs.yjmyzz.filter; 2  3 import java.io.IOException; 4  5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class AnotherFilter implements Filter {13 14     @Override15     public void destroy() {16         // TODO Auto-generated method stub17 18     }19 20     @Override21     public void doFilter(ServletRequest reqeust, ServletResponse response,22             FilterChain chain) throws IOException, ServletException {23         response.getWriter().append("

AnotherFilter.doFilter is called!

");24         chain.doFilter(reqeust, response);25     }26 27     @Override28     public void init(FilterConfig arg0) throws ServletException {29         // TODO Auto-generated method stub30 31     }32 33 }

View Code

注意下24行,开发人员自定义的处理完成后,最后记得调用chain.doFilter(reqeust, response),因为每一次http请求的完整处理通常会有很多个Filter按顺序协作完成,这些Filter形成一个”链式结构“,这一行的作用,就是当自己的处理完成后,继续交给Filter链中的下一个Filter去处理。

同样,Filter也必须在web.xml中注册方能使用:

1     2         Filter23         com.cnblogs.yjmyzz.filter.AnotherFilter4     5     6         Filter27         /*8     

View Code

 第2行与第6行的filter-name要保持一致;url-pattern为要拦截的url;如果一个web.xml中同时注册多个Filter,所有这些Filter都将起作用,处理的顺序按照在web.xml中出现的顺序,先出现的Filter先处理。

如果web.xml中同时注册了Servlet、Filter,且拦截的url相同时,Filter先处理,之后才轮到Servlet处理。

 

三、参数注入

通常在写Servlet、Filter时,有时候需要从外界获取一些参数,先来看下Filter的参数处理:

a) Filter基本String参数注入

 1 package com.cnblogs.yjmyzz.filter; 2  3 import java.io.IOException; 4  5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class AnotherFilter implements Filter {13     // 定义参数变量14     private String someParamter;15 16     @Override17     public void destroy() {18 19     }20 21     @Override22     public void doFilter(ServletRequest reqeust, ServletResponse response,23             FilterChain chain) throws IOException, ServletException {24         response.getWriter().append(25                 "

AnotherFilter.doFilter is called!" + someParamter26                         + "

");27         chain.doFilter(reqeust, response);28     }29 30     @Override31     public void init(FilterConfig cfg) throws ServletException {32         // 取得传入的参数33         someParamter = cfg.getInitParameter("someParameter");34 35     }36 37 }

View Code

代码很简单,在init方法中接收参数即可,这个参数是从哪里传进来的呢?看下面的web.xml配置

1     2         Filter23         com.cnblogs.yjmyzz.filter.AnotherFilter4         5             someParameter6             HelloWorld7         8     

View Code

init-param节点就是答案

b) Filter复杂对象的参数注入

如果要传的参数是一个复杂对象,上面的方法就不太适合(当然:你可以把对象序列化成json字符串,然后到init中接收,再反序列,理论上也可行,但是比较感觉比较怪。)

先定义一个参数对象:

 1 package com.cnblogs.yjmyzz.filter; 2  3 public class SampleData { 4      5     private String someField; 6  7     public String getSomeField() { 8         return someField; 9     }10 11     public void setSomeField(String someField) {12         this.someField = someField;13     }14 15 }

View Code

为了对比,再来一个Filter

 1 package com.cnblogs.yjmyzz.filter; 2  3 import java.io.IOException; 4  5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 import org.springframework.beans.factory.annotation.Autowired;13 14 public class SampleFilter implements Filter {15 16     @Autowired17     SampleData someData;18 19     @Override20     public void destroy() {21 22     }23 24     @Override25     public void doFilter(ServletRequest reqeust, ServletResponse response,26             FilterChain chain) throws IOException, ServletException {27         response.getWriter().append(28                 "

SampleFilter.doFilter is called!"29                         + someData.getSomeField() + "

");30         chain.doFilter(reqeust, response);31     }32 33     @Override34     public void init(FilterConfig filterConfig) throws ServletException {35 36     }37 38     public SampleData getSomeData() {39         return someData;40     }41 42     public void setSomeData(SampleData someData) {43         this.someData = someData;44     }45 46 }

View Code

这里,我们希望SomeFilter在运行时,能动态注入一个SomeData实例。下面是配置部分:

 1  2  5  6      7          8      9 10     11         12     13 14 

View Code

spring的xml配置中,先定义好SomeFilter的bean,然后是web.xml的Filter配置:

 1      2         Filter1 3         Filter1 4         Filter1 5         org.springframework.web.filter.DelegatingFilterProxy 6          7             targetBeanName 8             sampleFilter 9         10     11 12     13         Filter114         /*15     

View Code

对比下刚才的Filter配置,有几个变化:

filter-class 换成了 org.springframework.web.filter.DelegatingFilterProxy

init-param 节点通过targetBeanName 这个参数名,将sampleFilter bean动态注入

 

再来看看Servlet的参数注入,spring并没有提供类似DelegatingServletProxy的代理类,所以只能自己动手了,下面是二种常见做法:

a) 通过init方法,实现Servlet的Spring bean注入

 1 package com.cnblogs.yjmyzz.servlet; 2  3 import java.io.IOException; 4  5 import javax.servlet.*; 6 import javax.servlet.http.*; 7 import org.springframework.web.context.WebApplicationContext; 8 import org.springframework.web.context.support.WebApplicationContextUtils; 9 10 import com.cnblogs.yjmyzz.filter.SampleData;11 12 public class SampleServlet extends HttpServlet {13 14     private static final long serialVersionUID = 7065409287377444221L;15 16     SampleData someData;17 18     public SampleServlet() {19         System.out.println("SampleServlet is initialized!");20     }21 22     protected void doGet(HttpServletRequest request,23             HttpServletResponse response) throws ServletException, IOException {24 25         response.getWriter().append(26                 "

SampleServlet.doGet() is called!"27                         + someData.getSomeField() + "

");28 29     }30 31     protected void doPost(HttpServletRequest request,32             HttpServletResponse response) throws ServletException, IOException {33 34         response.getWriter().append(35                 "

SampleServlet.doPost() is called!

");36 37     }38 39     public void init() throws ServletException {40         super.init();41         ServletContext servletContext = this.getServletContext();42         WebApplicationContext ctx = WebApplicationContextUtils43                 .getWebApplicationContext(servletContext);44         someData = ctx.getBean("someData", SampleData.class);45     }46 }

View Code

关键在于init方法,通过Spring的WebApplicationContext拿到上下文,然后手动去获取bean实例

b) 自己实现ServletProxy,实现注入

先定义ServletProxy代理类:

 1 package com.cnblogs.yjmyzz.servlet; 2  3 import java.io.IOException; 4  5 import javax.servlet.*; 6 import javax.servlet.http.HttpServlet; 7  8 import org.springframework.web.context.WebApplicationContext; 9 import org.springframework.web.context.support.WebApplicationContextUtils;10 11 public class HttpServletProxy extends HttpServlet {12 13     private static final long serialVersionUID = 4358391761577767574L;14 15     private String targetBean;16     private HttpServlet proxy;17 18     public void service(ServletRequest req, ServletResponse res)19             throws ServletException, IOException {20         proxy.service(req, res);21     }22 23     public void init() throws ServletException {24         this.targetBean = getServletName();25         getServletBean();26         proxy.init(getServletConfig());27     }28 29     private void getServletBean() {30         WebApplicationContext wac = WebApplicationContextUtils31                 .getRequiredWebApplicationContext(getServletContext());32         this.proxy = (HttpServlet) wac.getBean(targetBean);33     }34 35 }

View Code

本质上ServletProxy也是一个Servlet,在init方法中,通过动态获取servletName,利用Spring的WebApplicationContextt得到真正需要的Servlet Bean实例并保存在proxy变量中,最终对http执行处理的(即:调用service方法的),是proxy变量所指向的Servlet Bean实例。

定义真正需要使用的Servlet

 1 package com.cnblogs.yjmyzz.servlet; 2  3 import java.io.IOException; 4  5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import com.cnblogs.yjmyzz.filter.SampleData;10 11 public class AnotherServlet extends HttpServlet {12 13     private static final long serialVersionUID = -3797187540470927379L;14 15     // 需要注入的Bean16     SampleData someData;17 18     public AnotherServlet() {19         System.out.println("AnotherServlet is initialized!");20     }21 22     protected void doGet(HttpServletRequest request,23             HttpServletResponse response) throws ServletException, IOException {24 25         response.getWriter().append(26                 "

AnotherServlet.doGet() is called!"27                         + someData.getSomeField() + "

");28 29     }30 31     protected void doPost(HttpServletRequest request,32             HttpServletResponse response) throws ServletException, IOException {33 34         response.getWriter().append(35                 "

AnotherServlet.doPost() is called!

");36 37     }38 39     public void setSomeData(SampleData someData) {40         this.someData = someData;41     }42 43 }

View Code

在spring的beans配置文件中,配置该Servlet Bean

1     2         3     4 5     6         7     

View Code

最后是web.xml配置

1     2         anotherServlet3         com.cnblogs.yjmyzz.servlet.HttpServletProxy4         15     6     7         anotherServlet8         /A/*9     

View Code

注:web.xml中的servlet-name节点值,必须于spring beans配置文件中的bean id一致,因为ServletProxy是根据ServletName来查找Bean实例的。

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3050/viewspace-2800258/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-08-13

  • 博文量
    90
  • 访问量
    785