java设计模式 改进一 改进二 改进三 改进四

一个BBS论坛,在发布帖子之前需要对帖子的内容进行审核过滤之后才能进行发布,要求

  1. 过滤脚本
  2. 过滤敏感词汇

尝试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.tomkk.dp;


class {
private String requestString;

public String getRequestString() {
return requestString;
}

public void setRequestString(String requestString) {
this.requestString = requestString;
}
}

class MessageProcess{
public static String process(Request request) {
String str = request.getRequestString();

// 替换脚本
str = str.replaceAll("<", "[")
.replaceAll(">", "]");

// 删除敏感词汇
str = str.replaceAll("敏感词汇", "****");

return str;
}
}

public class Main {

public static void main(String[] args) {
String requestStr = "<script>alert('敏感词汇')</script>";
Request request = new Request();
request.setRequestString(requestStr);

MessageProcess mp = new MessageProcess();
String result = mp.process(request);

System.out.println(result);
}
}

存在的问题

当要添加新的过滤规则的时候比较僵硬,需要加在process方法里面,这将导致最终这个方法代码量会很多。

改进一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.tomkk.dp;

import java.util.ArrayList;
import java.util.List;


class {
private String requestString;

public String getRequestString() {
return requestString;
}

public void setRequestString(String requestString) {
this.requestString = requestString;
}
}

interface Filter{
String doFilter(Request request);
}

//替换脚本的过滤器
class HTMLFilter implements Filter {


public String doFilter(Request request) {
String str = request.getRequestString();

str = str.replaceAll("<", "[")
.replaceAll(">", "]");

return str;
}
}

//替换敏感词汇的过滤器
class SensitiveFilter implements Filter{


public String doFilter(Request request) {
String str = request.getRequestString();

str = str.replaceAll("敏感词汇", "****");

return str;
}

}

//过滤链
class FilterChain{

private List<Filter> filters = new ArrayList<>();

public FilterChain addFilter(Filter filter) {
filters.add(filter);

// 为了链式写法
return this;
}

public String doFilter(Request request) {
String str = request.getRequestString();

for (Filter filter : filters) {
str = filter.doFilter(request);
request.setRequestString(str);
}

return str;
}
}

class MessageProcess{
private FilterChain chain = new FilterChain();

public FilterChain getChain() {
return chain;
}

public void setChain(FilterChain chain) {
this.chain = chain;
}

public String process(Request request) {

return chain.doFilter(request);

}
}

public class Main {

public static void main(String[] args) {
String requestStr = "<script>alert('敏感词汇')</script>";
Request request = new Request();
request.setRequestString(requestStr);

MessageProcess mp = new MessageProcess();
FilterChain chain = new FilterChain();

chain.addFilter(new HTMLFilter())
.addFilter(new SensitiveFilter());

mp.setChain(chain);

String result = mp.process(request);

System.out.println(result);
}
}

解决的问题

现在如果有新的检验规则的话,只需要创建一个新的Filter的实现类,在doFilter方法里面加入逻辑,然后添加到“链条”里即可。提高了一定的可扩展性。

还存在的问题

预测未来的需求

需要在一个已存在的过滤链中间插入另一条过滤链

以目前的设计,必须事先知道新链条的所有过滤器然后在适合的地方一个个add进去,可以想象如果这个新链条很长,那么工作量将会很大。

改进二

让FilterChain也实现Filter接口,那么FilterChain就能添加“链条”到容器中了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.tomkk.dp;

import java.util.ArrayList;
import java.util.List;


class {
private String requestString;

public String getRequestString() {
return requestString;
}

public void setRequestString(String requestString) {
this.requestString = requestString;
}
}

interface Filter{
String doFilter(Request request);
}

//替换脚本的过滤器
class HTMLFilter implements Filter {


public String doFilter(Request request) {
String str = request.getRequestString();

str = str.replaceAll("<", "[")
.replaceAll(">", "]");

return str;
}
}

//替换敏感词汇的过滤器
class SensitiveFilter implements Filter{


public String doFilter(Request request) {
String str = request.getRequestString();

str = str.replaceAll("敏感词汇", "****");

return str;
}

}

//过滤链
class FilterChain implements Filter{

private List<Filter> filters = new ArrayList<>();

public FilterChain addFilter(Filter filter) {
filters.add(filter);

// 为了链式写法
return this;
}

public String doFilter(Request request) {
String str = request.getRequestString();

for (Filter filter : filters) {
str = filter.doFilter(request);
request.setRequestString(str);
}

return str;
}
}

class MessageProcess{
private FilterChain chain = new FilterChain();

public FilterChain getChain() {
return chain;
}

public void setChain(FilterChain chain) {
this.chain = chain;
}

public String process(Request request) {

return chain.doFilter(request);

}
}

public class Main {

public static void main(String[] args) {
String requestStr = "<script>alert('敏感词汇')</script>";
Request request = new Request();
request.setRequestString(requestStr);

MessageProcess mp = new MessageProcess();
FilterChain chain = new FilterChain();


FilterChain newChain = new FilterChain();
newChain.addFilter(new SensitiveFilter());

chain.addFilter(new HTMLFilter())
// 中间插入新的过滤链
.addFilter(newChain);

mp.setChain(chain);

String result = mp.process(request);

System.out.println(result);
}
}

解决的问题

现在这个版本下,能够比较自由的组合过滤链,而只改动少量代码。

还存在的问题

预想未来的新需求

需要这些过滤器也能够应用于由服务器回复的字符串上。

改进三

因为逻辑上应该是请求走完所有的的过滤器之后,再去进行业务逻辑的处理,然后再在Response对象中存入内容,之后再对Response对象内的内容进行过滤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.tomkk.dp;

import java.util.ArrayList;
import java.util.List;


class {
private String requestString;

public String getRequestString() {
return requestString;
}

public void setRequestString(String requestString) {
this.requestString = requestString;
}
}

class Response{
private String responseString;


public String getResponseString() {
return responseString;
}

public void setResponseString(String responseString) {
this.responseString = responseString;
}
}

//添加过滤器链对象
interface Filter{
void doFilter(Request request, Response response, FilterChain chain);
}

//替换脚本的过滤器
class HTMLFilter implements Filter {


public void doFilter(Request request, Response response, FilterChain chain) {
String requestString = request.getRequestString();

requestString = requestString.replaceAll("<", "[");
requestString = requestString.replaceAll(">", "]");
request.setRequestString(requestString);

// 进入下一环过滤
chain.doFilter(request, response, chain);

String responseString = response.getResponseString();
responseString = responseString.replaceAll("<", "[");
responseString = responseString.replaceAll(">", "]");
response.setResponseString(responseString);

}
}

//替换敏感词汇的过滤器
class SensitiveFilter implements Filter{

@Override
public void doFilter(Request request, Response response, FilterChain chain) {
String requestString = request.getRequestString();
requestString = requestString.replaceAll("敏感词汇", "****");
request.setRequestString(requestString);

// 进入下一环过滤
chain.doFilter(request, response, chain);

String responseString = response.getResponseString();
responseString = responseString.replaceAll("敏感词汇", "****");
response.setResponseString(responseString);
}

}

//过滤链
class FilterChain implements Filter{

private List<Filter> filters = new ArrayList<>();

// 标识目前执行到哪个过滤器了
private int index;

public FilterChain addFilter(Filter filter) {
filters.add(filter);

// 为了链式写法
return this;
}

public void doFilter(Request request, Response response, FilterChain chain) {
if (index == filters.size()) {
// 执行完所有的过滤器,进入业务逻辑
response.setResponseString("敏感词汇已经清除");
return;
}else{
Filter filter = filters.get(index);
index++;
filter.doFilter(request, response, chain);
}
}
}

class MessageProcess{
private FilterChain chain = new FilterChain();

public FilterChain getChain() {
return chain;
}

public void setChain(FilterChain chain) {
this.chain = chain;
}

public void process(Request request, Response response) {

chain.doFilter(request, response, chain);

}
}

public class Main {

public static void main(String[] args) {
String requestStr = "<script>alert('敏感词汇')</script>";
Request request = new Request();
Response response = new Response();

request.setRequestString(requestStr);

MessageProcess mp = new MessageProcess();
FilterChain chain = new FilterChain();


FilterChain newChain = new FilterChain();
newChain.addFilter(new SensitiveFilter());

chain.addFilter(new HTMLFilter())
// 中间插入新的过滤链
.addFilter(newChain);

mp.setChain(chain);

mp.process(request, response);

System.out.println(request.getRequestString());
System.out.println(response.getResponseString());
}
}

解决的问题

在目前的版本中,设定的过滤器能够请求阶段和响应阶段都生效。但是注意执行的顺序的变化

  • 请求阶段:过滤器1 —> 过滤器2 —> 过滤器3
  • 响应阶段:过滤器3 —> 过滤器2 —> 过滤器1

还存在的问题

预想未来的新需求

如果在过滤的过程中,某一环的检验没有通过,那么如何终止剩下的链条的执行。

改进四

采用异常来中断跳出整个链条,或者可以通过将过滤逻辑封装成doBefore和doAfter,然后通过返回值来决定是否继续调用后序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package com.tomkk.dp;

import java.util.ArrayList;
import java.util.List;


class {
private String requestString;

public String getRequestString() {
return requestString;
}

public void setRequestString(String requestString) {
this.requestString = requestString;
}
}

class Response{
private String responseString;


public String getResponseString() {
return responseString;
}

public void setResponseString(String responseString) {
this.responseString = responseString;
}
}

//添加过滤器链对象
interface Filter{
void doFilter(Request request, Response response, FilterChain chain) throws Exception;
}

//替换脚本的过滤器
class HTMLFilter implements Filter {

@Override
public void doFilter(Request request, Response response, FilterChain chain) throws Exception{
String requestString = request.getRequestString();

requestString = requestString.replaceAll("<", "[");
requestString = requestString.replaceAll(">", "]");
request.setRequestString(requestString);

// 进入下一环过滤
chain.doFilter(request, response, chain);

String responseString = response.getResponseString();
responseString = responseString.replaceAll("<", "[");
responseString = responseString.replaceAll(">", "]");
response.setResponseString(responseString);

}
}

//替换敏感词汇的过滤器
class SensitiveFilter implements Filter{

@Override
public void doFilter(Request request, Response response, FilterChain chain) throws Exception{
String requestString = request.getRequestString();
// 过滤出错
if (requestString.contains("敏感词汇")) {
throw new Exception("过滤敏感词汇错误");
}
requestString = requestString.replaceAll("敏感词汇", "****");
request.setRequestString(requestString);
// 进入下一环过滤
chain.doFilter(request, response, chain);

String responseString = response.getResponseString();
responseString = responseString.replaceAll("敏感词汇", "****");
response.setResponseString(responseString);
}

}

//过滤链
class FilterChain implements Filter{

private List<Filter> filters = new ArrayList<>();

// 标识目前执行到哪个过滤器了
private int index;

public FilterChain addFilter(Filter filter) {
filters.add(filter);

// 为了链式写法
return this;
}

public void doFilter(Request request, Response response, FilterChain chain) throws Exception {
if (index == filters.size()) {
// 执行完所有的过滤器,进入业务逻辑
response.setResponseString("敏感词汇已经清除");
return;
}else{
Filter filter = filters.get(index);
index++;
filter.doFilter(request, response, chain);
}
}
}

class MessageProcess{
private FilterChain chain = new FilterChain();

public FilterChain getChain() {
return chain;
}

public void setChain(FilterChain chain) {
this.chain = chain;
}

public void process(Request request, Response response) {

try {
chain.doFilter(request, response, chain);
} catch (Exception e) {
response.setResponseString("发生错误");
}

}
}

public class Main {

public static void main(String[] args) {
String requestStr = "<script>alert('敏感词汇')</script>";
Request request = new Request();
Response response = new Response();

request.setRequestString(requestStr);

MessageProcess mp = new MessageProcess();
FilterChain chain = new FilterChain();


FilterChain newChain = new FilterChain();
newChain.addFilter(new SensitiveFilter());

chain.addFilter(new HTMLFilter())
// 中间插入新的过滤链
.addFilter(newChain);

mp.setChain(chain);

mp.process(request, response);

System.out.println(request.getRequestString());
System.out.println(response.getResponseString());
}
}

解决的问题

比如在权限控制中,当某一环检测没有权限,后面的就不需要进行了,直接返回“没有权限”,在这里是通过抛出异常来跳出。