前言
在前一章中已经初步的介绍了过滤器的定义和过滤器的简单使用,这一章详细介绍过滤器的具体使用
还是先给各位贴出我的架构
编码过滤器
目的:解决前台数据提交到后端的编码问题
开发过滤器
首先还是在web.xml中去注册好我们的过滤器;
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>net.zxy.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/login</url-pattern>
</filter-mapping>
然后写一个简单的表单提交页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>表单验证</title>
</head>
<body>
<form method="post" action="login">
<input type="text" name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
然后写一个MyFilter类,开始编写方法体:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpServletResponse response= (HttpServletResponse) servletResponse;
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
filterChain.doFilter(request,response);
}
测试1
Servlet类
import java.io.IOException;
@javax.servlet.annotation.WebServlet(name = "LoginServlet",value = "/login")
public class LoginServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
String username=request.getParameter("username");
System.out.println(username);
response.getWriter().write(username);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
}
}
发现并没有乱码的现象
但是上面的过滤器是不完善的,因为浏览器是采用的get方式请求数据,只靠上面的过滤器是无法直接完成过滤的。
那我们咋办呢?在之前我们解决乱码是将响应的数据用ISO8859-1进行反编译然后可以得到utf-8的数据。
也就是说,根本原因就是在于getParameter()方法得到的是ISO8859-1的数据我们不想要,换句话说,request对象中的方法不够我们使用。
当然,sun公司也考虑到这件事,所以为我们提供了一个request的增强类HttpServletRequestWrapper
来为我们增强request功能。
增强request对象
要增强request对象,就需要使用包装模式,包装模式一共有以下五个步骤:
- 实现与被增强对象相同的接口
- 定义一个变量记住被增强对象
- 定义一个构造器接受被增强对象
- 覆盖需要增强的方法
- 对于不想增强的方法,那就直接去调用他
所以我们再来使用包装类,需要继承HttpServletRequestWrapper
所以我这儿在FIlter包下新建一个类,叫做CharsetFilter
import net.zxy.wrapper.MyCharsetFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CharsetFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request= (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) resp;
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MyCharsetFilter myCharsetFilter=new MyCharsetFilter(request);
chain.doFilter(myCharsetFilter, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
然后再写一个Servlet和wrapper,我这儿就直接把代码和图贴出来了:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "Servlet02",value = "/s2")
public class Servlet02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username=request.getParameter("username");
System.out.println(username);
response.getWriter().write(username);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
public class MyCharsetFilter extends HttpServletRequestWrapper {
/**
* Constructs a request object wrapping the given request.
*
* @param request the {@link HttpServletRequest} to be wrapped.
* @throws IllegalArgumentException if the request is null
*/
HttpServletRequest request;
public MyCharsetFilter(HttpServletRequest request) {
super(request);
this.request=request;
}
@Override
public String getParameter(String name) {
String value = this.request.getParameter(name);
try {
if (this.request.getMethod().equalsIgnoreCase("get") && this.request.getMethod().equalsIgnoreCase("post")){
value = new String(value.getBytes("ISO-8859-1"), "utf-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value ;
}
}
然后再去注册一下filter
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>net.zxy.filter.MyFilter</filter-class>
</filter>
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>net.zxy.filter.CharsetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/login</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CharsetFilter</filter-name>
<url-pattern>/s2</url-pattern>
</filter-mapping>
</web-app>
这些弄好了之后再去写一个表单,因为之前的表单已经绑定了一个过滤器
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>表单验证</title>
</head>
<body>
<form method="post" action="s2">
<input type="text" name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
我们再看看效果
控制台也完美输出
可能有小伙伴儿会觉得奇怪,我们多谢了这么多类,但是原先的代码还是没有变,这是为啥,不会觉得多此一举吗?
其实我们原先设置的确实没有变,我们多写的这个类最主要的还是我们的过滤器,其他的代码都只是配角。
不信你看下面的这个例子;
敏感词过滤器
这个例子我们还是在index.jsp中去操作。
所谓的敏感词过滤器,说白了相当于你打LOL的时候,骂人的话会自动给你屏蔽成*
号,当然我们也可以自定义符号,这儿为了方便我也用*
号
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
public class MyDirtyFilter extends HttpServletRequestWrapper {
HttpServletRequest request;
public MyDirtyFilter(HttpServletRequest request) {
super(request);
this.request=request;
}
@Override
public String getParameter(String name) {
String value=this.request.getParameter(name);
try {
value=new String(value.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
List<String> list= Arrays.asList("sb","尼玛");
try{
for (String s:list){
if (s.equals(value)){
value="*****";
}
}
}
catch (Exception e){
e.printStackTrace();
}
return value;
}
}
然后我们去运行一下子:
wc,很强大啊,有木有。。
我学到这儿的时候,我顿时想了想,我们学过反射,也就是说可以通过类名去调用方法,那我们就可以在代码中通过反射,用逆向思维去改这个代码。等有空了我去试试,经验也会分享给大家。
压缩资源过滤器
所谓的压缩资源,也就是我们平时用的解压,你可以理解为抽真空。
我们想服务器上传数据的时候,有时候会因为数据过大而导致占用资源的情况,这时候就需要去压缩他。
想一想,我们在实现压缩的时候是在请求的时候就压缩还是收到响应之后再压缩呢?
我们客户端向浏览器发送数据一般是:客户端发起请求——经过过滤器——服务器响应——接收数据
所以,这时候就会用response来实现压缩。
当然,最原始的当然是这样,不过我们既然学了过滤器,就不可能去响应的时候压缩他了。要体现出过滤器的高逼格,当然要使用过滤器来搞定了。
sun公司也很人性化,知道我们想干嘛,所以呢,有一个HttpServletResponseWrapper
来对response进行增强。
就以一个很简单的例子,由于过滤器执行之后需要放行才能执行后面的代码,所以我们就以response中的writer()方法来搞定这一节。不让他输入到浏览器上。
说了这么一大堆,还是上手吧。
新建一个wrapper类,叫做MyResponse,让他继承自HttpServletResponseWrapper
增强response对象
我们知道,response中有两个对象(ServletOutputStream和PrintWriter
)来调用write()方法的,我们为了不让他直接显示到浏览器上,我们就要对他进行一次重写。
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.http.HttpResponse;
public class MyResponse extends HttpServletResponseWrapper {
/**
* Constructs a response adaptor wrapping the given response.
*
* @param response the {@link HttpServletResponse} to be wrapped.
* @throws IllegalArgumentException if the response is null
*/
HttpServletResponse response;
public MyResponse(HttpServletResponse response) {
super(response);
this.response=response;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return super.getOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException {
return super.getWriter();
}
}
由于ServletOutputStream能直接调用write()方法,所以我们需要去对他再一次增强
增强ServletOutputStream
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class MyServletOutputStream extends ServletOutputStream {
ByteArrayOutputStream byteArrayOutputStream;
public MyServletOutputStream(ByteArrayOutputStream byteArrayOutputStream){
this.byteArrayOutputStream=byteArrayOutputStream;
}
public boolean isReady() {
return false;
}
public void setWriteListener(WriteListener writeListener) {
}
public void write(int b) throws IOException {
this.byteArrayOutputStream.write(b);
}
}
接着我们再去增强一下PrintWriter()方法;别问为啥上面的MyResponse类没有做这些,仔细看上面重写的是什么你就知道了。
增强PrintWriter
PrintWriter对象就好办了,它本来就是一个包装类,看它的构造方法,我们直接可以把ByteArrayOutputSteam传递给PrintWriter上。
@Override
public PrintWriter getWriter() throws IOException {
printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, this.response.getCharacterEncoding()));
return printWriter;
}
获取缓存数据
由于我们把所有的数据都放在了ByteArrayOutputStream上,所以哦我们要提供一个方法去获取这上面的数据。
public byte[] getBuffer() {
try {
//防止数据在缓存中,要刷新一下!
if (printWriter != null) {
printWriter.close();
}
if (byteArrayOutputStream != null) {
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
所以完整的代码就是
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.http.HttpResponse;
public class MyResponse extends HttpServletResponseWrapper {
/**
* Constructs a response adaptor wrapping the given response.
*
* @param response the {@link HttpServletResponse} to be wrapped.
* @throws IllegalArgumentException if the response is null
*/
HttpServletResponse response;
private PrintWriter printWriter;
private ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
public MyResponse(HttpServletResponse response) {
super(response);
this.response=response;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MyServletOutputStream(byteArrayOutputStream);
}
@Override
public PrintWriter getWriter() throws IOException {
printWriter=new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));
return printWriter;
}
public byte[] getBuffer(){
try {
// 防止数据缓存,刷新一下
if (printWriter !=null){
printWriter.close();
}
if (byteArrayOutputStream!=null){
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
过滤器
在filter包下新建一个过滤器叫ResponseFilter
import net.zxy.wrapper.MyResponse;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
public class ResponseFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request= (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) resp;
MyResponse myResponse=new MyResponse(response);
// 把被增强的的response对象传递进去,目标资源调用write()方法的死后就不会直接把数据显示到浏览器上
chain.doFilter(req, myResponse);
// 得到目标资源想要返回给浏览器的数据
byte[] bytes=myResponse.getBuffer();
// 输出原来的大小
System.out.println("压缩前:"+bytes.length);
// 使用GZIP压缩
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream=new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(bytes);
// 得到压缩后的数据
byte[] gzip=byteArrayOutputStream.toByteArray();
System.out.println("压缩后:"+gzip.length);
// 设置headers,告诉浏览器,这是压缩数据
response.setHeader("content-encoding","gzip");
response.setContentLength(gzip.length);
response.getOutputStream().write(gzip);
}
public void init(FilterConfig config) throws ServletException {
}
}
测试
新建一个Servlet03
在Servlet上输出一大段字:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "Servlet03",value = "/s3")
public class Servlet03 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("fdshfidsuhfidusfhuidsfhuidshdsuifhsd" +
"uifhsduifffffdshfidsuhfidusfhuidsfhuidshdsuif" +
"hsduifhsduifffffdshfidsuhfidusfhuidsfhuidshd" +
"suifhsduifhsduifffffdshfidsuhfidusfhuidsfhuidsh" +
"dsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuids" +
"hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuid" +
"shdsuifhsduifhsduiffdshfidsuhfidusfhuidsfhuids" +
"hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhui" +
"dshdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfh" +
"uidshdsuifhsduifhsduifffffdshfidsuhfidusfhuids" +
"fhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhuid" +
"sfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhui" +
"dsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfh" +
"uidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusf" +
"huidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidus" +
"fhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhfid" +
"usfhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhf" +
"idusfhuidsfhuidshdsuifhsduifhsd" +
"uifffffdshfidsuhfidusfhuidsfhuidshdsuifhsduifhsduifffffff");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
效果图
小结
由于这一章本人知识学的也不是很牢固,所以暂时也只能分享给大家这些。
谢谢观看