0 设计模式
不了解设计模式的小伙伴可以通过这篇文章了解一下什么是设计模式
https://blog.csdn.net/qq_42874315/article/details/120006447?spm=1001.2014.3001.5502
1 责任链模式
责任链模式是我个人认为比较重要的一种设计模式,在我日常的编码中也较常用到,责任链模式的本质就是过滤器,责任链模式可以使过滤条件自由组合,降低了代码的耦合度,并且扩展性非常高,面向责任链过滤,而不面向具体的过滤器去过滤。
原理图
2 实现思路
3 需要的类
-
过滤器接口 -
多个实现过滤器接口的具体过滤器 -
实现过滤器接口的具体责任链(在责任链的doFilter中可以提前就对过滤器进行注册) 责任链中需要一个额外的方法add,用来添加具体的过滤器 需要一个含有多个Filter集合(注册过滤器用的) -
消息实体(往过滤器中传入的) -
额外的一个测试方法(需要注意的是,提前将过滤器添加到责任链中,面向责任链过滤,而不面向具体的过滤器去过滤)
4 具体实现
4.1 Filter(创建过滤器接口)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:44
*/
public interface Filter {
boolean doFilter(Message m);
}
4.2 多个实现过滤器接口的具体过滤器
4.2.1 FaceFilter(将:) 替换为 V)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:45
*/
public class FaceFilter implements Filter {
@Override
public boolean doFilter(Message m) {
// 处理msg
String r = m.getMsg();
r = r.replace(":)","^V^");
m.setMsg(r);
return true;
}
}
4.2.2 HtmlFilter(将< 替换为 [ 将> 替换为 ])
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:45
*/
public class HtmlFilter implements Filter {
@Override
public boolean doFilter(Message m) {
// 处理msg
String r = m.getMsg();
r = r.replace('<','[');
r = r.replace('>',']');
m.setMsg(r);
return true;
}
}
4.2.3 SensitiveFilter(将996 替换为 007)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:54
*/
public class SensitiveFilter implements Filter {
@Override
public boolean doFilter(Message m) {
// 处理msg
String r = m.getMsg();
r = r.replace("996","007");
m.setMsg(r);
return true;
}
}
4.3 FilterChain(实现过滤器接口的具体责任链)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:47
*/
public class FilterChain implements Filter {
List<Filter> filters = new ArrayList<>();
public FilterChain add(Filter f){
filters.add(f);
return this;
}
@Override
public boolean doFilter(Message m) {
for (Filter filter : filters) {
if (!filter.doFilter(m)){
return false;
}
}
return true;
}
}
4.4 Message(消息实体,根据实际情况完全可以用一个字符串去替代)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:44
*/
public class Message {
String name;
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 "Message{" +
"msg='" + msg + '\'' +
'}';
}
}
4.5 测试类
注:在责任链的doFilter中可以提前就对过滤器进行注册,这样在测试类中就不用再注册过滤器了(具体示例见扩展)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/1 13:50
*/
public class Main {
public static void main(String[] args) {
Message message = new Message();
message.setMsg("大家好:),<script>,我是程序员五条,大家都是996");
// 过滤表情和HTML的链条
FilterChain filterChain = new FilterChain();
filterChain.add(new FaceFilter()).add(new HtmlFilter());
// 过滤996的链条
FilterChain filterChain1 = new FilterChain();
filterChain1.add(new SensitiveFilter());
// 两个链条合并(也可以单用)
filterChain.add(filterChain1);
// 执行链条
filterChain.doFilter(message);
System.out.println(message);
}
}
5 扩展(链式拦截)
5.1 思路
- 定义多条拦截规则
- 只要其中一条不符合,这条消息就可以视为非法消息
5.2 实例:校验SQL
5.2.1 SqlInterceptor(拦截器接口)
5.2.2 拦截接口的实现类
IllegalKeywordsInterceptor(SQL非法关键字校验,只允许查询select)
/**
* SQL非法关键字校验
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/17 15:08
*/
@Component
public class IllegalKeywordsInterceptor implements SqlInterceptor{
static List<String> illegalKeywordsList = new ArrayList<>();
static {
illegalKeywordsList.add("update ");
illegalKeywordsList.add("drop ");
illegalKeywordsList.add("alter ");
illegalKeywordsList.add("delete ");
illegalKeywordsList.add("insert ");
illegalKeywordsList.add("create ");
illegalKeywordsList.add("grant ");
illegalKeywordsList.add("perpare ");
illegalKeywordsList.add("execute ");
illegalKeywordsList.add("deallocate ");
illegalKeywordsList.add("truncate ");
}
@Override
public void doInterceptor(String sql) {
// SQL全部转小写
String lowerSql = sql.toLowerCase();
for (String illegalKeywords : illegalKeywordsList) {
if (lowerSql.contains(illegalKeywords)){
throw new SqlCheckException("SQL中包含非法关键字:" + illegalKeywords);
}
}
}
}
SqlLengthInterceptor(SQL长度校验)
/**
* SQL长度校验
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/20 11:20
*/
public class SqlLengthInterceptor implements SqlInterceptor{
@Override
public void doInterceptor(String sql) throws SqlCheckException {
if (sql.length() < 20) {
throw new SqlCheckException("SQL长度至少需要大于等于20");
}
}
}
5.2.3 SqlCheckInterceptorChain(拦截链)
/**
* SQL校验链
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/17 15:09
*/
public class SqlCheckInterceptorChain implements SqlInterceptor{
List<SqlInterceptor> interceptors = new ArrayList<>();
private SqlCheckInterceptorChain add(SqlInterceptor sqlInterceptor){
interceptors.add(sqlInterceptor);
return this;
}
@Override
public void doInterceptor(String sql) {
add(new IllegalKeywordsInterceptor());
add(new SqlLengthInterceptor());
for (SqlInterceptor interceptor : interceptors) {
interceptor.doInterceptor(sql);
}
}
}
5.2.4 测试类
这里我已经提前将多个拦截规则提前注册到拦截链中了(见拦截链代码的doInterceptor()),所以在调用的时候只传入消息即可
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/17 15:15
*/
public class Main {
public static void main(String[] args) {
new SqlCheckInterceptorChain().doInterceptor("update public.user set username = '程序员五条' where id = 1");
}
}
6 思维导图
7 示例源码地址
https://github.com/ChenJiahao0205/design-pattern/tree/master
最后
我是通过马士兵老师的视频和菜鸟教程学习的,部分内容可能会有雷同
想阅读更多设计模式相关文章,欢迎到我的专栏【设计模式学习笔记】、【设计模式】中去查看
在23篇设计模式文章发布完成之后,我会公开完整的思维导图,点关注,不迷路
感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条!
|