Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
2d4ae59f
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2d4ae59f
编写于
7月 29, 2009
作者:
A
Arjen Poutsma
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SPR-5961
上级
9eb962d9
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
347 addition
and
52 deletion
+347
-52
org.springframework.web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java
...ingframework/web/filter/AbstractRequestLoggingFilter.java
+158
-52
org.springframework.web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java
...springframework/web/filter/RequestLoggingFilterTests.java
+189
-0
未找到文件。
org.springframework.web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java
浏览文件 @
2d4ae59f
...
...
@@ -16,38 +16,44 @@
package
org.springframework.web.filter
;
import
java.io.BufferedReader
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.UnsupportedEncodingException
;
import
javax.servlet.FilterChain
;
import
javax.servlet.ServletException
;
import
javax.servlet.ServletInputStream
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequestWrapper
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpSession
;
import
org.springframework.util.Assert
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.util.WebUtils
;
/**
* Base class for <code>Filter</code>s that perform logging operations before and after a
* request is processed.
* Base class for <code>Filter</code>s that perform logging operations before and after a request is processed.
*
* <p>Subclasses should override the <code>beforeRequest(HttpServletRequest, String)</code>
* and <code>afterRequest(HttpServletRequest, String)</code> methods to perform the actual
* logging around the request.
* <p>Subclasses should override the <code>beforeRequest(HttpServletRequest, String)</code> and
* <code>afterRequest(HttpServletRequest, String)</code> methods to perform the actual logging around the request.
*
* <p>Subclasses are passed the message to write to the log in the <code>beforeRequest</code>
* and <code>afterRequest</code> methods. By default, only the URI of the request is logged.
* However, setting the <code>includeQueryString</code> property to <code>true</code> will
* cause the query string of the request to be included also.
* <p>Subclasses are passed the message to write to the log in the <code>beforeRequest</code> and
* <code>afterRequest</code> methods. By default, only the URI of the request is logged. However, setting the
* <code>includeQueryString</code> property to <code>true</code> will cause the query string of the request to be
* included also. The payload (body) of the request can be logged via the <code>includePayload</code> flag. Note that
* this will only log that which is read, which might not be the entire payload.
*
* <p>Prefixes and suffixes for the before and after messages can be configured
*
using the <code>beforeMessagePrefix</code>, <code>afterMessagePrefix</code>,
* <code>
beforeMessageSuffix</code> and <code>
afterMessageSuffix</code> properties,
* <p>Prefixes and suffixes for the before and after messages can be configured
using the
*
<code>beforeMessagePrefix</code>, <code>afterMessagePrefix</code>, <code>beforeMessageSuffix</code> and
* <code>afterMessageSuffix</code> properties,
*
* @author Rob Harrop
* @author Juergen Hoeller
* @since 1.2.5
* @see #beforeRequest
* @see #afterRequest
* @since 1.2.5
*/
public
abstract
class
AbstractRequestLoggingFilter
extends
OncePerRequestFilter
{
...
...
@@ -59,11 +65,16 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
public
static
final
String
DEFAULT_AFTER_MESSAGE_SUFFIX
=
"]"
;
private
static
final
int
DEFAULT_MAX_PAYLOAD_LENGTH
=
50
;
private
boolean
includeQueryString
=
false
;
private
boolean
includeClientInfo
=
false
;
private
boolean
includePayload
=
false
;
private
int
maxPayloadLength
=
DEFAULT_MAX_PAYLOAD_LENGTH
;
private
String
beforeMessagePrefix
=
DEFAULT_BEFORE_MESSAGE_PREFIX
;
private
String
beforeMessageSuffix
=
DEFAULT_BEFORE_MESSAGE_SUFFIX
;
...
...
@@ -72,11 +83,10 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
private
String
afterMessageSuffix
=
DEFAULT_AFTER_MESSAGE_SUFFIX
;
/**
* Set whether or not the query string should be included in the log message.
* <
p>Should be configured using an <code><init-param></code> for parameter
*
name "includeQueryString" in the filter definition in
<code>web.xml</code>.
* Set whether or not the query string should be included in the log message.
<p>Should be configured using an
* <
code><init-param></code> for parameter name "includeQueryString" in the filter definition in
* <code>web.xml</code>.
*/
public
void
setIncludeQueryString
(
boolean
includeQueryString
)
{
this
.
includeQueryString
=
includeQueryString
;
...
...
@@ -90,68 +100,94 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
}
/**
* Set whether or not the client address and session id should be included
* in the log message.
* <p>Should be configured using an <code><init-param></code> for parameter
* name "includeClientInfo" in the filter definition in <code>web.xml</code>.
* Set whether or not the client address and session id should be included in the log message. <p>Should be configured
* using an <code><init-param></code> for parameter name "includeClientInfo" in the filter definition in
* <code>web.xml</code>.
*/
public
void
setIncludeClientInfo
(
boolean
includeClientInfo
)
{
this
.
includeClientInfo
=
includeClientInfo
;
}
/**
* Return whether or not the client address and session id should be included
* in the log message.
* Return whether or not the client address and session id should be included in the log message.
*/
protected
boolean
isIncludeClientInfo
()
{
return
this
.
includeClientInfo
;
}
/**
* Set the value that should be prepended to the log message written
* <i>before</i> a request is processed.
* Set whether or not the request payload (body) should be included in the log message. <p>Should be configured using
* an <code><init-param></code> for parameter name "includePayload" in the filter definition in
* <code>web.xml</code>.
*/
public
void
setIncludePayload
(
boolean
includePayload
)
{
this
.
includePayload
=
includePayload
;
}
/**
* Return whether or not the request payload (body) should be included in the log message.
*/
protected
boolean
isIncludePayload
()
{
return
includePayload
;
}
/**
* Sets the maximum length of the payload body to be included in the log message. Default is 50 characters.
*/
public
void
setMaxPayloadLength
(
int
maxPayloadLength
)
{
Assert
.
isTrue
(
maxPayloadLength
>=
0
,
"'maxPayloadLength' should be larger than or equal to 0"
);
this
.
maxPayloadLength
=
maxPayloadLength
;
}
/**
* Return the maximum length of the payload body to be included in the log message.
*/
protected
int
getMaxPayloadLength
()
{
return
maxPayloadLength
;
}
/**
* Set the value that should be prepended to the log message written <i>before</i> a request is processed.
*/
public
void
setBeforeMessagePrefix
(
String
beforeMessagePrefix
)
{
this
.
beforeMessagePrefix
=
beforeMessagePrefix
;
}
/**
* Set the value that should be apppended to the log message written
* <i>before</i> a request is processed.
* Set the value that should be apppended to the log message written <i>before</i> a request is processed.
*/
public
void
setBeforeMessageSuffix
(
String
beforeMessageSuffix
)
{
this
.
beforeMessageSuffix
=
beforeMessageSuffix
;
}
/**
* Set the value that should be prepended to the log message written
* <i>after</i> a request is processed.
* Set the value that should be prepended to the log message written <i>after</i> a request is processed.
*/
public
void
setAfterMessagePrefix
(
String
afterMessagePrefix
)
{
this
.
afterMessagePrefix
=
afterMessagePrefix
;
}
/**
* Set the value that should be appended to the log message written
* <i>after</i> a request is processed.
* Set the value that should be appended to the log message written <i>after</i> a request is processed.
*/
public
void
setAfterMessageSuffix
(
String
afterMessageSuffix
)
{
this
.
afterMessageSuffix
=
afterMessageSuffix
;
}
/**
* Forwards the request to the next filter in the chain and delegates
*
down to the subclasses to perform the actual request logging both
*
before and after the request is processed.
* Forwards the request to the next filter in the chain and delegates
down to the subclasses to perform the actual
*
request logging both before and after the request is processed.
*
* @see #beforeRequest
* @see #afterRequest
*/
@Override
protected
void
doFilterInternal
(
HttpServletRequest
request
,
HttpServletResponse
response
,
FilterChain
filterChain
)
protected
void
doFilterInternal
(
HttpServletRequest
request
,
HttpServletResponse
response
,
FilterChain
filterChain
)
throws
ServletException
,
IOException
{
if
(
isIncludePayload
())
{
request
=
new
RequestCachingRequestWrapper
(
request
);
}
beforeRequest
(
request
,
getBeforeMessage
(
request
));
try
{
filterChain
.
doFilter
(
request
,
response
);
...
...
@@ -161,9 +197,9 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
}
}
/**
* Get the message to write to the log before the request.
*
* @see #createMessage
*/
private
String
getBeforeMessage
(
HttpServletRequest
request
)
{
...
...
@@ -172,6 +208,7 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
/**
* Get the message to write to the log after the request.
*
* @see #createMessage
*/
private
String
getAfterMessage
(
HttpServletRequest
request
)
{
...
...
@@ -179,13 +216,10 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
}
/**
* Create a log message for the given request, prefix and suffix.
* <p>If <code>includeQueryString</code> is <code>true</code> then
* the inner part of the log message will take the form
* <code>request_uri?query_string</code> otherwise the message will
* simply be of the form <code>request_uri</code>.
* <p>The final message is composed of the inner part as described
* and the supplied prefix and suffix.
* Create a log message for the given request, prefix and suffix. <p>If <code>includeQueryString</code> is
* <code>true</code> then the inner part of the log message will take the form <code>request_uri?query_string</code>
* otherwise the message will simply be of the form <code>request_uri</code>. <p>The final message is composed of the
* inner part as described and the supplied prefix and suffix.
*/
protected
String
createMessage
(
HttpServletRequest
request
,
String
prefix
,
String
suffix
)
{
StringBuilder
msg
=
new
StringBuilder
();
...
...
@@ -208,25 +242,97 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
msg
.
append
(
";user="
).
append
(
user
);
}
}
if
(
isIncludePayload
()
&&
request
instanceof
RequestCachingRequestWrapper
)
{
RequestCachingRequestWrapper
wrapper
=
(
RequestCachingRequestWrapper
)
request
;
byte
[]
buf
=
wrapper
.
toByteArray
();
if
(
buf
.
length
>
0
)
{
int
length
=
Math
.
min
(
buf
.
length
,
getMaxPayloadLength
());
String
payload
;
try
{
payload
=
new
String
(
buf
,
0
,
length
,
wrapper
.
getCharacterEncoding
());
}
catch
(
UnsupportedEncodingException
e
)
{
payload
=
"[unknown]"
;
}
msg
.
append
(
";payload="
).
append
(
payload
);
}
}
msg
.
append
(
suffix
);
return
msg
.
toString
();
}
/**
* Concrete subclasses should implement this method to write a log message
*
<i>before</i> the request is processed.
* Concrete subclasses should implement this method to write a log message
<i>before</i> the request is processed.
*
* @param request current HTTP request
* @param message the message to log
*/
protected
abstract
void
beforeRequest
(
HttpServletRequest
request
,
String
message
);
/**
* Concrete subclasses should implement this method to write a log message
*
<i>after</i> the request is processed.
* Concrete subclasses should implement this method to write a log message
<i>after</i> the request is processed.
*
* @param request current HTTP request
* @param message the message to log
*/
protected
abstract
void
afterRequest
(
HttpServletRequest
request
,
String
message
);
private
static
class
RequestCachingRequestWrapper
extends
HttpServletRequestWrapper
{
private
final
ByteArrayOutputStream
bos
=
new
ByteArrayOutputStream
();
private
final
ServletInputStream
inputStream
;
private
BufferedReader
reader
;
private
RequestCachingRequestWrapper
(
HttpServletRequest
request
)
throws
IOException
{
super
(
request
);
this
.
inputStream
=
new
RequestCachingInputStream
(
request
.
getInputStream
());
}
@Override
public
ServletInputStream
getInputStream
()
throws
IOException
{
return
inputStream
;
}
@Override
public
String
getCharacterEncoding
()
{
return
super
.
getCharacterEncoding
()
!=
null
?
super
.
getCharacterEncoding
()
:
WebUtils
.
DEFAULT_CHARACTER_ENCODING
;
}
@Override
public
BufferedReader
getReader
()
throws
IOException
{
if
(
this
.
reader
==
null
)
{
this
.
reader
=
new
BufferedReader
(
new
InputStreamReader
(
inputStream
,
getCharacterEncoding
()));
}
return
this
.
reader
;
}
private
byte
[]
toByteArray
()
{
return
this
.
bos
.
toByteArray
();
}
private
class
RequestCachingInputStream
extends
ServletInputStream
{
private
final
ServletInputStream
is
;
private
RequestCachingInputStream
(
ServletInputStream
is
)
{
this
.
is
=
is
;
}
@Override
public
int
read
()
throws
IOException
{
int
ch
=
is
.
read
();
if
(
ch
!=
-
1
)
{
bos
.
write
(
ch
);
}
return
ch
;
}
}
}
}
org.springframework.web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java
0 → 100644
浏览文件 @
2d4ae59f
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.filter
;
import
java.io.IOException
;
import
javax.servlet.FilterChain
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
org.junit.Test
;
import
org.junit.Before
;
import
static
org
.
junit
.
Assert
.*;
import
org.springframework.mock.web.MockHttpServletRequest
;
import
org.springframework.mock.web.MockHttpServletResponse
;
import
org.springframework.util.FileCopyUtils
;
/**
* Test for {@link AbstractRequestLoggingFilter} and sub classes.
*
* @author Arjen Poutsma
*/
public
class
RequestLoggingFilterTests
{
private
MyRequestLoggingFilter
filter
;
@Before
public
void
createFilter
()
throws
Exception
{
filter
=
new
MyRequestLoggingFilter
();
}
@Test
public
void
uri
()
throws
Exception
{
final
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
request
.
setQueryString
(
"booking=42"
);
FilterChain
filterChain
=
new
NoopFilterChain
();
filter
.
doFilter
(
request
,
response
,
filterChain
);
assertNotNull
(
filter
.
beforeRequestMessage
);
assertTrue
(
filter
.
beforeRequestMessage
.
indexOf
(
"uri=/hotel"
)
!=
-
1
);
assertFalse
(
filter
.
beforeRequestMessage
.
indexOf
(
"booking=42"
)
!=
-
1
);
assertNotNull
(
filter
.
afterRequestMessage
);
assertTrue
(
filter
.
afterRequestMessage
.
indexOf
(
"uri=/hotel"
)
!=
-
1
);
assertFalse
(
filter
.
afterRequestMessage
.
indexOf
(
"booking=42"
)
!=
-
1
);
}
@Test
public
void
queryString
()
throws
Exception
{
filter
.
setIncludeQueryString
(
true
);
final
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
request
.
setQueryString
(
"booking=42"
);
FilterChain
filterChain
=
new
NoopFilterChain
();
filter
.
doFilter
(
request
,
response
,
filterChain
);
assertNotNull
(
filter
.
beforeRequestMessage
);
assertTrue
(
filter
.
beforeRequestMessage
.
indexOf
(
"uri=/hotels?booking=42"
)
!=
-
1
);
assertNotNull
(
filter
.
afterRequestMessage
);
assertTrue
(
filter
.
afterRequestMessage
.
indexOf
(
"uri=/hotels?booking=42"
)
!=
-
1
);
}
@Test
public
void
payloadInputStream
()
throws
Exception
{
filter
.
setIncludePayload
(
true
);
final
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
final
byte
[]
requestBody
=
"Hello World"
.
getBytes
(
"UTF-8"
);
request
.
setContent
(
requestBody
);
FilterChain
filterChain
=
new
FilterChain
()
{
public
void
doFilter
(
ServletRequest
filterRequest
,
ServletResponse
filterResponse
)
throws
IOException
,
ServletException
{
((
HttpServletResponse
)
filterResponse
).
setStatus
(
HttpServletResponse
.
SC_OK
);
byte
[]
buf
=
FileCopyUtils
.
copyToByteArray
(
filterRequest
.
getInputStream
());
assertArrayEquals
(
requestBody
,
buf
);
}
};
filter
.
doFilter
(
request
,
response
,
filterChain
);
assertNotNull
(
filter
.
afterRequestMessage
);
assertTrue
(
filter
.
afterRequestMessage
.
indexOf
(
"Hello World"
)
!=
-
1
);
}
@Test
public
void
payloadReader
()
throws
Exception
{
filter
.
setIncludePayload
(
true
);
final
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
final
String
requestBody
=
"Hello World"
;
request
.
setContent
(
requestBody
.
getBytes
(
"UTF-8"
));
FilterChain
filterChain
=
new
FilterChain
()
{
public
void
doFilter
(
ServletRequest
filterRequest
,
ServletResponse
filterResponse
)
throws
IOException
,
ServletException
{
((
HttpServletResponse
)
filterResponse
).
setStatus
(
HttpServletResponse
.
SC_OK
);
String
buf
=
FileCopyUtils
.
copyToString
(
filterRequest
.
getReader
());
assertEquals
(
requestBody
,
buf
);
}
};
filter
.
doFilter
(
request
,
response
,
filterChain
);
assertNotNull
(
filter
.
afterRequestMessage
);
assertTrue
(
filter
.
afterRequestMessage
.
indexOf
(
requestBody
)
!=
-
1
);
}
@Test
public
void
payloadMaxLength
()
throws
Exception
{
filter
.
setIncludePayload
(
true
);
filter
.
setMaxPayloadLength
(
3
);
final
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
final
byte
[]
requestBody
=
"Hello World"
.
getBytes
(
"UTF-8"
);
request
.
setContent
(
requestBody
);
FilterChain
filterChain
=
new
FilterChain
()
{
public
void
doFilter
(
ServletRequest
filterRequest
,
ServletResponse
filterResponse
)
throws
IOException
,
ServletException
{
((
HttpServletResponse
)
filterResponse
).
setStatus
(
HttpServletResponse
.
SC_OK
);
byte
[]
buf
=
FileCopyUtils
.
copyToByteArray
(
filterRequest
.
getInputStream
());
assertArrayEquals
(
requestBody
,
buf
);
}
};
filter
.
doFilter
(
request
,
response
,
filterChain
);
assertNotNull
(
filter
.
afterRequestMessage
);
assertTrue
(
filter
.
afterRequestMessage
.
indexOf
(
"Hel"
)
!=
-
1
);
assertFalse
(
filter
.
afterRequestMessage
.
indexOf
(
"Hello World"
)
!=
-
1
);
}
private
static
class
MyRequestLoggingFilter
extends
AbstractRequestLoggingFilter
{
private
String
beforeRequestMessage
;
private
String
afterRequestMessage
;
@Override
protected
void
beforeRequest
(
HttpServletRequest
request
,
String
message
)
{
this
.
beforeRequestMessage
=
message
;
}
@Override
protected
void
afterRequest
(
HttpServletRequest
request
,
String
message
)
{
this
.
afterRequestMessage
=
message
;
}
}
private
static
class
NoopFilterChain
implements
FilterChain
{
public
void
doFilter
(
ServletRequest
request
,
ServletResponse
response
)
throws
IOException
,
ServletException
{
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录