Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
W
wangxiaolu-sfa-auth
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
sfa
wangxiaolu-sfa-auth
Commits
2f61894a
提交
2f61894a
authored
10月 09, 2024
作者:
李秋林
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
初始化代码
上级
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
622 行增加
和
0 行删除
+622
-0
pom.xml
pom.xml
+83
-0
SfaAuthApplication.java
src/main/java/com/sfa/auth/SfaAuthApplication.java
+21
-0
TokenController.java
src/main/java/com/sfa/auth/controller/TokenController.java
+78
-0
LoginBody.java
src/main/java/com/sfa/auth/form/LoginBody.java
+46
-0
RegisterBody.java
src/main/java/com/sfa/auth/form/RegisterBody.java
+11
-0
SysLoginService.java
src/main/java/com/sfa/auth/service/SysLoginService.java
+155
-0
SysPasswordService.java
src/main/java/com/sfa/auth/service/SysPasswordService.java
+85
-0
SysRecordLogService.java
src/main/java/com/sfa/auth/service/SysRecordLogService.java
+48
-0
bootstrap-dev.yml
src/main/resources/bootstrap-dev.yml
+15
-0
bootstrap.yml
src/main/resources/bootstrap.yml
+5
-0
logback.xml
src/main/resources/logback.xml
+75
-0
没有找到文件。
pom.xml
0 → 100644
浏览文件 @
2f61894a
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<groupId>
com.wangxiaolu.sfa
</groupId>
<artifactId>
wangxiaolu-sfa-parent
</artifactId>
<version>
0.0.1
</version>
<relativePath/>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<name>
wangxiaolu-sfa-auth
</name>
<artifactId>
wangxiaolu-sfa-auth
</artifactId>
<version>
0.0.1
</version>
<description>
wangxiaolu-sfa-auth认证授权中心
</description>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-config
</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-sentinel
</artifactId>
</dependency>
<!-- SpringBoot Web -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-actuator
</artifactId>
</dependency>
<!-- RuoYi Common Security-->
<dependency>
<groupId>
com.wangxiaolu.sfa
</groupId>
<artifactId>
wangxiaolu-sfa-common-security
</artifactId>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
<optional>
true
</optional>
</dependency>
</dependencies>
<build>
<finalName>
${project.artifactId}
</finalName>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
src/main/java/com/sfa/auth/SfaAuthApplication.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
;
import
com.sfa.common.security.annotation.EnableRyFeignClients
;
/**
* 认证授权中心
*
* @author ruoyi
*/
@EnableRyFeignClients
@SpringBootApplication
(
exclude
=
{
DataSourceAutoConfiguration
.
class
})
public
class
SfaAuthApplication
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
SfaAuthApplication
.
class
,
args
);
}
}
src/main/java/com/sfa/auth/controller/TokenController.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
controller
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.DeleteMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RestController
;
import
com.sfa.auth.form.LoginBody
;
import
com.sfa.auth.form.RegisterBody
;
import
com.sfa.auth.service.SysLoginService
;
import
com.sfa.common.core.domain.R
;
import
com.sfa.common.core.utils.JwtUtils
;
import
com.sfa.common.core.utils.StringUtils
;
import
com.sfa.common.security.auth.AuthUtil
;
import
com.sfa.common.security.service.TokenService
;
import
com.sfa.common.security.utils.SecurityUtils
;
import
com.sfa.system.api.model.LoginUser
;
/**
* token 控制
*
* @author ruoyi
*/
@RestController
public
class
TokenController
{
@Autowired
private
TokenService
tokenService
;
@Autowired
private
SysLoginService
sysLoginService
;
@PostMapping
(
"/login"
)
public
R
<?>
login
(
@RequestBody
LoginBody
form
)
{
// 用户登录
LoginUser
userInfo
=
sysLoginService
.
login
(
form
.
getUsername
(),
form
.
getPassword
());
// 获取登录token
return
R
.
ok
(
tokenService
.
createToken
(
userInfo
));
}
@DeleteMapping
(
"/logout"
)
public
R
<?>
logout
(
HttpServletRequest
request
)
{
String
token
=
SecurityUtils
.
getToken
(
request
);
if
(
StringUtils
.
isNotEmpty
(
token
))
{
String
username
=
JwtUtils
.
getUserName
(
token
);
// 删除用户缓存记录
AuthUtil
.
logoutByToken
(
token
);
// 记录用户退出日志
sysLoginService
.
logout
(
username
);
}
return
R
.
ok
();
}
@PostMapping
(
"/refresh"
)
public
R
<?>
refresh
(
HttpServletRequest
request
)
{
LoginUser
loginUser
=
tokenService
.
getLoginUser
(
request
);
if
(
StringUtils
.
isNotNull
(
loginUser
))
{
// 刷新令牌有效期
tokenService
.
refreshToken
(
loginUser
);
return
R
.
ok
();
}
return
R
.
ok
();
}
@PostMapping
(
"/register"
)
public
R
<?>
register
(
@RequestBody
RegisterBody
registerBody
)
{
// 用户注册
sysLoginService
.
register
(
registerBody
.
getUsername
(),
registerBody
.
getPassword
());
return
R
.
ok
();
}
}
src/main/java/com/sfa/auth/form/LoginBody.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
form
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* 用户登录对象
*
* @author ruoyi
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public
class
LoginBody
{
/**
* 用户名
*/
private
String
username
;
/**
* 用户密码
*/
private
String
password
;
public
String
getUsername
()
{
return
username
;
}
public
void
setUsername
(
String
username
)
{
this
.
username
=
username
;
}
public
String
getPassword
()
{
return
password
;
}
public
void
setPassword
(
String
password
)
{
this
.
password
=
password
;
}
}
src/main/java/com/sfa/auth/form/RegisterBody.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
form
;
/**
* 用户注册对象
*
* @author ruoyi
*/
public
class
RegisterBody
extends
LoginBody
{
}
src/main/java/com/sfa/auth/service/SysLoginService.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
service
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
com.sfa.common.core.constant.CacheConstants
;
import
com.sfa.common.core.constant.Constants
;
import
com.sfa.common.core.constant.SecurityConstants
;
import
com.sfa.common.core.constant.UserConstants
;
import
com.sfa.common.core.domain.R
;
import
com.sfa.common.core.enums.UserStatus
;
import
com.sfa.common.core.exception.ServiceException
;
import
com.sfa.common.core.text.Convert
;
import
com.sfa.common.core.utils.DateUtils
;
import
com.sfa.common.core.utils.StringUtils
;
import
com.sfa.common.core.utils.ip.IpUtils
;
import
com.sfa.common.redis.service.RedisService
;
import
com.sfa.common.security.utils.SecurityUtils
;
import
com.sfa.system.api.RemoteUserService
;
import
com.sfa.system.api.domain.SysUser
;
import
com.sfa.system.api.model.LoginUser
;
/**
* 登录校验方法
*
* @author ruoyi
*/
@Component
public
class
SysLoginService
{
@Autowired
private
RemoteUserService
remoteUserService
;
@Autowired
private
SysPasswordService
passwordService
;
@Autowired
private
SysRecordLogService
recordLogService
;
@Autowired
private
RedisService
redisService
;
/**
* 登录
*/
public
LoginUser
login
(
String
username
,
String
password
)
{
// 用户名或密码为空 错误
if
(
StringUtils
.
isAnyBlank
(
username
,
password
))
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"用户/密码必须填写"
);
throw
new
ServiceException
(
"用户/密码必须填写"
);
}
// 密码如果不在指定范围内 错误
if
(
password
.
length
()
<
UserConstants
.
PASSWORD_MIN_LENGTH
||
password
.
length
()
>
UserConstants
.
PASSWORD_MAX_LENGTH
)
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"用户密码不在指定范围"
);
throw
new
ServiceException
(
"用户密码不在指定范围"
);
}
// 用户名不在指定范围内 错误
if
(
username
.
length
()
<
UserConstants
.
USERNAME_MIN_LENGTH
||
username
.
length
()
>
UserConstants
.
USERNAME_MAX_LENGTH
)
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"用户名不在指定范围"
);
throw
new
ServiceException
(
"用户名不在指定范围"
);
}
// IP黑名单校验
String
blackStr
=
Convert
.
toStr
(
redisService
.
getCacheObject
(
CacheConstants
.
SYS_LOGIN_BLACKIPLIST
));
if
(
IpUtils
.
isMatchedIp
(
blackStr
,
IpUtils
.
getIpAddr
()))
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"很遗憾,访问IP已被列入系统黑名单"
);
throw
new
ServiceException
(
"很遗憾,访问IP已被列入系统黑名单"
);
}
// 查询用户信息
R
<
LoginUser
>
userResult
=
remoteUserService
.
getUserInfo
(
username
,
SecurityConstants
.
INNER
);
if
(
R
.
FAIL
==
userResult
.
getCode
())
{
throw
new
ServiceException
(
userResult
.
getMsg
());
}
LoginUser
userInfo
=
userResult
.
getData
();
SysUser
user
=
userResult
.
getData
().
getSysUser
();
if
(
UserStatus
.
DELETED
.
getCode
().
equals
(
user
.
getDelFlag
()))
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"对不起,您的账号已被删除"
);
throw
new
ServiceException
(
"对不起,您的账号:"
+
username
+
" 已被删除"
);
}
if
(
UserStatus
.
DISABLE
.
getCode
().
equals
(
user
.
getStatus
()))
{
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
"用户已停用,请联系管理员"
);
throw
new
ServiceException
(
"对不起,您的账号:"
+
username
+
" 已停用"
);
}
passwordService
.
validate
(
user
,
password
);
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_SUCCESS
,
"登录成功"
);
recordLoginInfo
(
user
.
getUserId
());
return
userInfo
;
}
/**
* 记录登录信息
*
* @param userId 用户ID
*/
public
void
recordLoginInfo
(
Long
userId
)
{
SysUser
sysUser
=
new
SysUser
();
sysUser
.
setUserId
(
userId
);
// 更新用户登录IP
sysUser
.
setLoginIp
(
IpUtils
.
getIpAddr
());
// 更新用户登录时间
sysUser
.
setLoginDate
(
DateUtils
.
getNowDate
());
remoteUserService
.
recordUserLogin
(
sysUser
,
SecurityConstants
.
INNER
);
}
public
void
logout
(
String
loginName
)
{
recordLogService
.
recordLogininfor
(
loginName
,
Constants
.
LOGOUT
,
"退出成功"
);
}
/**
* 注册
*/
public
void
register
(
String
username
,
String
password
)
{
// 用户名或密码为空 错误
if
(
StringUtils
.
isAnyBlank
(
username
,
password
))
{
throw
new
ServiceException
(
"用户/密码必须填写"
);
}
if
(
username
.
length
()
<
UserConstants
.
USERNAME_MIN_LENGTH
||
username
.
length
()
>
UserConstants
.
USERNAME_MAX_LENGTH
)
{
throw
new
ServiceException
(
"账户长度必须在2到20个字符之间"
);
}
if
(
password
.
length
()
<
UserConstants
.
PASSWORD_MIN_LENGTH
||
password
.
length
()
>
UserConstants
.
PASSWORD_MAX_LENGTH
)
{
throw
new
ServiceException
(
"密码长度必须在5到20个字符之间"
);
}
// 注册用户信息
SysUser
sysUser
=
new
SysUser
();
sysUser
.
setUserName
(
username
);
sysUser
.
setNickName
(
username
);
sysUser
.
setPassword
(
SecurityUtils
.
encryptPassword
(
password
));
R
<?>
registerResult
=
remoteUserService
.
registerUserInfo
(
sysUser
,
SecurityConstants
.
INNER
);
if
(
R
.
FAIL
==
registerResult
.
getCode
())
{
throw
new
ServiceException
(
registerResult
.
getMsg
());
}
recordLogService
.
recordLogininfor
(
username
,
Constants
.
REGISTER
,
"注册成功"
);
}
}
src/main/java/com/sfa/auth/service/SysPasswordService.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
service
;
import
java.util.concurrent.TimeUnit
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
com.sfa.common.core.constant.CacheConstants
;
import
com.sfa.common.core.constant.Constants
;
import
com.sfa.common.core.exception.ServiceException
;
import
com.sfa.common.redis.service.RedisService
;
import
com.sfa.common.security.utils.SecurityUtils
;
import
com.sfa.system.api.domain.SysUser
;
/**
* 登录密码方法
*
* @author ruoyi
*/
@Component
public
class
SysPasswordService
{
@Autowired
private
RedisService
redisService
;
private
int
maxRetryCount
=
CacheConstants
.
PASSWORD_MAX_RETRY_COUNT
;
private
Long
lockTime
=
CacheConstants
.
PASSWORD_LOCK_TIME
;
@Autowired
private
SysRecordLogService
recordLogService
;
/**
* 登录账户密码错误次数缓存键名
*
* @param username 用户名
* @return 缓存键key
*/
private
String
getCacheKey
(
String
username
)
{
return
CacheConstants
.
PWD_ERR_CNT_KEY
+
username
;
}
public
void
validate
(
SysUser
user
,
String
password
)
{
String
username
=
user
.
getUserName
();
Integer
retryCount
=
redisService
.
getCacheObject
(
getCacheKey
(
username
));
if
(
retryCount
==
null
)
{
retryCount
=
0
;
}
if
(
retryCount
>=
Integer
.
valueOf
(
maxRetryCount
).
intValue
())
{
String
errMsg
=
String
.
format
(
"密码输入错误%s次,帐户锁定%s分钟"
,
maxRetryCount
,
lockTime
);
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
errMsg
);
throw
new
ServiceException
(
errMsg
);
}
if
(!
matches
(
user
,
password
))
{
retryCount
=
retryCount
+
1
;
recordLogService
.
recordLogininfor
(
username
,
Constants
.
LOGIN_FAIL
,
String
.
format
(
"密码输入错误%s次"
,
retryCount
));
redisService
.
setCacheObject
(
getCacheKey
(
username
),
retryCount
,
lockTime
,
TimeUnit
.
MINUTES
);
throw
new
ServiceException
(
"用户不存在/密码错误"
);
}
else
{
clearLoginRecordCache
(
username
);
}
}
public
boolean
matches
(
SysUser
user
,
String
rawPassword
)
{
return
SecurityUtils
.
matchesPassword
(
rawPassword
,
user
.
getPassword
());
}
public
void
clearLoginRecordCache
(
String
loginName
)
{
if
(
redisService
.
hasKey
(
getCacheKey
(
loginName
)))
{
redisService
.
deleteObject
(
getCacheKey
(
loginName
));
}
}
}
src/main/java/com/sfa/auth/service/SysRecordLogService.java
0 → 100644
浏览文件 @
2f61894a
package
com
.
sfa
.
auth
.
service
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
com.sfa.common.core.constant.Constants
;
import
com.sfa.common.core.constant.SecurityConstants
;
import
com.sfa.common.core.utils.StringUtils
;
import
com.sfa.common.core.utils.ip.IpUtils
;
import
com.sfa.system.api.RemoteLogService
;
import
com.sfa.system.api.domain.SysLogininfor
;
/**
* 记录日志方法
*
* @author ruoyi
*/
@Component
public
class
SysRecordLogService
{
@Autowired
private
RemoteLogService
remoteLogService
;
/**
* 记录登录信息
*
* @param username 用户名
* @param status 状态
* @param message 消息内容
* @return
*/
public
void
recordLogininfor
(
String
username
,
String
status
,
String
message
)
{
SysLogininfor
logininfor
=
new
SysLogininfor
();
logininfor
.
setUserName
(
username
);
logininfor
.
setIpaddr
(
IpUtils
.
getIpAddr
());
logininfor
.
setMsg
(
message
);
// 日志状态
if
(
StringUtils
.
equalsAny
(
status
,
Constants
.
LOGIN_SUCCESS
,
Constants
.
LOGOUT
,
Constants
.
REGISTER
))
{
logininfor
.
setStatus
(
Constants
.
LOGIN_SUCCESS_STATUS
);
}
else
if
(
Constants
.
LOGIN_FAIL
.
equals
(
status
))
{
logininfor
.
setStatus
(
Constants
.
LOGIN_FAIL_STATUS
);
}
remoteLogService
.
saveLogininfor
(
logininfor
,
SecurityConstants
.
INNER
);
}
}
src/main/resources/bootstrap-dev.yml
0 → 100644
浏览文件 @
2f61894a
spring
:
application
:
name
:
wangxiaolu-sfa-auth
cloud
:
nacos
:
discovery
:
server-addr
:
sfa.test.wxl66.cn:8848
group
:
sfa
namespace
:
db2a5aa4-e380-4787-9214-1c394f99ffb4
config
:
server-addr
:
sfa.test.wxl66.cn:8848
file-extension
:
yaml
group
:
sfa
namespace
:
db2a5aa4-e380-4787-9214-1c394f99ffb4
src/main/resources/bootstrap.yml
0 → 100644
浏览文件 @
2f61894a
spring
:
profiles
:
active
:
dev
server
:
\ No newline at end of file
src/main/resources/logback.xml
0 → 100644
浏览文件 @
2f61894a
<?xml version="1.0" encoding="UTF-8"?>
<configuration
scan=
"true"
scanPeriod=
"60 seconds"
debug=
"false"
>
<!-- 日志存放路径 -->
<property
name=
"log.path"
value=
"logs/wangxiaolu-sfa-auth"
/>
<!-- 日志输出格式 -->
<property
name=
"log.pattern"
value=
"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"
/>
<!-- 控制台输出 -->
<appender
name=
"console"
class=
"ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>
${log.pattern}
</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender
name=
"file_info"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<file>
${log.path}/info.log
</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<!-- 日志文件名格式 -->
<fileNamePattern>
${log.path}/info.%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>
60
</maxHistory>
</rollingPolicy>
<encoder>
<pattern>
${log.pattern}
</pattern>
</encoder>
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<!-- 过滤的级别 -->
<level>
INFO
</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>
ACCEPT
</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<appender
name=
"file_error"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<file>
${log.path}/error.log
</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<!-- 日志文件名格式 -->
<fileNamePattern>
${log.path}/error.%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>
60
</maxHistory>
</rollingPolicy>
<encoder>
<pattern>
${log.pattern}
</pattern>
</encoder>
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<!-- 过滤的级别 -->
<level>
ERROR
</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>
ACCEPT
</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger
name=
"com.sfa"
level=
"info"
/>
<!-- Spring日志级别控制 -->
<logger
name=
"org.springframework"
level=
"warn"
/>
<root
level=
"info"
>
<appender-ref
ref=
"console"
/>
</root>
<!--系统操作日志-->
<root
level=
"info"
>
<appender-ref
ref=
"file_info"
/>
<appender-ref
ref=
"file_error"
/>
</root>
</configuration>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论