Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
532daf62
提交
532daf62
authored
3月 18, 2019
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
后端:增加管理员访问日志
上级
bb612cac
显示空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
761 行增加
和
2 行删除
+761
-2
MVCConfiguration.java
...coder/mall/admin/application/config/MVCConfiguration.java
+4
-2
AdminAccessLogInterceptor.java
...mall/admin/sdk/interceptor/AdminAccessLogInterceptor.java
+78
-0
AdminSecurityInterceptor.java
.../mall/admin/sdk/interceptor/AdminSecurityInterceptor.java
+7
-0
AdminAccessLogService.java
...java/cn/iocoder/mall/admin/api/AdminAccessLogService.java
+13
-0
AdminService.java
...src/main/java/cn/iocoder/mall/admin/api/AdminService.java
+3
-0
AdminAccessLogAddDTO.java
...a/cn/iocoder/mall/admin/api/dto/AdminAccessLogAddDTO.java
+133
-0
AdminAccessLogConvert.java
.../cn/iocoder/mall/admin/convert/AdminAccessLogConvert.java
+18
-0
AdminAccessLogMapper.java
.../java/cn/iocoder/mall/admin/dao/AdminAccessLogMapper.java
+11
-0
AdminAccessLogDO.java
...va/cn/iocoder/mall/admin/dataobject/AdminAccessLogDO.java
+133
-0
AdminAccessLogServiceImpl.java
...iocoder/mall/admin/service/AdminAccessLogServiceImpl.java
+57
-0
AdminAccessLogMapper.xml
...e-impl/src/main/resources/mapper/AdminAccessLogMapper.xml
+21
-0
HttpUtil.java
.../main/java/cn/iocoder/common/framework/util/HttpUtil.java
+278
-0
StringUtil.java
...ain/java/cn/iocoder/common/framework/util/StringUtil.java
+5
-0
没有找到文件。
admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/config/MVCConfiguration.java
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
application
.
config
;
import
cn.iocoder.common.framework.config.GlobalExceptionHandler
;
import
cn.iocoder.mall.admin.sdk.interceptor.AdminAccessLogInterceptor
;
import
cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Configuration
;
...
...
@@ -18,16 +19,17 @@ public class MVCConfiguration implements WebMvcConfigurer {
@Autowired
private
AdminSecurityInterceptor
adminSecurityInterceptor
;
@Autowired
private
AdminAccessLogInterceptor
adminAccessLogInterceptor
;
//
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
// registry.addInterceptor(securityInterceptor).addPathPatterns("/user/**", "/admin/**"); // 只拦截我们定义的接口
registry
.
addInterceptor
(
adminAccessLogInterceptor
).
addPathPatterns
(
"/admins/**"
);
registry
.
addInterceptor
(
adminSecurityInterceptor
).
addPathPatterns
(
"/admins/**"
)
.
excludePathPatterns
(
"/admins/passport/login"
);
// 排除登陆接口
}
@Override
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
// 解决 swagger-ui.html 的访问,参考自 https://stackoverflow.com/questions/43545540/swagger-ui-no-mapping-found-for-http-request 解决
...
...
admin/admin-sdk/src/main/java/cn/iocoder/mall/admin/sdk/interceptor/AdminAccessLogInterceptor.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
sdk
.
interceptor
;
import
cn.iocoder.common.framework.util.HttpUtil
;
import
cn.iocoder.mall.admin.api.AdminAccessLogService
;
import
cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO
;
import
com.alibaba.dubbo.config.annotation.Reference
;
import
com.alibaba.fastjson.JSON
;
import
org.apache.commons.lang3.exception.ExceptionUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.util.Date
;
/**
* 访问日志拦截器
*/
@Component
public
class
AdminAccessLogInterceptor
extends
HandlerInterceptorAdapter
{
private
Logger
logger
=
LoggerFactory
.
getLogger
(
getClass
());
/**
* 开始时间
*/
private
static
final
ThreadLocal
<
Date
>
START_TIME
=
new
ThreadLocal
<>();
/**
* 管理员编号
*/
private
static
final
ThreadLocal
<
Integer
>
ADMIN_ID
=
new
ThreadLocal
<>();
@Reference
private
AdminAccessLogService
adminAccessLogService
;
@Override
public
boolean
preHandle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
Object
handler
)
{
// 记录当前时间
START_TIME
.
set
(
new
Date
());
return
true
;
}
@Override
public
void
afterCompletion
(
HttpServletRequest
request
,
HttpServletResponse
response
,
Object
handler
,
Exception
ex
)
{
AdminAccessLogAddDTO
accessLog
=
new
AdminAccessLogAddDTO
();
try
{
accessLog
.
setAdminId
(
ADMIN_ID
.
get
());
if
(
accessLog
.
getAdminId
()
==
null
)
{
accessLog
.
setAdminId
(
AdminAccessLogAddDTO
.
ADMIN_ID_NULL
);
}
accessLog
.
setUri
(
request
.
getRequestURI
());
// TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
accessLog
.
setQueryString
(
HttpUtil
.
buildQueryString
(
request
));
accessLog
.
setMethod
(
request
.
getMethod
());
accessLog
.
setUserAgent
(
HttpUtil
.
getUserAgent
(
request
));
accessLog
.
setIp
(
HttpUtil
.
getIp
(
request
));
accessLog
.
setStartTime
(
START_TIME
.
get
());
accessLog
.
setResponseTime
((
int
)
(
System
.
currentTimeMillis
()
-
accessLog
.
getStartTime
().
getTime
()));
// 默认响应时间设为0
adminAccessLogService
.
addAdminAccessLog
(
accessLog
);
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
}
catch
(
Throwable
th
)
{
logger
.
error
(
"[afterCompletion][插入管理员访问日志({}) 发生异常({})"
,
JSON
.
toJSONString
(
accessLog
),
ExceptionUtils
.
getRootCauseMessage
(
th
));
}
finally
{
clear
();
}
}
public
static
void
setAdminId
(
Integer
adminId
)
{
ADMIN_ID
.
set
(
adminId
);
}
public
static
void
clear
()
{
START_TIME
.
remove
();
ADMIN_ID
.
remove
();
}
}
admin/admin-sdk/src/main/java/cn/iocoder/mall/admin/sdk/interceptor/AdminSecurityInterceptor.java
浏览文件 @
532daf62
...
...
@@ -39,6 +39,13 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
// 添加到 AdminSecurityContext
AdminSecurityContext
context
=
new
AdminSecurityContext
(
authentication
.
getAdminId
(),
authentication
.
getRoleIds
());
AdminSecurityContextHolder
.
setContext
(
context
);
// 同时也记录管理员编号到 AdminAccessLogInterceptor 中。因为:
// AdminAccessLogInterceptor 需要在 AdminSecurityInterceptor 之前执行,这样记录的访问日志才健全
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
// 因此,这里需要进行记录
if
(
authentication
.
getAdminId
()
!=
null
)
{
AdminAccessLogInterceptor
.
setAdminId
(
authentication
.
getAdminId
());
}
}
else
{
String
url
=
request
.
getRequestURI
();
if
(!
url
.
equals
(
"/admin/passport/login"
))
{
// TODO 临时写死。非登陆接口,必须已经认证身份,不允许匿名访问
...
...
admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/AdminAccessLogService.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
api
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO
;
/**
* 管理员访问日志 Service 接口
*/
public
interface
AdminAccessLogService
{
CommonResult
<
Boolean
>
addAdminAccessLog
(
AdminAccessLogAddDTO
adminAccessLogAddDTO
);
}
admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/AdminService.java
浏览文件 @
532daf62
...
...
@@ -9,6 +9,9 @@ import cn.iocoder.mall.admin.api.dto.AdminUpdateDTO;
import
java.util.Set
;
/**
* 管理员 Service 接口
*/
public
interface
AdminService
{
CommonResult
<
AdminPageBO
>
getAdminPage
(
AdminPageDTO
adminPageDTO
);
...
...
admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/AdminAccessLogAddDTO.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
api
.
dto
;
import
javax.validation.constraints.NotNull
;
import
java.util.Date
;
/**
* 管理员访问日志添加 DTO
*/
public
class
AdminAccessLogAddDTO
{
/**
* 管理员编号 - 空
*/
public
static
final
Integer
ADMIN_ID_NULL
=
0
;
/**
* 管理员编号.
*
* 当管理员为空时,该值为0
*/
@NotNull
(
message
=
"管理员编号不能为空"
)
private
Integer
adminId
;
/**
* 访问地址
*/
@NotNull
(
message
=
"访问地址不能为空"
)
private
String
uri
;
/**
* 参数
*/
@NotNull
(
message
=
"请求参数不能为空"
)
private
String
queryString
;
/**
* http 方法
*/
@NotNull
(
message
=
"http 请求方法不能为空"
)
private
String
method
;
/**
* User Agent
*/
@NotNull
(
message
=
"User-Agent 不能为空"
)
private
String
userAgent
;
/**
* ip
*/
@NotNull
(
message
=
"ip 不能为空"
)
private
String
ip
;
/**
* 请求时间
*/
@NotNull
(
message
=
"请求时间不能为空"
)
private
Date
startTime
;
/**
* 响应时长 -- 毫秒级
*/
@NotNull
(
message
=
"响应时长不能为空"
)
private
Integer
responseTime
;
public
Integer
getAdminId
()
{
return
adminId
;
}
public
AdminAccessLogAddDTO
setAdminId
(
Integer
adminId
)
{
this
.
adminId
=
adminId
;
return
this
;
}
public
String
getUri
()
{
return
uri
;
}
public
AdminAccessLogAddDTO
setUri
(
String
uri
)
{
this
.
uri
=
uri
;
return
this
;
}
public
String
getQueryString
()
{
return
queryString
;
}
public
AdminAccessLogAddDTO
setQueryString
(
String
queryString
)
{
this
.
queryString
=
queryString
;
return
this
;
}
public
String
getMethod
()
{
return
method
;
}
public
AdminAccessLogAddDTO
setMethod
(
String
method
)
{
this
.
method
=
method
;
return
this
;
}
public
String
getUserAgent
()
{
return
userAgent
;
}
public
AdminAccessLogAddDTO
setUserAgent
(
String
userAgent
)
{
this
.
userAgent
=
userAgent
;
return
this
;
}
public
String
getIp
()
{
return
ip
;
}
public
AdminAccessLogAddDTO
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
return
this
;
}
public
Date
getStartTime
()
{
return
startTime
;
}
public
AdminAccessLogAddDTO
setStartTime
(
Date
startTime
)
{
this
.
startTime
=
startTime
;
return
this
;
}
public
Integer
getResponseTime
()
{
return
responseTime
;
}
public
AdminAccessLogAddDTO
setResponseTime
(
Integer
responseTime
)
{
this
.
responseTime
=
responseTime
;
return
this
;
}
}
\ No newline at end of file
admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/convert/AdminAccessLogConvert.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
convert
;
import
cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO
;
import
cn.iocoder.mall.admin.dataobject.AdminAccessLogDO
;
import
org.mapstruct.Mapper
;
import
org.mapstruct.Mappings
;
import
org.mapstruct.factory.Mappers
;
@Mapper
public
interface
AdminAccessLogConvert
{
AdminAccessLogConvert
INSTANCE
=
Mappers
.
getMapper
(
AdminAccessLogConvert
.
class
);
@Mappings
({})
AdminAccessLogDO
convert
(
AdminAccessLogAddDTO
adminAccessLogAddDTO
);
}
\ No newline at end of file
admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dao/AdminAccessLogMapper.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
dao
;
import
cn.iocoder.mall.admin.dataobject.AdminAccessLogDO
;
import
org.springframework.stereotype.Repository
;
@Repository
public
interface
AdminAccessLogMapper
{
void
insert
(
AdminAccessLogDO
entity
);
}
admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/AdminAccessLogDO.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
dataobject
;
import
cn.iocoder.common.framework.dataobject.BaseDO
;
import
java.util.Date
;
/**
* 管理员访问日志 DO
*/
public
class
AdminAccessLogDO
extends
BaseDO
{
/**
* 编号
*/
private
Integer
id
;
/**
* 管理员编号.
*
* 当管理员为空时,该值为0
*/
private
Integer
adminId
;
/**
* 访问地址
*/
private
String
uri
;
/**
* 参数
*/
private
String
queryString
;
/**
* http 方法
*/
private
String
method
;
/**
* userAgent
*/
private
String
userAgent
;
/**
* ip
*/
private
String
ip
;
/**
* 请求时间
*/
private
Date
startTime
;
/**
* 响应时长 -- 毫秒级
*/
private
Integer
responseTime
;
public
Integer
getId
()
{
return
id
;
}
public
AdminAccessLogDO
setId
(
Integer
id
)
{
this
.
id
=
id
;
return
this
;
}
public
Integer
getAdminId
()
{
return
adminId
;
}
public
AdminAccessLogDO
setAdminId
(
Integer
adminId
)
{
this
.
adminId
=
adminId
;
return
this
;
}
public
String
getUri
()
{
return
uri
;
}
public
AdminAccessLogDO
setUri
(
String
uri
)
{
this
.
uri
=
uri
;
return
this
;
}
public
String
getQueryString
()
{
return
queryString
;
}
public
AdminAccessLogDO
setQueryString
(
String
queryString
)
{
this
.
queryString
=
queryString
;
return
this
;
}
public
String
getMethod
()
{
return
method
;
}
public
AdminAccessLogDO
setMethod
(
String
method
)
{
this
.
method
=
method
;
return
this
;
}
public
String
getUserAgent
()
{
return
userAgent
;
}
public
AdminAccessLogDO
setUserAgent
(
String
userAgent
)
{
this
.
userAgent
=
userAgent
;
return
this
;
}
public
String
getIp
()
{
return
ip
;
}
public
AdminAccessLogDO
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
return
this
;
}
public
Date
getStartTime
()
{
return
startTime
;
}
public
AdminAccessLogDO
setStartTime
(
Date
startTime
)
{
this
.
startTime
=
startTime
;
return
this
;
}
public
Integer
getResponseTime
()
{
return
responseTime
;
}
public
AdminAccessLogDO
setResponseTime
(
Integer
responseTime
)
{
this
.
responseTime
=
responseTime
;
return
this
;
}
}
\ No newline at end of file
admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/service/AdminAccessLogServiceImpl.java
0 → 100644
浏览文件 @
532daf62
package
cn
.
iocoder
.
mall
.
admin
.
service
;
import
cn.iocoder.common.framework.util.StringUtil
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.admin.api.AdminAccessLogService
;
import
cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO
;
import
cn.iocoder.mall.admin.convert.AdminAccessLogConvert
;
import
cn.iocoder.mall.admin.dao.AdminAccessLogMapper
;
import
cn.iocoder.mall.admin.dataobject.AdminAccessLogDO
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.util.Date
;
@Service
@com
.
alibaba
.
dubbo
.
config
.
annotation
.
Service
(
validation
=
"true"
)
public
class
AdminAccessLogServiceImpl
implements
AdminAccessLogService
{
/**
* 请求参数最大长度。
*/
private
static
final
Integer
QUERY_STRING_MAX_LENGTH
=
4096
;
/**
* 请求地址最大长度。
*/
private
static
final
Integer
URI_MAX_LENGTH
=
4096
;
/**
* User-Agent 最大长度。
*/
private
static
final
Integer
USER_AGENT_MAX_LENGTH
=
1024
;
@Autowired
private
AdminAccessLogMapper
adminAccessLogMapper
;
@Override
public
CommonResult
<
Boolean
>
addAdminAccessLog
(
AdminAccessLogAddDTO
adminAccessLogAddDTO
)
{
// 创建 AdminAccessLogDO
AdminAccessLogDO
accessLog
=
AdminAccessLogConvert
.
INSTANCE
.
convert
(
adminAccessLogAddDTO
);
accessLog
.
setCreateTime
(
new
Date
());
// 截取最大长度
if
(
accessLog
.
getUri
().
length
()
>
URI_MAX_LENGTH
)
{
accessLog
.
setUri
(
StringUtil
.
substring
(
accessLog
.
getUri
(),
URI_MAX_LENGTH
));
}
if
(
accessLog
.
getQueryString
().
length
()
>
QUERY_STRING_MAX_LENGTH
)
{
accessLog
.
setQueryString
(
StringUtil
.
substring
(
accessLog
.
getQueryString
(),
QUERY_STRING_MAX_LENGTH
));
}
if
(
accessLog
.
getUserAgent
().
length
()
>
USER_AGENT_MAX_LENGTH
)
{
accessLog
.
setUserAgent
(
StringUtil
.
substring
(
accessLog
.
getUserAgent
(),
USER_AGENT_MAX_LENGTH
));
}
// 插入
adminAccessLogMapper
.
insert
(
accessLog
);
// 返回成功
return
CommonResult
.
success
(
true
);
}
}
\ No newline at end of file
admin/admin-service-impl/src/main/resources/mapper/AdminAccessLogMapper.xml
0 → 100644
浏览文件 @
532daf62
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"cn.iocoder.mall.admin.dao.AdminAccessLogMapper"
>
<!--<sql id="FIELDS">-->
<!--id, username, nickname, password, status,-->
<!--create_time-->
<!--</sql>-->
<insert
id=
"insert"
parameterType=
"AdminAccessLogDO"
useGeneratedKeys=
"true"
keyColumn=
"id"
keyProperty=
"id"
>
INSERT INTO admin_access_log (
admin_id, uri, query_string, method, user_agent,
ip, start_time, response_time, create_time
) VALUES (
#{adminId}, #{uri}, #{queryString}, #{method}, #{userAgent},
#{ip}, #{startTime}, #{responseTime}, #{createTime}
)
</insert>
</mapper>
\ No newline at end of file
common/common-framework/src/main/java/cn/iocoder/common/framework/util/HttpUtil.java
浏览文件 @
532daf62
package
cn
.
iocoder
.
common
.
framework
.
util
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.util.StringUtils
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLDecoder
;
import
java.util.Enumeration
;
public
class
HttpUtil
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
HttpUtil
.
class
);
/**
* Standard Servlet 2.3+ spec request attributes for include URI and paths.
* <p>If included via a RequestDispatcher, the current resource will see the
* originating request. Its own URI and paths are exposed as request attributes.
*/
public
static
final
String
INCLUDE_REQUEST_URI_ATTRIBUTE
=
"javax.servlet.include.request_uri"
;
public
static
final
String
INCLUDE_CONTEXT_PATH_ATTRIBUTE
=
"javax.servlet.include.context_path"
;
// public static final String INCLUDE_SERVLET_PATH_ATTRIBUTE = "javax.servlet.include.servlet_path";
// public static final String INCLUDE_PATH_INFO_ATTRIBUTE = "javax.servlet.include.path_info";
// public static final String INCLUDE_QUERY_STRING_ATTRIBUTE = "javax.servlet.include.query_string";
//
// /**
// * Standard Servlet 2.4+ spec request attributes for forward URI and paths.
// * <p>If forwarded to via a RequestDispatcher, the current resource will see its
// * own URI and paths. The originating URI and paths are exposed as request attributes.
// */
// public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri";
// public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path";
// public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path";
// public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info";
// public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string";
/**
* Default character encoding to use when <code>request.getCharacterEncoding</code>
* returns <code>null</code>, according to the Servlet spec.
*
* @see javax.servlet.ServletRequest#getCharacterEncoding
*/
public
static
final
String
DEFAULT_CHARACTER_ENCODING
=
"ISO-8859-1"
;
public
static
String
obtainAccess
(
HttpServletRequest
request
)
{
String
authorization
=
request
.
getHeader
(
"Authorization"
);
if
(!
StringUtils
.
hasText
(
authorization
))
{
...
...
@@ -39,4 +77,243 @@ public class HttpUtil {
return
request
.
getRemoteAddr
();
}
/**
* @param request 请求
* @return ua
*/
public
static
String
getUserAgent
(
HttpServletRequest
request
)
{
String
ua
=
request
.
getHeader
(
"User-Agent"
);
return
ua
!=
null
?
ua
:
""
;
}
/**
* 根据request拼接queryString
*
* @return queryString
*/
@SuppressWarnings
(
"unchecked"
)
public
static
String
buildQueryString
(
HttpServletRequest
request
)
{
Enumeration
<
String
>
es
=
request
.
getParameterNames
();
if
(!
es
.
hasMoreElements
())
{
return
""
;
}
String
parameterName
,
parameterValue
;
StringBuilder
params
=
new
StringBuilder
();
while
(
es
.
hasMoreElements
())
{
parameterName
=
es
.
nextElement
();
parameterValue
=
request
.
getParameter
(
parameterName
);
params
.
append
(
parameterName
).
append
(
"="
).
append
(
parameterValue
).
append
(
"&"
);
}
return
params
.
deleteCharAt
(
params
.
length
()
-
1
).
toString
();
}
/**
* Return the path within the web application for the given request.
* Detects include request URL if called within a RequestDispatcher include.
* <p/>
* For example, for a request to URL
* <p/>
* <code>http://www.somehost.com/myapp/my/url.jsp</code>,
* <p/>
* for an application deployed to <code>/mayapp</code> (the application's context path), this method would return
* <p/>
* <code>/my/url.jsp</code>.
*
* 该方法,是从 Shiro 源码中,扣出来。add by 芋艿
*
* @param request current HTTP request
* @return the path within the web application
*/
public
static
String
getPathWithinApplication
(
HttpServletRequest
request
)
{
String
contextPath
=
getContextPath
(
request
);
String
requestUri
=
getRequestUri
(
request
);
if
(
StringUtils
.
startsWithIgnoreCase
(
requestUri
,
contextPath
))
{
// Normal case: URI contains context path.
String
path
=
requestUri
.
substring
(
contextPath
.
length
());
return
(
StringUtils
.
hasText
(
path
)
?
path
:
"/"
);
}
else
{
// Special case: rather unusual.
return
requestUri
;
}
}
/**
* Return the request URI for the given request, detecting an include request
* URL if called within a RequestDispatcher include.
* <p>As the value returned by <code>request.getRequestURI()</code> is <i>not</i>
* decoded by the servlet container, this method will decode it.
* <p>The URI that the web container resolves <i>should</i> be correct, but some
* containers like JBoss/Jetty incorrectly include ";" strings like ";jsessionid"
* in the URI. This method cuts off such incorrect appendices.
*
* @param request current HTTP request
* @return the request URI
*/
public
static
String
getRequestUri
(
HttpServletRequest
request
)
{
String
uri
=
(
String
)
request
.
getAttribute
(
INCLUDE_REQUEST_URI_ATTRIBUTE
);
if
(
uri
==
null
)
{
uri
=
request
.
getRequestURI
();
}
return
normalize
(
decodeAndCleanUriString
(
request
,
uri
));
}
/**
* Normalize a relative URI path that may have relative values ("/./",
* "/../", and so on ) it it. <strong>WARNING</strong> - This method is
* useful only for normalizing application-generated paths. It does not
* try to perform security checks for malicious input.
* Normalize operations were was happily taken from org.apache.catalina.util.RequestUtil in
* Tomcat trunk, r939305
*
* @param path Relative path to be normalized
* @return normalized path
*/
public
static
String
normalize
(
String
path
)
{
return
normalize
(
path
,
true
);
}
/**
* Normalize a relative URI path that may have relative values ("/./",
* "/../", and so on ) it it. <strong>WARNING</strong> - This method is
* useful only for normalizing application-generated paths. It does not
* try to perform security checks for malicious input.
* Normalize operations were was happily taken from org.apache.catalina.util.RequestUtil in
* Tomcat trunk, r939305
*
* @param path Relative path to be normalized
* @param replaceBackSlash Should '\\' be replaced with '/'
* @return normalized path
*/
private
static
String
normalize
(
String
path
,
boolean
replaceBackSlash
)
{
if
(
path
==
null
)
return
null
;
// Create a place for the normalized path
String
normalized
=
path
;
if
(
replaceBackSlash
&&
normalized
.
indexOf
(
'\\'
)
>=
0
)
normalized
=
normalized
.
replace
(
'\\'
,
'/'
);
if
(
normalized
.
equals
(
"/."
))
return
"/"
;
// Add a leading "/" if necessary
if
(!
normalized
.
startsWith
(
"/"
))
normalized
=
"/"
+
normalized
;
// Resolve occurrences of "//" in the normalized path
while
(
true
)
{
int
index
=
normalized
.
indexOf
(
"//"
);
if
(
index
<
0
)
break
;
normalized
=
normalized
.
substring
(
0
,
index
)
+
normalized
.
substring
(
index
+
1
);
}
// Resolve occurrences of "/./" in the normalized path
while
(
true
)
{
int
index
=
normalized
.
indexOf
(
"/./"
);
if
(
index
<
0
)
break
;
normalized
=
normalized
.
substring
(
0
,
index
)
+
normalized
.
substring
(
index
+
2
);
}
// Resolve occurrences of "/../" in the normalized path
while
(
true
)
{
int
index
=
normalized
.
indexOf
(
"/../"
);
if
(
index
<
0
)
break
;
if
(
index
==
0
)
return
(
null
);
// Trying to go outside our context
int
index2
=
normalized
.
lastIndexOf
(
'/'
,
index
-
1
);
normalized
=
normalized
.
substring
(
0
,
index2
)
+
normalized
.
substring
(
index
+
3
);
}
// Return the normalized path that we have completed
return
(
normalized
);
}
/**
* Decode the supplied URI string and strips any extraneous portion after a ';'.
*
* @param request the incoming HttpServletRequest
* @param uri the application's URI string
* @return the supplied URI string stripped of any extraneous portion after a ';'.
*/
private
static
String
decodeAndCleanUriString
(
HttpServletRequest
request
,
String
uri
)
{
uri
=
decodeRequestString
(
request
,
uri
);
int
semicolonIndex
=
uri
.
indexOf
(
';'
);
return
(
semicolonIndex
!=
-
1
?
uri
.
substring
(
0
,
semicolonIndex
)
:
uri
);
}
/**
* Return the context path for the given request, detecting an include request
* URL if called within a RequestDispatcher include.
* <p>As the value returned by <code>request.getContextPath()</code> is <i>not</i>
* decoded by the servlet container, this method will decode it.
*
* @param request current HTTP request
* @return the context path
*/
public
static
String
getContextPath
(
HttpServletRequest
request
)
{
String
contextPath
=
(
String
)
request
.
getAttribute
(
INCLUDE_CONTEXT_PATH_ATTRIBUTE
);
if
(
contextPath
==
null
)
{
contextPath
=
request
.
getContextPath
();
}
if
(
"/"
.
equals
(
contextPath
))
{
// Invalid case, but happens for includes on Jetty: silently adapt it.
contextPath
=
""
;
}
return
decodeRequestString
(
request
,
contextPath
);
}
/**
* Decode the given source string with a URLDecoder. The encoding will be taken
* from the request, falling back to the default "ISO-8859-1".
* <p>The default implementation uses <code>URLDecoder.decode(input, enc)</code>.
*
* @param request current HTTP request
* @param source the String to decode
* @return the decoded String
* @see #DEFAULT_CHARACTER_ENCODING
* @see javax.servlet.ServletRequest#getCharacterEncoding
* @see java.net.URLDecoder#decode(String, String)
* @see java.net.URLDecoder#decode(String)
*/
@SuppressWarnings
({
"deprecation"
})
public
static
String
decodeRequestString
(
HttpServletRequest
request
,
String
source
)
{
String
enc
=
determineEncoding
(
request
);
try
{
return
URLDecoder
.
decode
(
source
,
enc
);
}
catch
(
UnsupportedEncodingException
ex
)
{
if
(
logger
.
isWarnEnabled
())
{
logger
.
warn
(
"Could not decode request string ["
+
source
+
"] with encoding '"
+
enc
+
"': falling back to platform default encoding; exception message: "
+
ex
.
getMessage
());
}
return
URLDecoder
.
decode
(
source
);
}
}
/**
* Determine the encoding for the given request.
* Can be overridden in subclasses.
* <p>The default implementation checks the request's
* {@link ServletRequest#getCharacterEncoding() character encoding}, and if that
* <code>null</code>, falls back to the {@link #DEFAULT_CHARACTER_ENCODING}.
*
* @param request current HTTP request
* @return the encoding for the request (never <code>null</code>)
* @see javax.servlet.ServletRequest#getCharacterEncoding()
*/
protected
static
String
determineEncoding
(
HttpServletRequest
request
)
{
String
enc
=
request
.
getCharacterEncoding
();
if
(
enc
==
null
)
{
enc
=
DEFAULT_CHARACTER_ENCODING
;
}
return
enc
;
}
}
\ No newline at end of file
common/common-framework/src/main/java/cn/iocoder/common/framework/util/StringUtil.java
浏览文件 @
532daf62
...
...
@@ -27,4 +27,8 @@ public class StringUtil {
return
array
;
}
public
static
String
substring
(
String
str
,
int
start
)
{
return
org
.
apache
.
commons
.
lang3
.
StringUtils
.
substring
(
str
,
start
);
}
}
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论