SSM
参考
SSM 框架讲解:http://www.notedeep.com/note/6644/page/12419
框架搭建:https://www.cnblogs.com/hcbin/p/5397977.html
https://zhuanlan.zhihu.com/p/158613585
过滤器
概述
基于函数回调
,依赖于 servlet 容器
- 过滤器类
实现 Filter 接口
,需要在web.xml
中配置过滤器 - 在实现上,
基于函数回调
- 场景:业务无关的、宽泛的:例如字符编码
(CharacterEncodingFilter)
、过滤低俗文字
、危险字符
- 在
url-pattern
中配置了/*
之后,可以对所有要访问的资源进行拦截 Filter
的执行顺序在Interceptor
之前- 过滤作用:
拦截——数据分析——数据处理——放行/不放行
重点在过滤
示例
字符集过滤器
web.xml 配置
1 | <!-- 配置字符集过滤器 --> |
拦截器
概述
依赖于 web 框架
,在 SpringMVC 中就是依赖于 SpringMVC 框架- 拦截器类继承
HandlerInterceptorAdapter
类,需要在spring-mvc.xml
中配置拦截器 - 在实现上,
基于 Java 的反射机制
, 属于面向切面编程(AOP)的一种运用 - 只能对 controller 请求进行拦截
- 如果
修改 request 信息,不会传递给后面
- 场景:更细粒度的操作
- 拦截作用:
拦截——数据分析——放行/不放行
重点在拦截
自定义拦截器
拦截器类
MyInterceptor.java
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
32import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class MyInterceptor extends HandlerInterceptorAdapter {
// 在请求处理的方法之前执行
// 如果返回 true 执行下一个拦截器
// 如果返回 false 就不执行下一个拦截器
public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println ("------------ 处理前 ------------");
//放行
return true;
}
// 在请求处理方法执行之后执行
public void postHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println ("------------ 处理后 ------------");
}
// 在 dispatcherServlet 处理后执行,做清理工作.
public void afterCompletion (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println ("------------ 清理 ------------");
}
}spring-mvc.xml
1
2
3
4
5
6
7
8<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*.jspx"/>
<mvc:mapping path="/*.do"/>
<!--bean 配置的就是拦截器 -->
<bean class="com.bjtcrj.gms.common.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
自定义过滤器
示例一:新增/修改请求参数「非 form-data
」
ParameterFilter.java
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
32import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class ParameterFilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse reponse, FilterChain filterChain)
throws IOException, ServletException {
// TODO Auto-generated method stub
Map<String, String[]> newParameter = new HashMap<String, String[]>(request.getParameterMap());
newParameter.put("test", new String[]{"hello, world"});
filterChain.doFilter(new ParameterRequestWrapper(request, newParameter), reponse);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}ParameterRequestWrapper.java
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
86class ParameterRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> params;
public ParameterRequestWrapper(HttpServletRequest request, Map<String, String[]> newParams) {
super(request);
this.params = newParams;
renewParameterMap(request);
}
public String getParameter(String name) {
String result = "";
Object v = params.get(name);
if (v == null) {
result = null;
} else if (v instanceof String[]) {
String[] strArr = (String[]) v;
if (strArr.length > 0) {
result = strArr[0];
} else {
result = null;
}
} else if (v instanceof String) {
result = (String) v;
} else {
result = v.toString();
}
return result;
}
public Map<String, String[]> getParameterMap() {
return params;
}
public Enumeration<String> getParameterNames() {
return new Vector<String>(params.keySet()).elements();
}
public String[] getParameterValues(String name) {
String[] result = null;
Object v = params.get(name);
if (v == null) {
result = null;
} else if (v instanceof String[]) {
result = (String[]) v;
} else if (v instanceof String) {
result = new String[] { (String) v };
} else {
result = new String[] { v.toString() };
}
return result;
}
private void renewParameterMap(HttpServletRequest req) {
String queryString = req.getQueryString();
if (queryString != null && queryString.trim().length() > 0) {
String[] params = queryString.split("&");
for (int i = 0; i < params.length; i++) {
int splitIndex = params[i].indexOf("=");
if (splitIndex == -1) {
continue;
}
String key = params[i].substring(0, splitIndex);
if (!this.params.containsKey(key)) {
if (splitIndex < params[i].length()) {
String value = params[i].substring(splitIndex + 1);
this.params.put(key, new String[] { value });
}
}
}
}
}
}web.xml 中配置过滤器
1
2
3
4
5
6
7
8
9<filter>
<filter-name>ParameterFilter</filter-name>
<filter-class>com.bjtcrj.common.filter.ParameterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ParameterFilter</filter-name>
<url-pattern>/*.jspx</url-pattern>
<url-pattern>/*.do</url-pattern>
</filter-mapping>
示例二:防止 XSS 攻击,过滤特殊字符「非 form-data
」
XSSFilter.java
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
31import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class XSSFilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
// TODO Auto-generated method stub
arg2.doFilter(new XSSRequestWrapper((HttpServletRequest) arg0), arg1);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}XSSRequestWrapper.java
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
92import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XSSRequestWrapper extends HttpServletRequestWrapper {
public XSSRequestWrapper(HttpServletRequest request) {
super(request);
}
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = stripXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
return stripXSS(value);
}
public String getHeader(String name) {
String value = super.getHeader(name);
//return stripXSS(value);
return value;
}
public String getQueryString() {
String value = super.getQueryString();
if (value != null) {
value = stripXSS(value);
}
return value;
}
private String stripXSS(String value) {
if (value != null) {
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a
// expression
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<script(.*?)>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...) expressions
scriptPattern = Pattern.compile("expression\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid οnlοad= expressions
scriptPattern = Pattern.compile("onload(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
String regEx = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
value = compile(regEx).matcher(value).replaceAll("").trim();
}
return value;
}
}web.xml 配置过滤器
1
2
3
4
5
6
7
8
9<filter>
<filter-name>XSSFilter</filter-name>
<filter-class>com.bjtcrj.common.filter.XSSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XSSFilter</filter-name>
<url-pattern>/*.jspx</url-pattern>
<url-pattern>/*.do</url-pattern>
</filter-mapping>
示例三:过滤 form-data 表单域中特殊字符
新建
CustomMultipartResolver
类,实现CommonsMultipartResolver
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
102public class CustomMultipartResolver extends CommonsMultipartResolver {
private HttpServletRequest request;
protected FileUpload newFileUpload(FileItemFactory fileItemFactory) {
ServletFileUpload upload = new ServletFileUpload(fileItemFactory);
upload.setSizeMax(-1);
if (request != null) {
HttpSession session = request.getSession();
FileUploadProgressListener progressListener = new FileUploadProgressListener(session);
upload.setProgressListener(progressListener);
}
return upload;
}
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
// 获取到request,要用到session
this.request = request;
return super.resolveMultipart(request);
}
public MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
HttpSession session = request.getSession();
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
FileUploadProgressListener progressListener = new FileUploadProgressListener(session);
fileUpload.setProgressListener(progressListener);
try {
List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
return parseFileItems2(fileItems, encoding);
} catch (FileUploadBase.SizeLimitExceededException ex) {
throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
} catch (FileUploadException ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
}
}
private MultipartParsingResult parseFileItems2(List<FileItem> fileItems, String encoding) {
MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
Map<String, String[]> multipartParameters = new HashMap<String, String[]>();
Map<String, String> multipartParameterContentTypes = new HashMap<String, String>();
// Extract multipart files and multipart parameters.
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {
String value;
String partEncoding = determineEncoding(fileItem.getContentType(), encoding);
if (partEncoding != null) {
try {
value = fileItem.getString(partEncoding);
}
catch (UnsupportedEncodingException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not decode multipart item '" + fileItem.getFieldName() +
"' with encoding '" + partEncoding + "': using platform default");
}
value = fileItem.getString();
}
}
else {
value = fileItem.getString();
}
//处理特殊字符
value = StringEx.filterSpecialCharacters(value);
String[] curParam = multipartParameters.get(fileItem.getFieldName());
if (curParam == null) {
// simple form field
multipartParameters.put(fileItem.getFieldName(), new String[] {value});
}
else {
// array of simple form fields
String[] newParam = StringUtils.addStringToArray(curParam, value);
multipartParameters.put(fileItem.getFieldName(), newParam);
}
multipartParameterContentTypes.put(fileItem.getFieldName(), fileItem.getContentType());
}
else {
// multipart file field
CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
multipartFiles.add(file.getName(), file);
if (logger.isDebugEnabled()) {
logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize() +
" bytes with original filename [" + file.getOriginalFilename() + "], stored " +
file.getStorageDescription());
}
}
}
return new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes);
}
private String determineEncoding(String contentTypeHeader, String defaultEncoding) {
if (!StringUtils.hasText(contentTypeHeader)) {
return defaultEncoding;
}
MediaType contentType = MediaType.parseMediaType(contentTypeHeader);
Charset charset = contentType.getCharSet();
return (charset != null ? charset.name() : defaultEncoding);
}
}spring-mvc.xml 配置
1
2
3
4
5
6
7
8
9
10
11<bean id="multipartResolver" class="com.bjtcrj.scm.common.controller.CustomMultipartResolver">
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
<property name="maxUploadSize">
<value>32505856</value><!-- 上传文件大小限制为31M,31*1024*1024 -->
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
请求参数接收
GET请求
请求数据示例
1
GET http://localhost:8000/houseaddress/page?page=1&rows=10&fulltext=%E5%95%86%E5%9C%BA
接收
1
2
3
4
public Map<String, Object> page(int page, int size, Houseaddress houseaddress) {
}
POST 请求
根据 Content-Type
区分
application/x-www-form-urlencoded
请求数据示例
1
2
3
4POST http://localhost:8080/ssm_maven_demo/account/add
Content-Type: application/x-www-form-urlencoded
name=张三&money=1000接收
1
2
3
4
public Account add(Account account) {
return this.accountService.insert(account);
}
application/json
请求数据示例
1
2
3
4
5
6
7
8
9
10
11
12POST http://localhost:8080/ssm_maven_demo/account/add
Content-Type: application/json
{
"name": "hello",
"money": 190,
"stu":
{
"name": "ddddd",
"age": 222
}
}controller 接口处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public Account add( { Account account)
return this.accountService.insert(account);
}
public class Account implements Serializable {
private static final long serialVersionUID = 618038893780400829L;
private Integer id;
private String name;
private Double money;
private Stu stu;
}
class Stu {
String name;
Integer age;
}
multipart/form-data
请求数据示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17POST http://localhost:8080/ssm_maven_demo/account/addFile
Content-Type: multipart/form-data; boundary=WebAppBoundary
--WebAppBoundary
Content-Disposition: form-data; name="name"
Content-Type: text/plain
zhagnsan
--WebAppBoundary
Content-Disposition: form-data; name="money"
Content-Type: text/plain
2999
--WebAppBoundary
Content-Disposition: form-data; name="file"; filename="README.md"
< /Users/mac126/study/Study_Projects/ssm_maven_demo/README.md
--WebAppBoundary--接收
1
2
3
4
5
6
7
8
9
10
public void addFile( { MultipartFile file, Account account)
System.out.println(file.getOriginalFilename());
System.out.println(account.toString());
}
public void addHouseHolderBasic_App(HttpServletRequest request, HttpServletResponse response, PersonDto personDto) {
// personDto 对象接收表单数据;文本对象通过 request 强制转换为 MultipartHttpServletRequest 类型,再从中获取
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 王文哲的博客!