场景1
一个网站,可以留言评论发消息等。消息通过前端输入文字,然后传给后端,再进入数据库,然后在网站展示出来。如果文字中包含网页脚本,会破坏我们的网页;如果包含敏感词,会对网站造成更严重的影响,甚至可能触犯法律法规,所以我们需要对消息进行过滤,对过滤处理的有问题的文字进行替换处理。
我们定义一个消息类:
package org.garen.cor;
/**
* 消息
*/
public class Msg {
private String name;
private String msg;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Msg{" +
"name='" + name + '\'' +
", msg='" + msg + '\'' +
'}';
}
}
最简单的处理
测试类:
package org.garen.cor;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
// 处理网页脚本
String r = msg.getMsg();
r = r.replace("<", "[");
r = r.replace(">", "]");
msg.setMsg(r);
System.out.println(r);
// 处理敏感词
r = r.replace("996", "955");
msg.setMsg(r);
System.out.println(r);
}
}
运行结果:
大家好:),[script],欢迎访问www.garen.org,大家都是996
大家好:),[script],欢迎访问www.garen.org,大家都是955
这种方式简单,但是不利于扩展。如果有新的条件需要处理的,就要修改代码。
使用设计模式,是把简单的程序复杂化,哪里会发生变化,就封装哪里。程序复杂了,但是提高了扩展性。
封装变化
消息过滤接口:
package org.garen.cor;
/**
* 消息过滤接口
*/
public interface MsgFilter {
void doFilter(Msg m);
}
网页脚本过滤器:
package org.garen.cor;
/**
* 网页脚本过滤器
*/
public class HTMLFilter implements MsgFilter{
@Override
public void doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("<", "[");
s = s.replace(">", "]");
m.setMsg(s);
}
}
敏感词过滤器:
package org.garen.cor;
/**
* 敏感词过滤器
*/
public class SensitiveFilter implements MsgFilter{
@Override
public void doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("996", "955");
m.setMsg(s);
}
}
测试类:
package org.garen.cor;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
// 处理网页脚本
MsgFilter htmlFilter = new HTMLFilter();
htmlFilter.doFilter(msg);
// 处理敏感词
MsgFilter sensitiveFilter = new SensitiveFilter();
sensitiveFilter.doFilter(msg);
// 打印消息
System.out.println(msg);
}
}
运行结果:
Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}
这样,如果有新的条件需要处理的,只需要增加一个新的过滤器,修改一下测试类即可。
把过滤器加入集合
测试类:
package org.garen.cor;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
// 过滤器集合
List<MsgFilter> filters = new ArrayList<>();
filters.add(new HTMLFilter());
filters.add(new SensitiveFilter());
// add new filter ...
// 遍历集合,进行过滤
for (MsgFilter filter : filters) {
filter.doFilter(msg);
}
}
}
运行结果:
Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}
我们把过滤器加入到集合中,然后遍历集合进行过滤。
如果有新的条件需要处理的,只需要增加一个新的过滤器,加入过滤器集合中即可。
遍历过滤器集合,依次处理,像不像一个链呢?
过滤器链条类
我们继续改造代码,创建一个过滤器链条类,并提供新增、删除、过滤等方法。
过滤器链条类:
package org.garen.cor;
import java.util.ArrayList;
import java.util.List;
public class MsgFilterChain {
List<MsgFilter> filters = new ArrayList<>();
public void add(MsgFilter filter) {
filters.add(filter);
}
// delete省略
public void doFilter(Msg msg) {
for (MsgFilter filter : filters) {
filter.doFilter(msg);
}
}
}
测试类:
package org.garen.cor;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
MsgFilterChain fc = new MsgFilterChain();
fc.add(new HTMLFilter());
fc.add(new SensitiveFilter());
fc.doFilter(msg);
System.out.println(msg);
}
}
运行结果:
Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}
这样有什么好处吗?看起来就是把测试类中的过滤器集合和遍历的代码移到一个MsgFilterChain类中。
改造add方法
我们改造一下add方法,就有所不同了。
过滤器链条类的add方法:
public MsgFilterChain add(MsgFilter filter) {
filters.add(filter);
return this;
}
测试类的添加过滤器代码:
MsgFilterChain fc = new MsgFilterChain();
fc.add(new HTMLFilter()).add(new SensitiveFilter());
在有新的过滤器加入,就.add一直加下去,形成一条链。
再多加一个链条
笑脸过滤器:
package org.garen.cor;
public class FaceFilter implements MsgFilter{
@Override
public void doFilter(Msg m) {
String s = m.getMsg();
s = s.replace(":)", "^v^");
m.setMsg(s);
}
}
url过滤器:
package org.garen.cor;
public class UrlFilter implements MsgFilter{
@Override
public void doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("www.garen.org", "http://www.garen.org");
m.setMsg(s);
}
}
测试类:
package org.garen.cor;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
MsgFilterChain fc = new MsgFilterChain();
fc.add(new HTMLFilter()).add(new SensitiveFilter());
// 新增加的链条2
MsgFilterChain fc2 = new MsgFilterChain();
fc2.add(new FaceFilter()).add(new UrlFilter());
fc.doFilter(msg);
fc2.doFilter(msg); // 链条2的处理
System.out.println(msg);
}
}
运行结果:
Msg{name=‘null’, msg=‘大家好v,[script],欢迎访问http://www.garen.org,大家都是955’}
两个链条连起来
修改MsgFilterChain也实现MsgFilter接口,fc.add(fc2)把两个链条连起来
过滤器链条类:
package org.garen.cor;
import java.util.ArrayList;
import java.util.List;
public class MsgFilterChain implements MsgFilter{
List<MsgFilter> filters = new ArrayList<>();
public MsgFilterChain add(MsgFilter filter) {
filters.add(filter);
return this;
}
// delete省略
@Override
public void doFilter(Msg msg) {
for (MsgFilter filter : filters) {
filter.doFilter(msg);
}
}
}
测试类:
package org.garen.cor;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
MsgFilterChain fc = new MsgFilterChain();
fc.add(new HTMLFilter()).add(new SensitiveFilter());
// 新增加的链条2
MsgFilterChain fc2 = new MsgFilterChain();
fc2.add(new FaceFilter()).add(new UrlFilter());
// 链条连起来
fc.add(fc2);
// 两个链条一起处理
fc.doFilter(msg);
System.out.println(msg);
}
}
运行结果:
Msg{name=‘null’, msg=‘大家好v,[script],欢迎访问http://www.garen.org,大家都是955’}
场景2
如果我想控制,执行一个过滤器后,是否继续执行,要怎么做?
修改MsgFilter,返回值改成布尔类型
package org.garen.cor;
/**
* 消息过滤接口
*/
public interface MsgFilter {
boolean doFilter(Msg m);
}
修改所有过滤器实现类,每个过滤器自己的逻辑判断返回ture/false。这里我们就不写逻辑判断了,敏感词过滤器返回false,其它返回true。
网页过滤器:
package org.garen.cor;
/**
* 网页脚本过滤器
*/
public class HTMLFilter implements MsgFilter{
@Override
public boolean doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("<", "[");
s = s.replace(">", "]");
m.setMsg(s);
return true;
}
}
敏感词过滤器:
package org.garen.cor;
/**
* 敏感词过滤器
*/
public class SensitiveFilter implements MsgFilter{
@Override
public boolean doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("996", "955");
m.setMsg(s);
return false;
}
}
笑脸过滤器:
package org.garen.cor;
public class FaceFilter implements MsgFilter{
@Override
public boolean doFilter(Msg m) {
String s = m.getMsg();
s = s.replace(":)", "^v^");
m.setMsg(s);
return true;
}
}
url过滤器:
package org.garen.cor;
public class UrlFilter implements MsgFilter{
@Override
public boolean doFilter(Msg m) {
String s = m.getMsg();
s = s.replace("www.garen.org", "http://www.garen.org");
m.setMsg(s);
return true;
}
}
链条类,也实现了接口,doFilter也要改成返回布尔类型。同时,如果过滤器返回false,则不再继续执行。
链条类:
package org.garen.cor;
import java.util.ArrayList;
import java.util.List;
public class MsgFilterChain implements MsgFilter{
List<MsgFilter> filters = new ArrayList<>();
public MsgFilterChain add(MsgFilter filter) {
filters.add(filter);
return this;
}
// delete省略
@Override
public boolean doFilter(Msg msg) {
for (MsgFilter filter : filters) {
if(!filter.doFilter(msg)) return false;
}
return true;
}
}
测试类不变,测试结果:
Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}
执行完敏感词过滤器后就结束了。
模拟Servlet的Filter
要求:
request执行顺序:filter1,filter2
response执行顺序:filter2,filter1
请求响应对象:
package org.garen.cor2;
public class Request {
String str;
}
package org.garen.cor2;
public class Response {
String str;
}
过滤器接口:
package org.garen.cor2;
public interface Filter {
void doFilter(Request request, Response response, FilterChain filterChain);
}
过滤器:
package org.garen.cor2;
public class HTMLFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain filterChain) {
System.out.println("HTMLFilter request: " + request.str);
filterChain.chain(request, response);
System.out.println("HTMLFilter response: " + response.str);
}
}
package org.garen.cor2;
public class UrlFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain filterChain) {
System.out.println("UrlFilter request: " + request.str);
filterChain.chain(request, response);
System.out.println("UrlFilter response: " + response.str);
}
}
链条:
package org.garen.cor2;
import java.util.ArrayList;
import java.util.List;
public class FilterChain{
List<Filter> filters = new ArrayList<>();
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
int i = 0;
public void chain(Request request, Response response) {
if (i == filters.size()) return ;
Filter filter = filters.get(i);
i++;
filter.doFilter(request, response, this);
}
}
测试类:
package org.garen.cor2;
public class Main {
public static void main(String[] args) {
// 请求响应对象
Request request = new Request();
request.str = "REQUEST";
Response response = new Response();
response.str = "RESPONSE";
// 加入链条
FilterChain filterChain = new FilterChain();
filterChain.add(new HTMLFilter());
filterChain.add(new UrlFilter());
// 执行
filterChain.chain(request, response);
}
}
运行结果:
HTMLFilter request: REQUEST
UrlFilter request: REQUEST
UrlFilter response: RESPONSE
HTMLFilter response: RESPONSE