Servlet技术规范 描述三种技术 : Servlet(服务器小程序) 、Filter(过滤器)、 Listener(监听器)
1 新建类 继承httpServlet
2 重写doGet 和 dopost方法
3 在web.xml中 注册和映射
2.Filter是如何实现拦截的?
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
调用目标资源之前,让一段代码执行
是否调用目标资源(即是否让用户访问web资源)。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
调用目标资源之后,让一段代码执行
Filter运行在服务器端,对服务器端web资源的访问 进行拦截,起到过滤的作用
Servlet API中 定义接口 Filter,用户只需要编写程序实现Filter接口,完成过滤器编写
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
Hello,JSP
// HelloServlet
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().println("Hello,Servlet
");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.2. 编写类 实现 Filter接口
/**
* 编写为过滤器,过滤器作用 用来拦截web资源的访问
*
* @author seawind
*
*/
public class Filter1 implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 执行过滤
System.out.println("执行Filter1 ");
// 拦截后,如何让目标资源执行
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
3.3. 在服务器端注Filter(配置拦截哪个web资源----- web.xml
Filter1
cn.itcast.filter.Filter1
Filter1
/hello.jsp
HelloServlet
3.4. 客户端访问被拦截目标资源之前,服务器调用Filter的doFilter方法 ,执行过滤
3.5. Filter的doFilter方法中传入 FilterChain, 如果调用FilterChain的doFilter 就会执行目标资源,否则目标资源不会执行
问题1: 每次使用过滤器都需要 实现filter接口, 再去web.xml中配置, 是否很麻烦? 有没有更加简便的方法?
问题2: 如果配置两个过滤器谁先执行,谁后执行? 由什么决定的?
4. FilterChain
多个过滤器组成过滤器链,谁先执行,谁后执行?
在客户端访问服务器web资源时,服务器端为一个web资源,配置多个过滤器拦截 ,这多个过滤器,就会组成过滤器链 FilterChain, 调用FilterChain的doFilter 表示要执行过滤器链下一个资源,如果当前过滤器已经是链上最后一个过滤器,就会执行目标资源
安检部门上岗前, 必须 发放安检设备
每次安检,都有严格的流程
结束安检, 需要回收安检设备
public class AnjianFilter implements Filter {
public AnjianFilter() {
System.out.println("构造方法: 地铁安检部门成立----------------------");
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("init: 安检人员上岗前的准备工作----------------------");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter: 每次有人进入地铁必须进行安全检查----------------------" + new Date().toLocaleString());
// 允许通过
chain.doFilter(request, response);
}
public void destroy() {
System.out.println("destroy: 收回安检设备----------------------");
}
}
init(FilterConfig) doFilter(request,response,filterChain) destroy()
1、Filter对象在tomcat服务器启动时 创建,调用init方法 (只会创建一个对象,init方法执行一次)
2、doFilter 每次拦截目标资源时,执行
3、destroy 服务器关闭时执行
请思考:
安检部门 如果在非节假日客流量少时,5个手持安检设备就够了.
但是碰上节假日客流量多时,10个手持安检设备才够用,需要向上级申请.
节假日过后客流量少了,4个手持安检设备就够了,还需要再次向上级申请换回去…
如此频繁的申请,等待通过是否很麻烦,大家有没有好的主意?
6. FilterConfig对象
FilterConfig 作用和 ServletConfig 类似,用来在Filter初始化阶段,将参数传递给过滤器
1、通过 String getInitParameter(String name) 获得过滤器初始化参数
1、如果连接目标资源是一个Servlet,可以选择url和servlet名称两种配置方式
/hello
HelloServlet
2、url-pattern 和 Servlet中路径写法一样,有三种 : 完全匹配、目录匹配、扩展名匹配
3、指定过滤器所拦截的资源被 Servlet 容器调用的方式
容器调用服务器端资源 有四种方式
REQUEST、FORWARD、INCLUDE、ERROR
// 处理请求post乱码代码
request.setCharacterEncoding("utf-8");
// 设置响应编码集代码`这里写代码片`
response.setContentType("text/html;charset=utf-8");
经常会使用,而过滤器可以在目标资源之前执行,将很多程序中处理乱码公共代码,提取到过滤器中 ,以后程序中不需要处理编码问题
需求: 要求用户输入用户名,显示在页面上
8.1.1. input.jsp
8.1.2. Demo1Serlvet
public class Demo1Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
response.getWriter().println("幸会," + username);
}
}
8.1.3. EncodingFilter
public class EncodingFilter implements Filter {
public EncodingFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 解决获取参数出现中文乱码
request.setCharacterEncoding("utf-8");
// 解决浏览器出现中文乱码
response.setContentType("text/html;charset=utf-8");
// 放行
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
案例1缺点: 可以解决post方式的乱码, 但是解决get方式的乱码吗? 如果不可以请思考怎么做?
案例2:解决整个项目的乱码
public class GenericEncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 为了能够使用子类的方法,需要向下转型
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
// 使用包装 对方法进行增强
HttpServletRequest myRequest = new MyRequest(httpServletRequest);
// 放行
chain.doFilter(myRequest, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
@Override
public void destroy() {
}
class MyRequest extends HttpServletRequestWrapper{
private HttpServletRequest httpServletRequest;
// 记录是否修改过
private boolean isUpdate = false;
public MyRequest(HttpServletRequest request) {
super(request);
this.httpServletRequest = request;
}
@Override
public Map getParameterMap() {
// 1 获取请求方式
String method = httpServletRequest.getMethod();
// 2 根据不同方式,做出对应的处理
if("post".equalsIgnoreCase(method)) {
// 设置请求编码集
try {
httpServletRequest.setCharacterEncoding("utf-8");
return httpServletRequest.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else if("get".equalsIgnoreCase(method)) {
// 先编码,再解码
Map parameterMap = httpServletRequest.getParameterMap();
if(!isUpdate) {
try {
for(Entry entry : parameterMap.entrySet()){
String[] valueArr = entry.getValue();
for(int i=0; i parameterMap = this.getParameterMap();
String[] valueArr = parameterMap.get(name);
if(valueArr!=null) {
return valueArr[0];
}else {
return null;
}
}
@Override
public String[] getParameterValues(String name) {
return this.getParameterMap().get(name);
}
}
}
==================================================================================================================
过滤器
1、过滤器编写步骤
2、全局编码 过滤器
3、通用get/post乱码过滤器 ------------ 理解实现过程 ,保存起来会使用