JSP中的Servlet及Filter

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("<h1>SampleServlet.doGet() is called!</h1>");
22
23     }
24
25     protected void doPost(HttpServletRequest request,
26             HttpServletResponse response) throws ServletException, IOException {
27
28         response.getWriter()
29                 .append("<h1>SampleServlet.doPost() is called!</h1>");
30
31     }
32
33 }

View Code

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

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

1     <servlet>
2         <servlet-name>Sample</servlet-name>
3         <servlet-class>com.cnblogs.yjmyzz.servlet.SampleServlet</servlet-class>
4         <load-on-startup>1</load-on-startup>
5     </servlet>
6     <servlet-mapping>
7         <servlet-name>Sample</servlet-name>
8         <url-pattern>/A/*</url-pattern>
9     </servlet-mapping>

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     @Override
15     public void destroy() {
16         // TODO Auto-generated method stub
17
18     }
19
20     @Override
21     public void doFilter(ServletRequest reqeust, ServletResponse response,
22             FilterChain chain) throws IOException, ServletException {
23         response.getWriter().append("<h1>AnotherFilter.doFilter is called!</h1>");
24         chain.doFilter(reqeust, response);
25     }
26
27     @Override
28     public void init(FilterConfig arg0) throws ServletException {
29         // TODO Auto-generated method stub
30
31     }
32
33 }

View Code

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

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

1     <filter>
2         <filter-name>Filter2</filter-name>
3         <filter-class>com.cnblogs.yjmyzz.filter.AnotherFilter</filter-class>
4     </filter>
5     <filter-mapping>
6         <filter-name>Filter2</filter-name>
7         <url-pattern>/*</url-pattern>
8     </filter-mapping>

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     @Override
17     public void destroy() {
18
19     }
20
21     @Override
22     public void doFilter(ServletRequest reqeust, ServletResponse response,
23             FilterChain chain) throws IOException, ServletException {
24         response.getWriter().append(
25                 "<h1>AnotherFilter.doFilter is called!" + someParamter
26                         + "</h1>");
27         chain.doFilter(reqeust, response);
28     }
29
30     @Override
31     public void init(FilterConfig cfg) throws ServletException {
32         // 取得传入的参数
33         someParamter = cfg.getInitParameter("someParameter");
34
35     }
36
37 }

View Code

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

1     <filter>
2         <filter-name>Filter2</filter-name>
3         <filter-class>com.cnblogs.yjmyzz.filter.AnotherFilter</filter-class>
4         <init-param>
5             <param-name>someParameter</param-name>
6             <param-value>HelloWorld</param-value>
7         </init-param>
8     </filter>

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     @Autowired
17     SampleData someData;
18
19     @Override
20     public void destroy() {
21
22     }
23
24     @Override
25     public void doFilter(ServletRequest reqeust, ServletResponse response,
26             FilterChain chain) throws IOException, ServletException {
27         response.getWriter().append(
28                 "<h1>SampleFilter.doFilter is called!"
29                         + someData.getSomeField() + "</h1>");
30         chain.doFilter(reqeust, response);
31     }
32
33     @Override
34     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 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5
 6     <bean id="someData" class="com.cnblogs.yjmyzz.filter.SampleData">
 7         <property name="someField" value="abc"></property>
 8     </bean>
 9
10     <bean id="sampleFilter" class="com.cnblogs.yjmyzz.filter.SampleFilter">
11         <property name="someData" ref="someData"></property>
12     </bean>
13
14 </beans>

View Code

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

 1     <filter>
 2         <description>Filter1</description>
 3         <display-name>Filter1</display-name>
 4         <filter-name>Filter1</filter-name>
 5         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 6         <init-param>
 7             <param-name>targetBeanName</param-name>
 8             <param-value>sampleFilter</param-value>
 9         </init-param>
10     </filter>
11
12     <filter-mapping>
13         <filter-name>Filter1</filter-name>
14         <url-pattern>/*</url-pattern>
15     </filter-mapping>

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                 "<h1>SampleServlet.doGet() is called!"
27                         + someData.getSomeField() + "</h1>");
28
29     }
30
31     protected void doPost(HttpServletRequest request,
32             HttpServletResponse response) throws ServletException, IOException {
33
34         response.getWriter().append(
35                 "<h1>SampleServlet.doPost() is called!</h1>");
36
37     }
38
39     public void init() throws ServletException {
40         super.init();
41         ServletContext servletContext = this.getServletContext();
42         WebApplicationContext ctx = WebApplicationContextUtils
43                 .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 = WebApplicationContextUtils
31                 .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     // 需要注入的Bean
16     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                 "<h1>AnotherServlet.doGet() is called!"
27                         + someData.getSomeField() + "</h1>");
28
29     }
30
31     protected void doPost(HttpServletRequest request,
32             HttpServletResponse response) throws ServletException, IOException {
33
34         response.getWriter().append(
35                 "<h1>AnotherServlet.doPost() is called!</h1>");
36
37     }
38
39     public void setSomeData(SampleData someData) {
40         this.someData = someData;
41     }
42
43 }

View Code

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

1     <bean id="someData" class="com.cnblogs.yjmyzz.filter.SampleData">
2         <property name="someField" value="abc"></property>
3     </bean>
4
5     <bean id="anotherServlet" class="com.cnblogs.yjmyzz.servlet.AnotherServlet">
6         <property name="someData" ref="someData"></property>
7     </bean>

View Code

最后是web.xml配置

1     <servlet>
2         <servlet-name>anotherServlet</servlet-name>
3         <servlet-class>com.cnblogs.yjmyzz.servlet.HttpServletProxy</servlet-class>
4         <load-on-startup>1</load-on-startup>
5     </servlet>
6     <servlet-mapping>
7         <servlet-name>anotherServlet</servlet-name>
8         <url-pattern>/A/*</url-pattern>
9     </servlet-mapping>

View Code

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

 

时间: 2024-10-01 10:20:41

JSP中的Servlet及Filter的相关文章

JSP 中的servlet在本地能运行,在服务器端不能运行

问题描述 JSP 中的servlet在本地能运行,在服务器端不能运行 做一个用户名密码的登陆表单,使用servlet对输入的用户名密码与数据库里用户名密码进行比较,如果正确,就转至登陆页面,不正确就提示错误.在本地运行一切正常,但是放在服务器上,输入完用户名密码.点击确定后,就一直是网页正在连接的状态,死活不能运行出来.求大神看看到底是哪里有问题.(对不起实在没有C币了--) 解决方案 惊喜!Java为服务器端Web应用带来最高运行速度 解决方案二: 自己看一下日志文件,有没有报错信息. 据你描

从jsp中向servlet传数据库指针的写法不知道对不对,rs是不是可以传过去,求大神指导

问题描述 从jsp中向servlet传数据库指针的写法不知道对不对,rs是不是可以传过去,求大神指导 rs是数据库指针,想在servlet中获取rs数据库指针,不知道这么写对不对

jsp中利用servlet实现图片上传

 代码如下 复制代码 首先,页面中即JSP中需要如下的组件: <h2 class="h2">       上传照片:      </h2>      <form action="pic.do" method="post"       enctype="multipart/form-data">       <input type="file" name="

web.xml 中的listener、 filter、servlet 加载顺序及其详解

在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰.         首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的结论是:listener -> filter -> servlet         同时还存在着这样一种配置节:context-pa

关于Servlet、Jsp中的多国语言显示

js|servlet|显示 因为一直不信Java竟会有不能混排显示多国语言的BUG,这个周末研究了一下Servlet.Jsp的多国语言显示的问题,也就是Servlet的多字符集问题,由于我对字符集的概念还不是很清晰所以写出的东西未必是准确的,我是这样理解Java中的字符集的:在运行时,每个字符串对象中存储的都是编码为UNICODE内码的(我觉得所有的语言中都是有相应编码的,因为在计算机内部字符串总是用内码来表示的,只不过一般计算机语言中的字符串编码时平台相关的,而Java则采用了平台无关的UNI

在Servlet与JSP中取得当前文件所在的相对路径与绝对路径

js|servlet //Servlet中 //JSP中的application对象就是Servlet中的ServerContext,所以在Servlet中是如此获得 //import java.io.File; System.out.println("根目录所对应的绝对路径:" + request.getServletPath() + ""); String strPathFile = request.getSession().getServletContext(

关于Servlet、Jsp中的多国语言显示(续)

js|servlet|显示 续   --- /*** Insert the method's description here.* Creation date: (2001-2-4 17:28:17)* @return java.util.Enumeration*/public Enumeration getParameterNames() {if (pairs == null) return null;return pairs.keys();}/*** Insert the method's

关于Servlet、Jsp中的多国语言显示 -- 转自高人

js|servlet|显示 /***有朋友有如此苦心之作,实在感谢,相信它不会怪我转贴吧,他的email是vividq@china.com*/ 关于Servlet.Jsp中的多国语言显示 因为一直不信Java竟会有不能混排显示多国语言的BUG,这个周末研究了一下Servlet.Jsp的多国语言显示的问题,也就是Servlet的多字符集问题,由于我对字符集的概念还不是很清晰所以写出的东西未必是准确的,我是这样理解Java中的字符集的:在运行时,每个字符串对象中存储的都是编码为UNICODE内码的(

Servlet、Jsp中的多国语言显示

js|servlet|显示 因为一直不信Java竟会有不能混排显示多国语言的BUG,这个周末研究了一下Servlet.Jsp的多国语言显示的问题,也就是Servlet的多字符集问题,由于我对字符集的概念还不是很清晰所以写出的东西未必是准确的,我是这样理解Java中的字符集的:在运行时,每个字符串对象中存储的都是编码为UNICODE内码的(我觉得所有的语言中都是有相应编码的,因为在计算机内部字符串总是用内码来表示的,只不过一般计算机语言中的字符串编码时平台相关的,而Java则采用了平台无关的UNI