Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lakernote
EasyAdmin
提交
f57cfdb9
E
EasyAdmin
项目概览
lakernote
/
EasyAdmin
9 个月 前同步成功
通知
14
Star
3
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
EasyAdmin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f57cfdb9
编写于
8月 24, 2021
作者:
lakernote
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
(新增)[整体](在线用户管理)
上级
5de93ffb
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
359 addition
and
7 deletion
+359
-7
src/main/java/com/laker/admin/EasyAdminApplication.java
src/main/java/com/laker/admin/EasyAdminApplication.java
+3
-0
src/main/java/com/laker/admin/framework/PageDtoUtil.java
src/main/java/com/laker/admin/framework/PageDtoUtil.java
+54
-0
src/main/java/com/laker/admin/framework/ext/satoken/MySaTokenListener.java
.../laker/admin/framework/ext/satoken/MySaTokenListener.java
+117
-0
src/main/java/com/laker/admin/framework/ext/satoken/OnlineUser.java
...ava/com/laker/admin/framework/ext/satoken/OnlineUser.java
+22
-0
src/main/java/com/laker/admin/module/sys/controller/LoginController.java
...om/laker/admin/module/sys/controller/LoginController.java
+31
-4
src/main/resources/application.yaml
src/main/resources/application.yaml
+5
-3
web/admin/view/system/onlineUser.html
web/admin/view/system/onlineUser.html
+127
-0
未找到文件。
src/main/java/com/laker/admin/EasyAdminApplication.java
浏览文件 @
f57cfdb9
...
...
@@ -5,11 +5,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* @author laker
*/
@SpringBootApplication
public
class
EasyAdminApplication
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
EasyAdminApplication
.
class
,
args
);
System
.
out
.
println
(
"Gitee:https://gitee.com/lakernote/easy-admin"
);
System
.
out
.
println
(
"GitHub:https://github.com/lakernote/easy-admin"
);
}
}
src/main/java/com/laker/admin/framework/PageDtoUtil.java
0 → 100644
浏览文件 @
f57cfdb9
package
com.laker.admin.framework
;
import
cn.hutool.core.util.PageUtil
;
import
lombok.Data
;
import
java.util.List
;
/**
* 内存分页
*/
@Data
public
class
PageDtoUtil
{
//当前页
private
int
pageNum
;
//页大小
private
int
pageSize
;
//总页数
private
int
pages
;
//数据总数
private
int
total
;
//分页结果
private
List
<?>
pageList
;
/**
* @return
* @description 内存分页,hutool工具类相关
* @Param
* @author tzh
* @date
*/
public
static
PageDtoUtil
getPageDto
(
List
<?>
list
,
int
pageNum
,
int
pageSize
)
{
PageDtoUtil
pageDtoUtil
=
new
PageDtoUtil
();
//总页数
int
pages
=
PageUtil
.
totalPage
(
list
.
size
(),
pageSize
);
//开始位置和结束位置
int
[]
startEnd
=
PageUtil
.
transToStartEnd
(
pageNum
-
1
,
pageSize
);
//分页后的结果集
List
<?>
pageList
=
null
;
if
(
startEnd
[
1
]
<
list
.
size
())
{
pageList
=
list
.
subList
(
startEnd
[
0
],
startEnd
[
1
]);
}
else
{
pageList
=
list
.
subList
(
startEnd
[
0
],
list
.
size
());
}
pageDtoUtil
.
setPageSize
(
pageSize
);
//页大小
pageDtoUtil
.
setPageNum
(
pageNum
);
//当前页码
pageDtoUtil
.
setPages
(
pages
);
//总页数
pageDtoUtil
.
setTotal
(
list
.
size
());
//数据总数
pageDtoUtil
.
setPageList
(
pageList
);
//分页结果集
return
pageDtoUtil
;
}
}
\ No newline at end of file
src/main/java/com/laker/admin/framework/ext/satoken/MySaTokenListener.java
0 → 100644
浏览文件 @
f57cfdb9
package
com.laker.admin.framework.ext.satoken
;
import
cn.dev33.satoken.listener.SaTokenListener
;
import
cn.dev33.satoken.stp.SaLoginModel
;
import
cn.dev33.satoken.stp.StpUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.http.useragent.UserAgent
;
import
com.laker.admin.module.sys.service.ISysUserService
;
import
com.laker.admin.utils.IP2CityUtil
;
import
com.laker.admin.utils.http.HttpServletRequestUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
* 自定义侦听器的实现
*/
@Component
@Slf4j
public
class
MySaTokenListener
implements
SaTokenListener
{
public
static
final
List
<
OnlineUser
>
ONLINE_USERS
=
new
CopyOnWriteArrayList
<>();
@Autowired
ISysUserService
sysUserService
;
/**
* 每次登录时触发
*/
@Override
public
void
doLogin
(
String
loginType
,
Object
loginId
,
SaLoginModel
loginModel
)
{
UserAgent
requestUserAgent
=
HttpServletRequestUtil
.
getRequestUserAgent
();
String
cityInfo
=
IP2CityUtil
.
getCityInfo
(
HttpServletRequestUtil
.
getRemoteIP
());
String
[]
split
=
cityInfo
.
split
(
"\\|"
);
ONLINE_USERS
.
add
(
OnlineUser
.
builder
()
.
ip
(
HttpServletRequestUtil
.
getRemoteIP
())
.
city
(
StrUtil
.
format
(
"{}.{}.{}"
,
split
[
0
],
split
[
2
],
split
[
3
]))
.
loginTime
(
new
Date
())
.
os
(
requestUserAgent
.
getOs
().
getName
())
.
userId
((
Long
)
loginId
)
.
tokenValue
(
StpUtil
.
getTokenValue
())
.
nickName
(
sysUserService
.
getById
((
Long
)
loginId
).
getNickName
())
.
browser
(
requestUserAgent
.
getBrowser
().
getName
()).
build
());
log
.
info
(
"user doLogin,useId:{},token:{}"
,
loginId
,
StpUtil
.
getTokenValue
());
}
/**
* 每次注销时触发
*/
@Override
public
void
doLogout
(
String
loginType
,
Object
loginId
,
String
tokenValue
)
{
// ...
ONLINE_USERS
.
removeIf
(
onlineUser
->
onlineUser
.
getTokenValue
().
equals
(
tokenValue
)
);
log
.
info
(
"user doLogout,useId:{},token:{}"
,
loginId
,
tokenValue
);
}
/**
* 每次被踢下线时触发
*/
@Override
public
void
doLogoutByLoginId
(
String
loginType
,
Object
loginId
,
String
tokenValue
,
String
device
)
{
// ...
ONLINE_USERS
.
removeIf
(
onlineUser
->
onlineUser
.
getTokenValue
().
equals
(
tokenValue
)
);
log
.
info
(
"user doLogoutByLoginId,useId:{},token:{}"
,
loginId
,
tokenValue
);
}
/**
* 每次被顶下线时触发
*/
@Override
public
void
doReplaced
(
String
loginType
,
Object
loginId
,
String
tokenValue
,
String
device
)
{
ONLINE_USERS
.
removeIf
(
onlineUser
->
onlineUser
.
getTokenValue
().
equals
(
tokenValue
)
);
log
.
info
(
"user doReplaced,useId:{},token:{}"
,
loginId
,
tokenValue
);
}
/**
* 每次被封禁时触发
*/
@Override
public
void
doDisable
(
String
loginType
,
Object
loginId
,
long
disableTime
)
{
// ...
}
/**
* 每次被解封时触发
*/
@Override
public
void
doUntieDisable
(
String
loginType
,
Object
loginId
)
{
// ...
}
/**
* 每次创建Session时触发
*/
@Override
public
void
doCreateSession
(
String
id
)
{
// ...
}
/**
* 每次注销Session时触发
*/
@Override
public
void
doLogoutSession
(
String
id
)
{
// ...
}
}
src/main/java/com/laker/admin/framework/ext/satoken/OnlineUser.java
0 → 100644
浏览文件 @
f57cfdb9
package
com.laker.admin.framework.ext.satoken
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.Builder
;
import
lombok.Data
;
import
java.util.Date
;
@Data
@Builder
public
class
OnlineUser
{
private
String
loginId
;
private
Long
userId
;
private
String
nickName
;
private
String
ip
;
private
String
os
;
private
String
city
;
private
String
browser
;
private
String
tokenValue
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
loginTime
;
}
src/main/java/com/laker/admin/module/sys/controller/LoginController.java
浏览文件 @
f57cfdb9
package
com.laker.admin.module.sys.controller
;
import
cn.dev33.satoken.annotation.SaCheckLogin
;
import
cn.dev33.satoken.annotation.SaCheckPermission
;
import
cn.dev33.satoken.stp.StpUtil
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.util.StrUtil
;
...
...
@@ -9,10 +10,13 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import
com.github.xiaoymin.knife4j.annotations.ApiOperationSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.laker.admin.framework.EasyAdminConstants
;
import
com.laker.admin.framework.PageDtoUtil
;
import
com.laker.admin.framework.PageResponse
;
import
com.laker.admin.framework.Response
;
import
com.laker.admin.framework.aop.Metrics
;
import
com.laker.admin.framework.cache.ICache
;
import
com.laker.admin.framework.ext.mybatis.UserInfoAndPowers
;
import
com.laker.admin.framework.ext.satoken.MySaTokenListener
;
import
com.laker.admin.module.sys.entity.SysRole
;
import
com.laker.admin.module.sys.entity.SysUser
;
import
com.laker.admin.module.sys.entity.SysUserRole
;
...
...
@@ -24,11 +28,9 @@ import io.swagger.annotations.ApiOperation;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.stream.Collectors
;
...
...
@@ -101,6 +103,31 @@ public class LoginController {
return
Response
.
ok
(
sysUserService
.
getById
(
StpUtil
.
getLoginIdAsLong
()));
}
@GetMapping
(
"/api/v1/onlineUsers"
)
@ApiOperationSupport
(
order
=
2
)
@ApiOperation
(
value
=
"获取在线用户信息"
)
public
PageResponse
onlineUsers
(
@RequestParam
(
required
=
false
,
defaultValue
=
"1"
)
int
page
,
@RequestParam
(
required
=
false
,
defaultValue
=
"10"
)
int
limit
)
{
List
<
String
>
sessionIds
=
StpUtil
.
searchTokenValue
(
null
,
-
1
,
1000
);
log
.
info
(
"当前用户:{}"
,
Arrays
.
toString
(
sessionIds
.
toArray
()));
PageDtoUtil
pageDto
=
PageDtoUtil
.
getPageDto
(
MySaTokenListener
.
ONLINE_USERS
,
page
,
limit
);
log
.
warn
(
"stp用户数:{},memory用户数:{}"
,
sessionIds
.
size
(),
pageDto
.
getTotal
());
return
PageResponse
.
ok
(
pageDto
.
getPageList
(),
(
long
)
pageDto
.
getTotal
());
}
@GetMapping
(
"/api/v1/kickOffline"
)
@ApiOperationSupport
(
order
=
2
)
@ApiOperation
(
value
=
"踢人下线"
)
@SaCheckPermission
(
"online.user.kick"
)
public
Response
kickOffline
(
String
token
)
{
log
.
info
(
"踢人下线,token:{}"
,
token
);
if
(
StpUtil
.
getTokenValue
().
equals
(
token
))
{
return
Response
.
error
(
"500"
,
"不能踢自己啊老弟"
);
}
StpUtil
.
logoutByTokenValue
(
token
);
return
Response
.
ok
();
}
@GetMapping
(
"/api/v1/loginOut"
)
@ApiOperationSupport
(
order
=
3
)
@ApiOperation
(
value
=
"登出"
)
...
...
src/main/resources/application.yaml
浏览文件 @
f57cfdb9
...
...
@@ -41,15 +41,17 @@ sa-token:
# token名称 (同时也是cookie名称)
token-name
:
LakerToken
# token有效期,单位s 默认30天, -1代表永不过期
#
timeout: 1800
# token临时有效期
(指定时间内无操作就视为token过期) 单位: 秒
# activity-timeout: 30
00
# timeout: 1800
# token临时有效期
[指定时间内无操作就视为token过期] (单位: 秒), 默认-1 代表不限制
activity-timeout
:
18
00
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
allow-concurrent-login
:
true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share
:
false
# token风格
token-style
:
simple-uuid
# 是否打印操作日志
is-log
:
false
video
:
url
:
http://1.1.1.1
admin
:
...
...
web/admin/view/system/onlineUser.html
0 → 100644
浏览文件 @
f57cfdb9
<!DOCTYPE html>
<html>
<head>
<meta
charset=
"utf-8"
>
<title>
日志
</title>
<link
href=
"../../component/pear/css/pear.css"
rel=
"stylesheet"
/>
</head>
<body
class=
"pear-container"
>
<div
class=
"layui-card"
>
<div
class=
"layui-card-body"
>
<form
class=
"layui-form"
action=
""
>
<div
class=
"layui-form-item"
>
<label
class=
"layui-form-label"
>
关键字
</label>
<div
class=
"layui-input-inline"
>
<input
type=
"text"
name=
"keyWord"
placeholder=
""
class=
"layui-input"
>
</div>
<button
class=
"pear-btn pear-btn-md pear-btn-primary"
lay-submit
lay-filter=
"dict-type-query"
>
<i
class=
"layui-icon layui-icon-search"
></i>
查询
</button>
<button
type=
"reset"
class=
"pear-btn pear-btn-md"
>
<i
class=
"layui-icon layui-icon-refresh"
></i>
重置
</button>
</div>
</form>
</div>
</div>
<div
class=
"layui-card"
>
<div
class=
"layui-card-body"
>
<table
id=
"table"
lay-filter=
"table-filter"
></table>
</div>
</div>
</body>
<script
type=
"text/html"
id=
"record-toolbar"
>
<
button
class
=
"
pear-btn pear-btn-danger pear-btn-sm
"
lay
-
event
=
"
kick
"
>
<
i
class
=
"
layui-icon layui-icon-delete
"
>
踢人
<
/i
>
<
/button
>
</script>
<script
src=
"../../component/layui/layui.js"
></script>
<script
src=
"../../component/pear/pear.js"
></script>
<script>
layui
.
use
([
'
easyAdmin
'
,
'
table
'
],
function
()
{
let
easyAdmin
=
layui
.
easyAdmin
;
let
table
=
layui
.
table
;
let
cols
=
[
[
{
title
:
'
用户
'
,
field
:
'
nickName
'
,
align
:
'
center
'
},
{
title
:
'
城市
'
,
field
:
'
city
'
,
align
:
'
center
'
},
{
title
:
'
操作系统
'
,
field
:
'
os
'
,
align
:
'
center
'
},
{
title
:
'
浏览器
'
,
field
:
'
browser
'
,
align
:
'
center
'
},
{
title
:
'
请求IP
'
,
field
:
'
ip
'
,
align
:
'
center
'
},
{
title
:
'
访问时间
'
,
field
:
'
loginTime
'
,
align
:
'
center
'
}
,
{
title
:
'
操作
'
,
field
:
'
loginTime
'
,
align
:
'
center
'
,
templet
:
'
#record-toolbar
'
}
]
]
;
let
module
=
"
log
"
;
easyAdmin
.
tableRender
({
url
:
"
/api/v1/onlineUsers
"
,
cols
:
cols
,
toolbar
:
null
,
defaultToolbar
:
null
});
table
.
on
(
'
tool(table-filter)
'
,
function
(
obj
)
{
if
(
obj
.
event
===
'
kick
'
)
{
easyAdmin
.
httpGet
(
"
/api/v1/kickOffline?token=
"
+
obj
.
data
.
tokenValue
,
function
(
result
)
{
if
(
result
.
success
)
{
layer
.
msg
(
"
踢人成功
"
,
{
icon
:
1
,
area
:
[
'
100px
'
,
'
65px
'
],
time
:
1000
},
function
()
{
table
.
reload
(
'
table
'
);
});
}
else
{
layer
.
msg
(
result
.
msg
,
{
icon
:
2
,
area
:
[
'
300px
'
,
'
65px
'
],
time
:
2000
});
}
});
}
});
easyAdmin
.
FormQuery
();
})
</script>
</html>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录