JSP中的Servlet及Filter
asp.net中,如果开发人员想自己处理http请求响应,可以利用HttpHandler来满足这一要求;类似的,如果要拦截所有http请求,可以使用HttpMoudle。java的web开发中,也有类似的处理机制,与HttpHandler应对的是HttpServlet,与HttpModule对应的则是Filter。
一、HttpServlet
先看一个简单的示例:
package com.cnblogs.yjmyzz.servlet; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class SampleServlet extends HttpServlet { private static final long serialVersionUID = 7065409287377444221L; public SampleServlet(){
System.out.println("SampleServlet is initialized!");
} protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter().append("<h1>SampleServlet.doGet() is called!</h1>"); } protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter()
.append("<h1>SampleServlet.doPost() is called!</h1>"); } }
在HttpServlet中,程序员得自己控制所有要在页面上输出的内容,类似ASP.NET HttpHandler中Response.Write(...)一样。
自定义的Servlet必须在web.xml中注册才能使用,参考下面的配置片段:
<servlet>
<servlet-name>Sample</servlet-name>
<servlet-class>com.cnblogs.yjmyzz.servlet.SampleServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Sample</servlet-name>
<url-pattern>/A/*</url-pattern>
</servlet-mapping>
第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
还是先来一个最基本的示例
package com.cnblogs.yjmyzz.filter; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class AnotherFilter implements Filter { @Override
public void destroy() {
// TODO Auto-generated method stub } @Override
public void doFilter(ServletRequest reqeust, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.getWriter().append("<h1>AnotherFilter.doFilter is called!</h1>");
chain.doFilter(reqeust, response);
} @Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub } }
注意下24行,开发人员自定义的处理完成后,最后记得调用chain.doFilter(reqeust, response),因为每一次http请求的完整处理通常会有很多个Filter按顺序协作完成,这些Filter形成一个”链式结构“,这一行的作用,就是当自己的处理完成后,继续交给Filter链中的下一个Filter去处理。
同样,Filter也必须在web.xml中注册方能使用:
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.cnblogs.yjmyzz.filter.AnotherFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第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参数注入
package com.cnblogs.yjmyzz.filter; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class AnotherFilter implements Filter {
// 定义参数变量
private String someParamter; @Override
public void destroy() { } @Override
public void doFilter(ServletRequest reqeust, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.getWriter().append(
"<h1>AnotherFilter.doFilter is called!" + someParamter
+ "</h1>");
chain.doFilter(reqeust, response);
} @Override
public void init(FilterConfig cfg) throws ServletException {
// 取得传入的参数
someParamter = cfg.getInitParameter("someParameter"); } }
代码很简单,在init方法中接收参数即可,这个参数是从哪里传进来的呢?看下面的web.xml配置
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.cnblogs.yjmyzz.filter.AnotherFilter</filter-class>
<init-param>
<param-name>someParameter</param-name>
<param-value>HelloWorld</param-value>
</init-param>
</filter>
init-param节点就是答案
b) Filter复杂对象的参数注入
如果要传的参数是一个复杂对象,上面的方法就不太适合(当然:你可以把对象序列化成json字符串,然后到init中接收,再反序列,理论上也可行,但是比较感觉比较怪。)
先定义一个参数对象:
package com.cnblogs.yjmyzz.filter; public class SampleData { private String someField; public String getSomeField() {
return someField;
} public void setSomeField(String someField) {
this.someField = someField;
} }
为了对比,再来一个Filter
package com.cnblogs.yjmyzz.filter; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import org.springframework.beans.factory.annotation.Autowired; public class SampleFilter implements Filter { @Autowired
SampleData someData; @Override
public void destroy() { } @Override
public void doFilter(ServletRequest reqeust, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.getWriter().append(
"<h1>SampleFilter.doFilter is called!"
+ someData.getSomeField() + "</h1>");
chain.doFilter(reqeust, response);
} @Override
public void init(FilterConfig filterConfig) throws ServletException { } public SampleData getSomeData() {
return someData;
} public void setSomeData(SampleData someData) {
this.someData = someData;
} }
这里,我们希望SomeFilter在运行时,能动态注入一个SomeData实例。下面是配置部分:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someData" class="com.cnblogs.yjmyzz.filter.SampleData">
<property name="someField" value="abc"></property>
</bean> <bean id="sampleFilter" class="com.cnblogs.yjmyzz.filter.SampleFilter">
<property name="someData" ref="someData"></property>
</bean> </beans>
spring的xml配置中,先定义好SomeFilter的bean,然后是web.xml的Filter配置:
<filter>
<description>Filter1</description>
<display-name>Filter1</display-name>
<filter-name>Filter1</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>sampleFilter</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
对比下刚才的Filter配置,有几个变化:
filter-class 换成了 org.springframework.web.filter.DelegatingFilterProxy
init-param 节点通过targetBeanName 这个参数名,将sampleFilter bean动态注入
再来看看Servlet的参数注入,spring并没有提供类似DelegatingServletProxy的代理类,所以只能自己动手了,下面是二种常见做法:
a) 通过init方法,实现Servlet的Spring bean注入
package com.cnblogs.yjmyzz.servlet; import java.io.IOException; import javax.servlet.*;
import javax.servlet.http.*;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import com.cnblogs.yjmyzz.filter.SampleData; public class SampleServlet extends HttpServlet { private static final long serialVersionUID = 7065409287377444221L; SampleData someData; public SampleServlet() {
System.out.println("SampleServlet is initialized!");
} protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter().append(
"<h1>SampleServlet.doGet() is called!"
+ someData.getSomeField() + "</h1>"); } protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter().append(
"<h1>SampleServlet.doPost() is called!</h1>"); } public void init() throws ServletException {
super.init();
ServletContext servletContext = this.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
someData = ctx.getBean("someData", SampleData.class);
}
}
关键在于init方法,通过Spring的WebApplicationContext拿到上下文,然后手动去获取bean实例
b) 自己实现ServletProxy,实现注入
先定义ServletProxy代理类:
package com.cnblogs.yjmyzz.servlet; import java.io.IOException; import javax.servlet.*;
import javax.servlet.http.HttpServlet; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; public class HttpServletProxy extends HttpServlet { private static final long serialVersionUID = 4358391761577767574L; private String targetBean;
private HttpServlet proxy; public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
proxy.service(req, res);
} public void init() throws ServletException {
this.targetBean = getServletName();
getServletBean();
proxy.init(getServletConfig());
} private void getServletBean() {
WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(getServletContext());
this.proxy = (HttpServlet) wac.getBean(targetBean);
} }
本质上ServletProxy也是一个Servlet,在init方法中,通过动态获取servletName,利用Spring的WebApplicationContextt得到真正需要的Servlet Bean实例并保存在proxy变量中,最终对http执行处理的(即:调用service方法的),是proxy变量所指向的Servlet Bean实例。
定义真正需要使用的Servlet
package com.cnblogs.yjmyzz.servlet; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.cnblogs.yjmyzz.filter.SampleData; public class AnotherServlet extends HttpServlet { private static final long serialVersionUID = -3797187540470927379L; // 需要注入的Bean
SampleData someData; public AnotherServlet() {
System.out.println("AnotherServlet is initialized!");
} protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter().append(
"<h1>AnotherServlet.doGet() is called!"
+ someData.getSomeField() + "</h1>"); } protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { response.getWriter().append(
"<h1>AnotherServlet.doPost() is called!</h1>"); } public void setSomeData(SampleData someData) {
this.someData = someData;
} }
在spring的beans配置文件中,配置该Servlet Bean
<bean id="someData" class="com.cnblogs.yjmyzz.filter.SampleData">
<property name="someField" value="abc"></property>
</bean> <bean id="anotherServlet" class="com.cnblogs.yjmyzz.servlet.AnotherServlet">
<property name="someData" ref="someData"></property>
</bean>
最后是web.xml配置
<servlet>
<servlet-name>anotherServlet</servlet-name>
<servlet-class>com.cnblogs.yjmyzz.servlet.HttpServletProxy</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>anotherServlet</servlet-name>
<url-pattern>/A/*</url-pattern>
</servlet-mapping>
注:web.xml中的servlet-name节点值,必须于spring beans配置文件中的bean id一致,因为ServletProxy是根据ServletName来查找Bean实例的。
JSP中的Servlet及Filter的更多相关文章
- 从零开始的Spring Boot(2、在Spring Boot中整合Servlet、Filter、Listener的方式)
在Spring Boot中整合Servlet.Filter.Listener的方式 写在前面 从零开始的Spring Boot(1.搭建一个Spring Boot项目Hello World):http ...
- SpringBoot中使用Servlet,Filter,Listener
项目最近在替换之前陈旧的框架,改用SpringBoot进行重构,初接触,暂时还没有用到Servlet,Filter,Listener的地方,但在之前回顾Servlet的生命周期时,https://ww ...
- jsp中使用Servlet查询SQLSERVER数据库中的表的信息,并且打印在屏幕上
jsp中使用Servlet查询SQLSERVER数据库中的表的信息,并且打印在屏幕上 1.JavaBean的使用 package com.zheng; public class BookBean { ...
- Spring Boot中使用Servlet与Filter
在Spring Boot中使用Servlet,根据Servlet注册方式的不同,有两种使用方式.若使用的是Servlet3.0+版本,则两种方式均可使用:若使用的是Servlet2.5版本,则只能使用 ...
- Web.xml中设置Servlet和Filter时的url-pattern匹配规则
一.servlet容器对url的匹配过程: 当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url,比如我访问的是http://loca ...
- IDEA使用技巧,如何在JSP中创建Servlet“小程序”
步骤 1.新建一个java类,实现Servlet接口 2.实现接口中的抽象方法: 3.在web.xml文件中配置好servlet <web-app ......> <servlet& ...
- SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - 自定义Servlet、Filter、Listener是如何注册到Tomcat容器中的?(SpringBoot实现SpringMvc的原理)
上一篇我们讲了SpringBoot中Tomcat的启动过程,本篇我们接着讲在SpringBoot中如何向Tomcat中添加Servlet.Filter.Listener 自定义Servlet.Filt ...
- Servlet、Filter、Listener、Interceptor
首先,JSP/Servlet规范中定义了Servlet.Filter.Listener这三种角色,并没有定义Interceptor这个角 色,Interceptor是某些MVC框架中的角色,比如Str ...
- j2ee Servlet、Filter、Listener
首先,JSP/Servlet规范中定义了Servlet.Filter.Listener这三种角色,并没有定义Interceptor这个角色,Interceptor是某些MVC框架中的角色,比如Stru ...
随机推荐
- (转) 一步一步学习ASP.NET 5 (五)- TypeScript
转发:微软MVP 卢建晖 的文章,希望对大家有帮助.原文:http://blog.csdn.net/kinfey/article/details/44568971 编者语 : 人总会多次犯错,历史上告 ...
- 深入解析Windows操作系统笔记——CH1概念和术语
1.概念和工具 本章主要介绍Windows操作系统的关键概念和术语 1.概念和工具 1.1操作系统版本 1.2基础概念和术语 1.2.1Windows API 1.2.2 服务.函数和例程 1.2.3 ...
- SQL Server 2014新特性——事务持久性控制
控制事务持久性 SQL Server 2014之后事务分为2种:完全持久, 默认或延迟的持久. 完全持久,当事务被提交之后,会把事务日志写入到磁盘,完成后返回给客户端. 延迟持久,事务提交是异步的,在 ...
- android动态注册监听网络变化异常
在使用广播接收器监听网络变化的时候,在AndroidManifest.xml中加入<user-permission android:name="android.permission.A ...
- mybatis oracle BLOB类型字段保存与读取
一.BLOB字段 BLOB是指二进制大对象也就是英文Binary Large Object的所写,而CLOB是指大字符对象也就是英文Character Large Object的所写.其中BLOB是用 ...
- Linux下使用NDK编译FFMPEG(libstagefright)
这个月要负责一个项目,使用FFMPEG渲染视频,主要是Android端的,由于性能要求,要使用硬解码,但网上大多数教程都是没有libstagefright的,所以个人觉得,生成的so库文件也是没有开启 ...
- ELK Kafka json to elk
Logstash配置 input { kafka { zk_connect => "127.0.0.1:2181" topic_id => "clus ...
- 解决mstsc无法连接问题:由于没有远程桌面授权服务器可以提供许可证
一.故障案例① 今天上午在给测试组的IIS新增https的时候,发现远程弹出如下错误: 由于没有远程桌面授权服务器可以提供许可证,远程会话被中断.请跟服务器管理员联系. 度了度,原来也是很常见的一种错 ...
- CentOS 6.4下Squid代理服务器的安装与配置
一.简介 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络信息. Squid是一个缓存Internet 数据的软件,其接收用户的下载申请,并自动处理所下载的数据.当一个用 ...
- 8、FTP,二种文本传输模式
一.基本知识 1. FTP是 TCP/IP协议族 的协议之一,简称文件传输协议,主要用于远距离文件传输,如文件的上传和下载 2. 下面都是以VSFTP服务器为例 VSFTP服务器的用户有三种形式: 匿 ...