Compare commits
33 Commits
dev-cloud-
...
dev-hzm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccfdd18516 | ||
|
|
c724387a16 | ||
|
|
ced025e292 | ||
|
|
37e264491f | ||
|
|
be4adbe00b | ||
| 33fc749363 | |||
|
|
eb5978eb9d | ||
|
|
db7dbcc97e | ||
|
|
cba659010a | ||
| 0a8c05e1df | |||
|
|
7a961d63a6 | ||
|
|
16779413a6 | ||
|
|
c0c2e492b8 | ||
|
|
023d35fecd | ||
| 895ae7383a | |||
|
|
0d12345ed4 | ||
| e6c1041202 | |||
| d7b36d9f59 | |||
| fb81670776 | |||
| f22189bc00 | |||
|
|
74d030a97e | ||
|
|
609bef8a87 | ||
| 0fa91a472d | |||
|
|
bdd3f251a2 | ||
| 4a0b1499c7 | |||
| 74064a4dc4 | |||
| 4c4f1acf32 | |||
|
|
92246a6767 | ||
|
|
6419f88c63 | ||
|
|
eee546fcc4 | ||
| 714b759050 | |||
|
|
2d3024b3e7 | ||
|
|
8b79ae515d |
@@ -14,11 +14,20 @@
|
||||
<artifactId>wol-common-web</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-system-base</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-module-ai</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-satoken</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
70
agileboot-boot-start/src/main/resources/application-dev.yml
Normal file
70
agileboot-boot-start/src/main/resources/application-dev.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: agileboot
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
dynamic:
|
||||
primary: master
|
||||
strict: false
|
||||
druid:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
datasource:
|
||||
master:
|
||||
url: jdbc:mysql://121.41.64.98:3306/agileboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&sslMode=REQUIRED
|
||||
username: agileboot
|
||||
password: 123456
|
||||
|
||||
data:
|
||||
redis:
|
||||
database: 3
|
||||
host: 121.41.64.98
|
||||
port: 6379
|
||||
password: 'Wyy123123'
|
||||
|
||||
|
||||
sa-token:
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
token-name: Authorization
|
||||
jasypt:
|
||||
encryptor:
|
||||
password: ${JASYPT_ENCRYPTOR_PASSWORD:}
|
||||
@@ -1,4 +1,13 @@
|
||||
server:
|
||||
port: 8080
|
||||
port: 8088
|
||||
servlet:
|
||||
context-path: /api
|
||||
context-path: /api
|
||||
tomcat:
|
||||
uri-encoding: UTF-8 # tomcat的URI编码
|
||||
accept-count: 1000 # 连接数满后的排队数,默认为100
|
||||
threads:
|
||||
max: 800 # tomcat最大线程数,默认为200
|
||||
min-spare: 100 # Tomcat启动初始化的线程数,默认值10
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
@@ -17,6 +17,7 @@
|
||||
<module>wol-common-mybatis</module>
|
||||
<module>wol-common-redis</module>
|
||||
<module>wol-common-json</module>
|
||||
<module>wol-common-satoken</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@
|
||||
<artifactId>wol-common-json</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-satoken</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -85,7 +85,16 @@
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
<!--ENC加密-->
|
||||
<dependency>
|
||||
<groupId>com.github.ulisesbocchio</groupId>
|
||||
<artifactId>jasypt-spring-boot-starter</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- swagger注解 -->
|
||||
<dependency>
|
||||
|
||||
@@ -45,11 +45,13 @@ public interface Constants {
|
||||
* 通用成功标识
|
||||
*/
|
||||
String SUCCESS = "0";
|
||||
String NORMAL = "0"; // 正常状态
|
||||
|
||||
/**
|
||||
* 通用失败标识
|
||||
*/
|
||||
String FAIL = "1";
|
||||
String DISABLE = "1"; // 异常/停用状态
|
||||
|
||||
/**
|
||||
* 登录成功
|
||||
@@ -80,6 +82,45 @@ public interface Constants {
|
||||
* 顶级部门id
|
||||
*/
|
||||
Long TOP_PARENT_ID = 0L;
|
||||
/**
|
||||
* 超级管理员ID
|
||||
*/
|
||||
Long SUPER_ADMIN_ID = 1L;
|
||||
/**
|
||||
* 超级管理员角色 roleKey
|
||||
*/
|
||||
String SUPER_ADMIN_ROLE_KEY = "superadmin";
|
||||
|
||||
/**
|
||||
* 租户管理员角色 roleKey
|
||||
*/
|
||||
String TENANT_ADMIN_ROLE_KEY = "admin";
|
||||
|
||||
/**
|
||||
* 租户管理员角色名称
|
||||
*/
|
||||
String TENANT_ADMIN_ROLE_NAME = "管理员";
|
||||
|
||||
/**
|
||||
* 默认租户ID
|
||||
*/
|
||||
String DEFAULT_TENANT_ID = "000000";
|
||||
|
||||
interface Cache {
|
||||
/**
|
||||
* 全局 redis key (业务无关的key)
|
||||
*/
|
||||
String GLOBAL_REDIS_KEY = "global:";
|
||||
|
||||
/**
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public interface BasicEnum<T>{
|
||||
* 获取枚举的描述
|
||||
* @return 描述
|
||||
*/
|
||||
String description();
|
||||
String getDesc();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.agileboot.common.core.enums;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.agileboot.common.core.exception.ApiException;
|
||||
import com.agileboot.common.core.exception.error.ErrorCode;
|
||||
import com.agileboot.common.core.enums.BasicEnum;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -55,7 +54,7 @@ public class BasicEnumUtil {
|
||||
public static <E extends Enum<E>> String getDescriptionByValue(Class<E> enumClass, Object value) {
|
||||
E basicEnum = fromValueSafely(enumClass, value);
|
||||
if (basicEnum != null) {
|
||||
return ((BasicEnum<?>) basicEnum).description();
|
||||
return ((BasicEnum<?>) basicEnum).getDesc();
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ public interface DictionaryEnum<T> extends BasicEnum<T> {
|
||||
* 获取css标签
|
||||
* @return css标签
|
||||
*/
|
||||
String cssTag();
|
||||
String getCssTag();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.agileboot.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 登录类型
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginType {
|
||||
|
||||
/**
|
||||
* 密码登录
|
||||
*/
|
||||
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
|
||||
|
||||
/**
|
||||
* 短信登录
|
||||
*/
|
||||
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
|
||||
|
||||
/**
|
||||
* 邮箱登录
|
||||
*/
|
||||
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
XCX("", "");
|
||||
|
||||
/**
|
||||
* 登录重试超出限制提示
|
||||
*/
|
||||
final String retryLimitExceed;
|
||||
|
||||
/**
|
||||
* 登录重试限制计数提示
|
||||
*/
|
||||
final String retryLimitCount;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.agileboot.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum UserType {
|
||||
|
||||
/**
|
||||
* 后台系统用户
|
||||
*/
|
||||
SYS_USER("sys_user"),
|
||||
|
||||
/**
|
||||
* 移动客户端用户
|
||||
*/
|
||||
APP_USER("app_user");
|
||||
|
||||
/**
|
||||
* 用户类型标识(用于 token、权限识别等)
|
||||
*/
|
||||
private final String userType;
|
||||
|
||||
public static UserType getUserType(String str) {
|
||||
for (UserType value : values()) {
|
||||
if (StringUtils.contains(str, value.getUserType())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("'UserType' not found By " + str);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,16 @@ package com.agileboot.common.core.enums.common;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_operation_log的business_type
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@Dictionary(name = "sysOperationLog.businessType")
|
||||
public enum BusinessTypeEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
@@ -26,29 +30,7 @@ public enum BusinessTypeEnum implements DictionaryEnum<Integer> {
|
||||
CLEAN(8, "清空", CssTag.DANGER),
|
||||
;
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
BusinessTypeEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_user的sex字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@Dictionary(name = "sysUser.sex")
|
||||
public enum GenderEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
@@ -19,29 +23,7 @@ public enum GenderEnum implements DictionaryEnum<Integer> {
|
||||
FEMALE(2, "女", CssTag.PRIMARY),
|
||||
UNKNOWN(0, "未知", CssTag.PRIMARY);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
GenderEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 用户状态
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
// TODO 表记得改成LoginLog
|
||||
@Dictionary(name = "sysLoginLog.status")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginStatusEnum implements DictionaryEnum<Integer> {
|
||||
/**
|
||||
* status of user
|
||||
@@ -19,28 +24,7 @@ public enum LoginStatusEnum implements DictionaryEnum<Integer> {
|
||||
REGISTER(3, "注册", CssTag.PRIMARY),
|
||||
LOGIN_FAIL(0, "登录失败", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String msg;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
LoginStatusEnum(int status, String msg, String cssTag) {
|
||||
this.value = status;
|
||||
this.msg = msg;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.BasicEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Deprecated
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum MenuComponentEnum implements BasicEnum<Integer> {
|
||||
|
||||
/**
|
||||
* 菜单组件类型
|
||||
*/
|
||||
LAYOUT(1,"Layout"),
|
||||
PARENT_VIEW(2,"ParentView"),
|
||||
INNER_LINK(3,"InnerLink");
|
||||
LAYOUT(1, "Layout"),
|
||||
PARENT_VIEW(2, "ParentView"),
|
||||
INNER_LINK(3, "InnerLink");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
|
||||
MenuComponentEnum(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.BasicEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
* 对应 sys_menu表的menu_type字段
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum MenuTypeEnum implements BasicEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -16,23 +20,7 @@ public enum MenuTypeEnum implements BasicEnum<Integer> {
|
||||
IFRAME(3, "内嵌Iframe"),
|
||||
OUTSIDE_LINK_REDIRECT(4, "外链跳转");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
MenuTypeEnum(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_notice的 status字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Dictionary(name = "sysNotice.status")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum NoticeStatusEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -17,29 +22,8 @@ public enum NoticeStatusEnum implements DictionaryEnum<Integer> {
|
||||
OPEN(1, "正常", CssTag.PRIMARY),
|
||||
CLOSE(0, "关闭", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
NoticeStatusEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_notice的 notice_type字段
|
||||
* 名称一般由对应的表名.字段构成
|
||||
* 全局的话使用common作为表名
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Dictionary(name = "sysNotice.noticeType")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum NoticeTypeEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -19,29 +24,16 @@ public enum NoticeTypeEnum implements DictionaryEnum<Integer> {
|
||||
NOTIFICATION(1, "通知", CssTag.WARNING),
|
||||
ANNOUNCEMENT(2, "公告", CssTag.SUCCESS);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
NoticeTypeEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
public static Integer getDescByValue(Integer value) {
|
||||
for (NoticeTypeEnum item : values()) {
|
||||
if (item.value.equals(value)) {
|
||||
return item.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_operation_log的status字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Dictionary(name = "sysOperationLog.status")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OperationStatusEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -17,29 +22,8 @@ public enum OperationStatusEnum implements DictionaryEnum<Integer> {
|
||||
SUCCESS(1, "成功", CssTag.PRIMARY),
|
||||
FAIL(0, "失败", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
OperationStatusEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.BasicEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 操作者类型
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@Dictionary(name = "sysOperationLog.operatorType")
|
||||
public enum OperatorTypeEnum implements BasicEnum<Integer> {
|
||||
|
||||
@@ -17,23 +22,8 @@ public enum OperatorTypeEnum implements BasicEnum<Integer> {
|
||||
WEB(2, "Web用户"),
|
||||
MOBILE(3, "手机端用户");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
OperatorTypeEnum(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.BasicEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Http Method
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RequestMethodEnum implements BasicEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -17,23 +22,8 @@ public enum RequestMethodEnum implements BasicEnum<Integer> {
|
||||
DELETE(4, "DELETE"),
|
||||
UNKNOWN(-1, "UNKNOWN");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
RequestMethodEnum(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 除非表有特殊指明的话,一般用这个枚举代表 status字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Dictionary(name = "common.status")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum StatusEnum implements DictionaryEnum<Integer> {
|
||||
/**
|
||||
* 开关状态
|
||||
@@ -16,29 +21,17 @@ public enum StatusEnum implements DictionaryEnum<Integer> {
|
||||
ENABLE(1, "正常", CssTag.PRIMARY),
|
||||
DISABLE(0, "停用", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
StatusEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
public static Integer getDescByValue(Integer value) {
|
||||
for (StatusEnum item : StatusEnum.values()) {
|
||||
if (item.value.equals(value)) {
|
||||
return item.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_user的status字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Dictionary(name = "sysUser.status")
|
||||
public enum UserStatusEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
@@ -18,32 +23,7 @@ public enum UserStatusEnum implements DictionaryEnum<Integer> {
|
||||
DISABLED(2, "禁用", CssTag.DANGER),
|
||||
FROZEN(3, "冻结", CssTag.WARNING);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
UserStatusEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.agileboot.common.core.enums.common;
|
||||
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 对应sys_menu表的is_visible字段
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Deprecated
|
||||
@Dictionary(name = "sysMenu.isVisible")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum VisibleStatusEnum implements DictionaryEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -18,29 +23,8 @@ public enum VisibleStatusEnum implements DictionaryEnum<Integer> {
|
||||
SHOW(1, "显示", CssTag.PRIMARY),
|
||||
HIDE(0, "隐藏", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
VisibleStatusEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,17 @@ package com.agileboot.common.core.enums.common;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.dictionary.CssTag;
|
||||
import com.agileboot.common.core.enums.dictionary.Dictionary;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 系统内代表是与否的枚举
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Dictionary(name = "common.yesOrNo")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum YesOrNoEnum implements DictionaryEnum<Integer> {
|
||||
/**
|
||||
* 是与否
|
||||
@@ -16,31 +21,8 @@ public enum YesOrNoEnum implements DictionaryEnum<Integer> {
|
||||
YES(1, "是", CssTag.PRIMARY),
|
||||
NO(0, "否", CssTag.DANGER);
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
private final String cssTag;
|
||||
|
||||
YesOrNoEnum(int value, String description, String cssTag) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.cssTag = cssTag;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String cssTag() {
|
||||
return cssTag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.agileboot.common.core.enums.dictionary;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.agileboot.common.core.enums.DictionaryEnum;
|
||||
import com.agileboot.common.core.enums.common.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 本地一级缓存 使用Map
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class DictCache {
|
||||
|
||||
private static final Map<String, List<DictionaryData>> DICTIONARY_CACHE = MapUtil.newHashMap(128);
|
||||
|
||||
private DictCache() {
|
||||
}
|
||||
|
||||
static {
|
||||
initDictionaryCache();
|
||||
}
|
||||
|
||||
private static void initDictionaryCache() {
|
||||
// TODO 这个可以做成自动扫描
|
||||
loadInCache(BusinessTypeEnum.values());
|
||||
loadInCache(YesOrNoEnum.values());
|
||||
loadInCache(StatusEnum.values());
|
||||
loadInCache(GenderEnum.values());
|
||||
loadInCache(NoticeStatusEnum.values());
|
||||
loadInCache(NoticeTypeEnum.values());
|
||||
loadInCache(OperationStatusEnum.values());
|
||||
loadInCache(LoginStatusEnum.values());
|
||||
loadInCache(VisibleStatusEnum.values());
|
||||
loadInCache(UserStatusEnum.values());
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, List<DictionaryData>> dictionaryCache() {
|
||||
return DICTIONARY_CACHE;
|
||||
}
|
||||
|
||||
private static void loadInCache(DictionaryEnum[] dictionaryEnums) {
|
||||
DICTIONARY_CACHE.put(getDictionaryName(dictionaryEnums[0].getClass()), arrayToList(dictionaryEnums));
|
||||
}
|
||||
|
||||
|
||||
private static String getDictionaryName(Class<?> clazz) {
|
||||
Objects.requireNonNull(clazz);
|
||||
Dictionary annotation = clazz.getAnnotation(Dictionary.class);
|
||||
|
||||
Objects.requireNonNull(annotation);
|
||||
return annotation.name();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<DictionaryData> arrayToList(DictionaryEnum[] dictionaryEnums) {
|
||||
if(ArrayUtil.isEmpty(dictionaryEnums)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
return Arrays.stream(dictionaryEnums).map(DictionaryData::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -17,9 +17,9 @@ public class DictionaryData {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public DictionaryData(DictionaryEnum enumType) {
|
||||
if (enumType != null) {
|
||||
this.label = enumType.description();
|
||||
this.label = enumType.getDesc();
|
||||
this.value = (Integer) enumType.getValue();
|
||||
this.cssTag = enumType.cssTag();
|
||||
this.cssTag = enumType.getCssTag();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.agileboot.common.core.exception;
|
||||
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import com.agileboot.common.core.exception.error.ErrorCodeInterface;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -34,6 +35,11 @@ public class BizException extends RuntimeException {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public BizException(ErrorCodeInterface errorCode) {
|
||||
this.code = errorCode.code();
|
||||
this.message = errorCode.message();
|
||||
}
|
||||
|
||||
public BizException(String message, Integer code) {
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
@@ -42,4 +48,8 @@ public class BizException extends RuntimeException {
|
||||
public BizException(String message, Object... args) {
|
||||
this.message = StrFormatter.format(message, args);
|
||||
}
|
||||
|
||||
public BizException(ErrorCodeInterface errorCode, Object... args) {
|
||||
this.message = StrFormatter.format(errorCode.message(), args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ public enum ErrorCode implements ErrorCodeInterface {
|
||||
|
||||
ROLE_DATA_SCOPE_DUPLICATED_DEPT(11003, "重复的部门id", "Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT"),
|
||||
|
||||
ROLE_ALREADY_ASSIGN_TO_USER(11004, "角色已分配给用户,请先取消分配,再删除角色", "Business.ROLE_ALREADY_ASSIGN_TO_USER"),
|
||||
ROLE_ALREADY_ASSIGN_TO_USER(11004, "角色:{} 已分配给用户,请先取消分配,再删除角色", "Business.ROLE_ALREADY_ASSIGN_TO_USER"),
|
||||
|
||||
ROLE_IS_NOT_AVAILABLE(11005, "角色:{} 已禁用,无法分配给用户", "Business.ROLE_IS_NOT_AVAILABLE"),
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.agileboot.common.core.utils;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import jakarta.validation.Validator;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Validator 校验框架工具
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ValidatorUtils {
|
||||
|
||||
private static final Validator VALID = SpringUtil.getBean(Validator.class);
|
||||
|
||||
/**
|
||||
* 对给定对象进行参数校验,并根据指定的校验组进行校验
|
||||
*
|
||||
* @param object 要进行校验的对象
|
||||
* @param groups 校验组
|
||||
* @throws ConstraintViolationException 如果校验不通过,则抛出参数校验异常
|
||||
*/
|
||||
public static <T> void validate(T object, Class<?>... groups) {
|
||||
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
|
||||
if (!validate.isEmpty()) {
|
||||
throw new ConstraintViolationException("参数校验异常", validate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,6 +20,29 @@
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.20</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-satoken</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.agileboot.common.mybatis.config;
|
||||
|
||||
import com.agileboot.common.core.factory.YmlPropertySourceFactory;
|
||||
import com.agileboot.common.mybatis.handler.InjectionMetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -16,9 +20,23 @@ public class MybatisPlusConfiguration {
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 分页插件 自动识别数据库类型
|
||||
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
|
||||
paginationInnerInterceptor.setOverflow(true); // 超出总页数后回到首页
|
||||
interceptor.addInnerInterceptor(paginationInnerInterceptor);
|
||||
// 乐观锁插件
|
||||
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
|
||||
// 阻止恶意的全表更新删除
|
||||
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 元对象字段填充控制器
|
||||
*/
|
||||
@Bean
|
||||
public MetaObjectHandler metaObjectHandler() {
|
||||
return new InjectionMetaObjectHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.agileboot.common.mybatis.core.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
@@ -33,8 +32,8 @@ public class BaseEntity implements Serializable {
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createDept;
|
||||
// @TableField(fill = FieldFill.INSERT)
|
||||
// private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
@@ -60,6 +59,10 @@ public class BaseEntity implements Serializable {
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Integer deleted;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.agileboot.common.mybatis.core.page;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.exception.ServiceException;
|
||||
import com.agileboot.common.core.utils.sql.SqlUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -24,45 +26,42 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PageQuery implements Serializable {
|
||||
public abstract class PageQuery<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int MAX_PAGE_NUM = 200; // 最大分页页数
|
||||
public static final int MAX_PAGE_SIZE = 500; // 单页最大大小
|
||||
public static final int DEFAULT_PAGE_NUM = 1; // 默认分页页数
|
||||
public static final int DEFAULT_PAGE_SIZE = 10; // 默认分页大小
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private Integer pageSize;
|
||||
@Max(MAX_PAGE_SIZE)
|
||||
protected Integer pageSize;
|
||||
|
||||
/**
|
||||
* 当前页数
|
||||
*/
|
||||
private Integer pageNum;
|
||||
@Max(MAX_PAGE_NUM)
|
||||
protected Integer pageNum;
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
private String orderByColumn;
|
||||
protected String orderByColumn;
|
||||
|
||||
/**
|
||||
* 排序的方向desc或者asc
|
||||
*/
|
||||
private String isAsc;
|
||||
|
||||
/**
|
||||
* 当前记录起始索引 默认值
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_NUM = 1;
|
||||
|
||||
/**
|
||||
* 每页显示记录数 默认值 默认查全部
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
|
||||
protected String isAsc = "desc";
|
||||
|
||||
/**
|
||||
* 构建分页对象
|
||||
*/
|
||||
public <T> Page<T> build() {
|
||||
public <T> Page<T> toPage() {
|
||||
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
|
||||
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
|
||||
if (pageNum <= 0) {
|
||||
@@ -70,7 +69,7 @@ public class PageQuery implements Serializable {
|
||||
}
|
||||
Page<T> page = new Page<>(pageNum, pageSize);
|
||||
List<OrderItem> orderItems = buildOrderItem();
|
||||
if (CollUtil.isNotEmpty(orderItems)) {
|
||||
if (CollectionUtils.isNotEmpty(orderItems)) {
|
||||
page.addOrder(orderItems);
|
||||
}
|
||||
return page;
|
||||
@@ -127,4 +126,5 @@ public class PageQuery implements Serializable {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
public abstract LambdaQueryWrapper<T> toQueryWrapper();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.agileboot.common.mybatis.core.page;
|
||||
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页模型类
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class PageR<T> {
|
||||
private List<T> rows; // 列表数据
|
||||
private Long total; // 总记录数
|
||||
private Long current; // 当前页数
|
||||
private Long size; // 每页记录数
|
||||
private Long pages; // 总页数
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
|
||||
public PageR() {
|
||||
this.code = HttpStatus.HTTP_OK;
|
||||
this.msg = "查询成功";
|
||||
this.total = 0L;
|
||||
this.current = 0L;
|
||||
this.size = 0L;
|
||||
this.pages = 0L;
|
||||
}
|
||||
|
||||
public PageR(List<T> list) {
|
||||
this.code = HttpStatus.HTTP_OK;
|
||||
this.rows = list;
|
||||
this.total = (long) list.size();
|
||||
this.msg = "查询成功";
|
||||
}
|
||||
|
||||
public PageR(IPage<T> page) {
|
||||
this.code = HttpStatus.HTTP_OK;
|
||||
this.msg = "查询成功";
|
||||
this.rows = page.getRecords();
|
||||
this.total = page.getTotal();
|
||||
this.current = page.getCurrent();
|
||||
this.size = page.getSize();
|
||||
this.pages = page.getPages();
|
||||
}
|
||||
|
||||
public PageR(IPage<?> page, List<T> list) {
|
||||
this.code = HttpStatus.HTTP_OK;
|
||||
this.msg = "查询成功";
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
this.total = 0L;
|
||||
this.current = 0L;
|
||||
this.size = 0L;
|
||||
this.pages = 0L;
|
||||
} else {
|
||||
this.rows = list;
|
||||
this.total = page.getTotal();
|
||||
this.current = page.getCurrent();
|
||||
this.size = page.getSize();
|
||||
this.pages = page.getPages();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package com.agileboot.common.mybatis.core.page;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表格分页数据对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TableDataInfo<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private long total;
|
||||
|
||||
/**
|
||||
* 列表数据
|
||||
*/
|
||||
private List<T> rows;
|
||||
|
||||
/**
|
||||
* 消息状态码
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*
|
||||
* @param list 列表数据
|
||||
* @param total 总记录数
|
||||
*/
|
||||
public TableDataInfo(List<T> list, long total) {
|
||||
this.rows = list;
|
||||
this.total = total;
|
||||
this.code = HttpStatus.HTTP_OK;
|
||||
this.msg = "查询成功";
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分页对象构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build(IPage<T> page) {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
rspData.setCode(HttpStatus.HTTP_OK);
|
||||
rspData.setMsg("查询成功");
|
||||
rspData.setRows(page.getRecords());
|
||||
rspData.setTotal(page.getTotal());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据列表构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build(List<T> list) {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
rspData.setCode(HttpStatus.HTTP_OK);
|
||||
rspData.setMsg("查询成功");
|
||||
rspData.setRows(list);
|
||||
rspData.setTotal(list.size());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build() {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
rspData.setCode(HttpStatus.HTTP_OK);
|
||||
rspData.setMsg("查询成功");
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据原始数据列表和分页参数,构建表格分页数据对象(用于假分页)
|
||||
*
|
||||
* @param list 原始数据列表(全部数据)
|
||||
* @param page 分页参数对象(包含当前页码、每页大小等)
|
||||
* @return 构造好的分页结果 TableDataInfo<T>
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build(List<T> list, IPage<T> page) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
List<T> pageList = CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), list);
|
||||
return new TableDataInfo<>(pageList, list.size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.agileboot.common.mybatis.handler;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.mybatis.core.domain.BaseEntity;
|
||||
import com.agileboot.common.satoken.pojo.LoginUser;
|
||||
import com.agileboot.common.satoken.utils.LoginHelper;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MP注入处理器
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
/**
|
||||
* 如果用户不存在默认注入-1代表无用户
|
||||
*/
|
||||
private static final Long DEFAULT_USER_ID = -1L;
|
||||
|
||||
/**
|
||||
* 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息
|
||||
*
|
||||
* @param metaObject 元对象,用于获取原始对象并进行填充
|
||||
*/
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
try {
|
||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||
Date current = ObjectUtils.defaultIfNull(baseEntity.getCreateTime(), new Date());
|
||||
baseEntity.setCreateTime(current);
|
||||
baseEntity.setUpdateTime(current);
|
||||
baseEntity.setDeleted(0);
|
||||
|
||||
// 如果创建人为空,则填充当前登录用户的信息
|
||||
if (ObjectUtil.isNull(baseEntity.getCreateBy())) {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (ObjectUtil.isNotNull(loginUser)) {
|
||||
Long userId = loginUser.getUserId();
|
||||
// 填充创建人、更新人和创建部门信息
|
||||
baseEntity.setCreateBy(userId);
|
||||
baseEntity.setUpdateBy(userId);
|
||||
} else {
|
||||
// 填充创建人、更新人和创建部门信息
|
||||
baseEntity.setCreateBy(DEFAULT_USER_ID);
|
||||
baseEntity.setUpdateBy(DEFAULT_USER_ID);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Date date = new Date();
|
||||
this.strictInsertFill(metaObject, "createTime", Date.class, date);
|
||||
this.strictInsertFill(metaObject, "updateTime", Date.class, date);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new BizException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息
|
||||
*
|
||||
* @param metaObject 元对象,用于获取原始对象并进行填充
|
||||
*/
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
try {
|
||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||
// 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充
|
||||
Date current = new Date();
|
||||
baseEntity.setUpdateTime(current);
|
||||
|
||||
// 获取当前登录用户的ID,并填充更新人信息
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (ObjectUtil.isNotNull(userId)) {
|
||||
baseEntity.setUpdateBy(userId);
|
||||
} else {
|
||||
baseEntity.setUpdateBy(DEFAULT_USER_ID);
|
||||
}
|
||||
} else {
|
||||
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new BizException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @return 当前登录用户的信息,如果用户未登录则返回 null
|
||||
*/
|
||||
private LoginUser getLoginUser() {
|
||||
LoginUser loginUser;
|
||||
try {
|
||||
loginUser = LoginHelper.getLoginUser();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
# MyBatisPlus配置
|
||||
# https://baomidou.com/config/
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:com/agileboot/**/mapper/xml/*Mapper.xml
|
||||
mapperPackage: com.agileboot.**.mapper*
|
||||
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查
|
||||
checkConfigLocation: false
|
||||
configuration:
|
||||
@@ -16,11 +18,13 @@ mybatis-plus:
|
||||
# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
|
||||
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
||||
logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
banner: true # 是否打印 Logo banner
|
||||
dbConfig:
|
||||
idType: ASSIGN_ID # 主键类型: AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
|
||||
table-underline: true # 默认数据库表下划线命名
|
||||
logic-delete-field: deleted # 全局逻辑删除字段名
|
||||
logicDeleteValue: 1 # 逻辑已删除值(框架表均使用此值 禁止随意修改)
|
||||
logicNotDeleteValue: 0 # 逻辑未删除值
|
||||
insertStrategy: NOT_NULL
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
|
||||
@@ -42,7 +42,7 @@ public class RedissonConfiguration {
|
||||
@Autowired
|
||||
private RedissonProperties redissonProperties;
|
||||
|
||||
@Bean
|
||||
// @Bean
|
||||
public RedissonAutoConfigurationCustomizer redissonCustomizer() {
|
||||
return config -> {
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
|
||||
45
agileboot-common/wol-common-satoken/pom.xml
Normal file
45
agileboot-common/wol-common-satoken/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>wol-common-satoken</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>${satoken.version}</version>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 jwt -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
<version>${satoken.version}</version>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 RedisTemplate -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-redis-template</artifactId>
|
||||
<version>${satoken.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 提供 Redis 连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.common.satoken.config;
|
||||
|
||||
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import com.agileboot.common.core.factory.YmlPropertySourceFactory;
|
||||
import com.agileboot.common.satoken.handler.SaTokenExceptionHandler;
|
||||
import com.agileboot.common.satoken.service.SaPermissionImpl;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* Sa-Token 配置
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
|
||||
public class SaTokenConfiguration {
|
||||
|
||||
// Sa-Token 整合 jwt (Simple 简单模式)
|
||||
@Bean
|
||||
public StpLogic getStpLogicJwt() {
|
||||
return new StpLogicJwtForSimple();
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限接口实现(使用bean注入方便用户替换)
|
||||
*/
|
||||
@Bean
|
||||
public StpInterface stpInterface() {
|
||||
return new SaPermissionImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义dao层存储
|
||||
*/
|
||||
// @Bean
|
||||
// public SaTokenDao saTokenDao() {
|
||||
// return new PlusSaTokenDao();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
*/
|
||||
@Bean
|
||||
public SaTokenExceptionHandler saTokenExceptionHandler() {
|
||||
return new SaTokenExceptionHandler();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.agileboot.common.satoken.config;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.filter.SaServletFilter;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.same.SaSameUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.agileboot.common.core.constant.HttpStatus;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* 权限安全配置
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class SaTokenMvcConfiguration implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 注册sa-token的拦截器
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册路由拦截器,自定义验证规则
|
||||
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 [Sa-Token全局过滤器]
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingClass("cn.dev33.satoken.reactor.spring.SaTokenContextRegister")
|
||||
public SaServletFilter getGlobleSaServletFilter() {
|
||||
return new SaServletFilter()
|
||||
.addInclude("/**").addExclude("/favicon.ico")
|
||||
.addExclude("/auth/getConfig", "/captcha/code", "/auth/register")
|
||||
.setAuth(obj -> {
|
||||
SaRouter.match("/**", "/auth/login", StpUtil::checkLogin);
|
||||
})
|
||||
.setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否从网关转发
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SaServletFilter.class)
|
||||
public SaServletFilter getSaServletFilter() {
|
||||
return new SaServletFilter()
|
||||
.addInclude("/**")
|
||||
.addExclude("/actuator", "/actuator/**")
|
||||
.setAuth(obj -> {
|
||||
if (SaManager.getConfig().getCheckSameToken()) {
|
||||
SaSameUtil.checkCurrentRequestToken();
|
||||
}
|
||||
})
|
||||
.setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对 actuator 健康检查接口 做账号密码鉴权
|
||||
*/
|
||||
// @Bean
|
||||
// public SaServletFilter actuatorFilter() {
|
||||
// String username = SpringUtil.getProperty("spring.cloud.nacos.discovery.metadata.username");
|
||||
// String password = SpringUtil.getProperty("spring.cloud.nacos.discovery.metadata.userpassword");
|
||||
// return new SaServletFilter()
|
||||
// .addInclude("/actuator", "/actuator/**")
|
||||
// .setAuth(obj -> {
|
||||
// SaHttpBasicUtil.check(username + ":" + password);
|
||||
// })
|
||||
// .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.common.satoken.handler;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.agileboot.common.core.core.R;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* SaToken异常处理器
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class SaTokenExceptionHandler {
|
||||
|
||||
/**
|
||||
* 权限码异常
|
||||
*/
|
||||
@ExceptionHandler(NotPermissionException.class)
|
||||
public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
|
||||
return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权");
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色权限异常
|
||||
*/
|
||||
@ExceptionHandler(NotRoleException.class)
|
||||
public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
|
||||
return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权");
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证失败
|
||||
*/
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
|
||||
return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "2认证失败,无法访问系统资源");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.agileboot.common.satoken.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class LoginUser implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门类别编码
|
||||
*/
|
||||
private String deptCategory;
|
||||
|
||||
/**
|
||||
* 部门名
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户唯一标识
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Long expireTime;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipaddr;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
|
||||
/**
|
||||
* 菜单权限
|
||||
*/
|
||||
private Set<String> menuPermission;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*/
|
||||
private Set<String> rolePermission;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 角色对象
|
||||
*/
|
||||
private List<RoleDTO> roles;
|
||||
|
||||
/**
|
||||
* 岗位对象
|
||||
*/
|
||||
private List<PostDTO> posts;
|
||||
|
||||
/**
|
||||
* 数据权限 当前角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 客户端
|
||||
*/
|
||||
private String clientKey;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 是否是超级管理员
|
||||
*/
|
||||
private Integer isAdmin;
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 获取登录id
|
||||
*/
|
||||
public String getLoginId() {
|
||||
if (userType == null) {
|
||||
throw new IllegalArgumentException("用户类型不能为空");
|
||||
}
|
||||
if (userId == null) {
|
||||
throw new IllegalArgumentException("用户ID不能为空");
|
||||
}
|
||||
return userType + ":" + userId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.agileboot.common.satoken.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 岗位
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PostDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
private Long postId;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 岗位编码
|
||||
*/
|
||||
private String postCode;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
private String postName;
|
||||
|
||||
/**
|
||||
* 岗位类别编码
|
||||
*/
|
||||
private String postCategory;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.agileboot.common.satoken.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class RoleDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*/
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限)
|
||||
*/
|
||||
private String dataScope;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.agileboot.common.satoken.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* sa-token 权限管理实现类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public class SaPermissionImpl implements StpInterface {
|
||||
|
||||
/**
|
||||
* 获取菜单权限列表
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色权限列表
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.agileboot.common.satoken.utils;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.agileboot.common.core.constant.Constants;
|
||||
import com.agileboot.common.core.enums.UserType;
|
||||
import com.agileboot.common.satoken.pojo.LoginUser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* 登录鉴权助手
|
||||
* <p>
|
||||
* user_type 为 用户类型 同一个用户表 可以有多种用户类型 例如 pc,app
|
||||
* deivce 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios
|
||||
* 可以组成 用户类型与设备类型多对多的 权限灵活控制
|
||||
* <p>
|
||||
* 多用户体系 针对 多种用户类型 但权限控制不一致
|
||||
* 可以组成 多用户类型表与多设备类型 分别控制权限
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class LoginHelper {
|
||||
|
||||
public static final String LOGIN_USER_KEY = "loginUser";
|
||||
public static final String TENANT_KEY = "tenantId";
|
||||
public static final String USER_KEY = "userId";
|
||||
public static final String USER_NAME_KEY = "userName";
|
||||
public static final String DEPT_KEY = "deptId";
|
||||
public static final String DEPT_NAME_KEY = "deptName";
|
||||
public static final String DEPT_CATEGORY_KEY = "deptCategory";
|
||||
public static final String CLIENT_KEY = "clientid";
|
||||
|
||||
/**
|
||||
* 登录系统 基于 设备类型
|
||||
* 针对相同用户体系不同设备
|
||||
*
|
||||
* @param loginUser 登录用户信息
|
||||
* @param model 配置参数
|
||||
*/
|
||||
public static void login(LoginUser loginUser, SaLoginParameter model) {
|
||||
model = ObjectUtil.defaultIfNull(model, new SaLoginParameter());
|
||||
StpUtil.login(loginUser.getLoginId(),
|
||||
model.setExtra(TENANT_KEY, loginUser.getTenantId())
|
||||
.setExtra(USER_KEY, loginUser.getUserId())
|
||||
.setExtra(USER_NAME_KEY, loginUser.getUsername())
|
||||
.setExtra(DEPT_KEY, loginUser.getDeptId())
|
||||
.setExtra(DEPT_NAME_KEY, loginUser.getDeptName())
|
||||
.setExtra(DEPT_CATEGORY_KEY, loginUser.getDeptCategory())
|
||||
);
|
||||
StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户(多级缓存)
|
||||
*/
|
||||
@SuppressWarnings("unchecked cast")
|
||||
public static <T extends LoginUser> T getLoginUser() {
|
||||
SaSession session = StpUtil.getTokenSession();
|
||||
if (ObjectUtil.isNull(session)) {
|
||||
return null;
|
||||
}
|
||||
return (T) session.get(LOGIN_USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户基于token
|
||||
*/
|
||||
@SuppressWarnings("unchecked cast")
|
||||
public static <T extends LoginUser> T getLoginUser(String token) {
|
||||
SaSession session = StpUtil.getTokenSessionByToken(token);
|
||||
if (ObjectUtil.isNull(session)) {
|
||||
return null;
|
||||
}
|
||||
return (T) session.get(LOGIN_USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户id
|
||||
*/
|
||||
public static Long getUserId() {
|
||||
return Convert.toLong(getExtra(USER_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户id
|
||||
*/
|
||||
public static String getUserIdStr() {
|
||||
return Convert.toStr(getExtra(USER_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户账户
|
||||
*/
|
||||
public static String getUsername() {
|
||||
return Convert.toStr(getExtra(USER_NAME_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取租户ID
|
||||
*/
|
||||
public static String getTenantId() {
|
||||
return Convert.toStr(getExtra(TENANT_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门ID
|
||||
*/
|
||||
public static Long getDeptId() {
|
||||
return Convert.toLong(getExtra(DEPT_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门名
|
||||
*/
|
||||
public static String getDeptName() {
|
||||
return Convert.toStr(getExtra(DEPT_NAME_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门类别编码
|
||||
*/
|
||||
public static String getDeptCategory() {
|
||||
return Convert.toStr(getExtra(DEPT_CATEGORY_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 Token 的扩展信息
|
||||
*
|
||||
* @param key 键值
|
||||
* @return 对应的扩展数据
|
||||
*/
|
||||
private static Object getExtra(String key) {
|
||||
try {
|
||||
return StpUtil.getExtra(key);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户类型
|
||||
*/
|
||||
public static UserType getUserType() {
|
||||
String loginType = StpUtil.getLoginIdAsString();
|
||||
return UserType.getUserType(loginType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为超级管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isSuperAdmin(Long userId) {
|
||||
return Constants.SUPER_ADMIN_ID.equals(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为超级管理员
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isSuperAdmin() {
|
||||
return isSuperAdmin(getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为租户管理员
|
||||
*
|
||||
* @param rolePermission 角色权限标识组
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isTenantAdmin(Set<String> rolePermission) {
|
||||
if (CollectionUtils.isEmpty(rolePermission)) {
|
||||
return false;
|
||||
}
|
||||
return rolePermission.contains(Constants.TENANT_ADMIN_ROLE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为租户管理员
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isTenantAdmin() {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (loginUser == null) {
|
||||
return false;
|
||||
}
|
||||
return Convert.toBool(isTenantAdmin(loginUser.getRolePermission()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否已登录
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
try {
|
||||
StpUtil.checkLogin();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
com.agileboot.common.satoken.config.SaTokenConfiguration
|
||||
com.agileboot.common.satoken.config.SaTokenMvcConfiguration
|
||||
@@ -0,0 +1,15 @@
|
||||
# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
|
||||
# Sa-Token配置
|
||||
sa-token:
|
||||
# 允许动态设置 token 有效期
|
||||
dynamic-active-timeout: true
|
||||
# 允许从 请求参数 读取 token
|
||||
is-read-body: true
|
||||
# 允许从 header 读取 token
|
||||
is-read-header: true
|
||||
# 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险
|
||||
is-read-cookie: false
|
||||
# 开启内网服务调用鉴权(不允许越过gateway访问内网服务 保障服务安全)
|
||||
check-same-token: false
|
||||
# token前缀
|
||||
token-prefix: "Bearer"
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.agileboot.common.web.aspect;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LogAspect {
|
||||
|
||||
@Value("${agileboot.traceRequestIdKey:W-RequestId}")
|
||||
private String requestIdKey;
|
||||
|
||||
@Pointcut("execution(* *..controller..*.*(..))")
|
||||
public void logPointCut() {
|
||||
}
|
||||
|
||||
|
||||
@Around("logPointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes == null) {
|
||||
log.warn("无法获取请求上下文信息");
|
||||
return point.proceed();
|
||||
}
|
||||
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
HttpServletResponse response = servletRequestAttributes.getResponse();
|
||||
|
||||
String url = request.getRequestURI().toString();
|
||||
String uuid = response != null ? response.getHeader(requestIdKey) : null;
|
||||
|
||||
Object[] args = point.getArgs();
|
||||
String reqParam = filterAndConvertArgsToString(args);
|
||||
|
||||
log.info("request start, path: {}, uuid: {}, params: {}", url, uuid, reqParam);
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
|
||||
try {
|
||||
Object res = point.proceed();
|
||||
stopWatch.stop();
|
||||
long totalTimeMillis = stopWatch.getTotalTimeMillis();
|
||||
log.info("request end, path: {}, uuid: {}, cost: {}ms", url, uuid, totalTimeMillis);
|
||||
return res;
|
||||
} catch (Throwable throwable) {
|
||||
stopWatch.stop();
|
||||
long totalTimeMillis = stopWatch.getTotalTimeMillis();
|
||||
log.error("request error, path: {}, uuid: {}, cost: {}ms", url, uuid, totalTimeMillis);
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
private String filterAndConvertArgsToString(Object[] args) {
|
||||
if (args == null || args.length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return Arrays.stream(args)
|
||||
.filter(arg -> !(arg instanceof HttpServletRequest ||
|
||||
arg instanceof HttpServletResponse ||
|
||||
arg instanceof MultipartFile ||
|
||||
(arg != null && arg.getClass().isArray() && arg.getClass().getComponentType() != null &&
|
||||
arg.getClass().getComponentType().isAssignableFrom(MultipartFile.class))))
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(", ", "[", "]"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.springframework.web.filter.CorsFilter;
|
||||
@AutoConfiguration
|
||||
public class FilterConfig {
|
||||
|
||||
@Value("${agileboot.traceRequestIdKey:WOl-RequestId}")
|
||||
@Value("${agileboot.traceRequestIdKey:W-RequestId}")
|
||||
private String requestIdKey;
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.agileboot.common.web.handler.GlobalExceptionHandler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
@@ -14,10 +15,12 @@ import java.util.Date;
|
||||
|
||||
/**
|
||||
* 通用配置
|
||||
* 注解EnableAspectJAutoProxy 表示通过aop框架暴露该代理对象,AopContext能够访问
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
public class ResourcesConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -77,7 +77,8 @@ public class GlobalExceptionHandler {
|
||||
@ExceptionHandler(BizException.class)
|
||||
public R<Void> handleBaseException(BizException e, HttpServletRequest request) {
|
||||
log.error(e.getMessage());
|
||||
return R.fail(e.getMessage());
|
||||
Integer code = e.getCode();
|
||||
return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
public interface SysConfigService extends IService<SysConfigEntity> {
|
||||
|
||||
/**
|
||||
* 通过key获取配置
|
||||
*
|
||||
* @param key 配置对应的key
|
||||
* @return 配置
|
||||
*/
|
||||
String getConfigValueByKey(String key);
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
@Service
|
||||
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfigEntity> implements
|
||||
SysConfigService {
|
||||
|
||||
@Override
|
||||
public String getConfigValueByKey(String key) {
|
||||
if (StrUtil.isBlank(key)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
QueryWrapper<SysConfigEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("config_key", key);
|
||||
SysConfigEntity one = this.getOne(queryWrapper);
|
||||
if (one == null || one.getConfigValue() == null) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
return one.getConfigValue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
34
agileboot-system/agileboot-system-base/pom.xml
Normal file
34
agileboot-system/agileboot-system-base/pom.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-system</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agileboot-system-base</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>wol-domain</artifactId>
|
||||
</dependency>
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.agileboot.system.client.mapper;
|
||||
|
||||
import com.agileboot.system.client.entity.SysClient;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface SysClientMapper extends BaseMapper<SysClient> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.client.mapper.SysClientMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.agileboot.system.client.service;
|
||||
|
||||
import com.agileboot.system.client.vo.SysClientVO;
|
||||
|
||||
public interface ISysClientService {
|
||||
SysClientVO queryByClientId(String clientId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.system.client.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.system.client.entity.SysClient;
|
||||
import com.agileboot.system.client.mapper.SysClientMapper;
|
||||
import com.agileboot.system.client.service.ISysClientService;
|
||||
import com.agileboot.system.client.vo.SysClientVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SysClientServiceImpl extends ServiceImpl<SysClientMapper, SysClient> implements ISysClientService {
|
||||
@Override
|
||||
public SysClientVO queryByClientId(String clientId) {
|
||||
SysClient client = super.baseMapper.selectOne(new LambdaQueryWrapper<SysClient>().eq(SysClient::getClientId, clientId));
|
||||
return BeanUtil.copyProperties(client, SysClientVO.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.agileboot.system.config.controller;
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.config.dto.ConfigQuery;
|
||||
import com.agileboot.system.config.dto.ConfigUpdate;
|
||||
import com.agileboot.system.config.service.ISysConfigService;
|
||||
import com.agileboot.system.config.vo.ConfigVO;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @Author cuiJiaWang
|
||||
* @Create 2025-08-13 11:49
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysConfigController {
|
||||
|
||||
private final ISysConfigService sysConfigService;
|
||||
|
||||
@GetMapping("/test")
|
||||
@Deprecated
|
||||
public R<String> test(@RequestParam("key") String key) {
|
||||
return R.ok(sysConfigService.getConfigValueByKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数配置列表
|
||||
*/
|
||||
@GetMapping("/configs")
|
||||
public PageR<ConfigVO> list(ConfigQuery query) {
|
||||
return sysConfigService.getConfigPage(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/config/{configId}")
|
||||
public R<ConfigVO> getInfo(@NotNull @Positive @PathVariable Long configId) {
|
||||
return R.ok(sysConfigService.getConfigInfo(configId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数配置
|
||||
*/
|
||||
@PostMapping(value = "/config/{id}")
|
||||
public R<Void> edit(@NotNull @Positive @PathVariable Long id, @RequestBody ConfigUpdate config) {
|
||||
sysConfigService.updateConfig(id, config);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
package com.agileboot.system.config.mapper;
|
||||
|
||||
import com.agileboot.system.config.entity.SysConfig;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
@@ -10,6 +11,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
public interface SysConfigMapper extends BaseMapper<SysConfigEntity> {
|
||||
public interface SysConfigMapper extends BaseMapper<SysConfig> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.config.mapper.SysConfigMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.agileboot.system.config.service;
|
||||
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.config.dto.ConfigQuery;
|
||||
import com.agileboot.system.config.dto.ConfigUpdate;
|
||||
import com.agileboot.system.config.vo.ConfigVO;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
public interface ISysConfigService {
|
||||
|
||||
/**
|
||||
* 通过key获取配置
|
||||
*
|
||||
* @param key 配置对应的key
|
||||
* @return 配置
|
||||
*/
|
||||
String getConfigValueByKey(String key);
|
||||
|
||||
PageR<ConfigVO> getConfigPage(ConfigQuery query);
|
||||
|
||||
ConfigVO getConfigInfo(Long id);
|
||||
|
||||
void updateConfig(Long id, ConfigUpdate update);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.agileboot.system.config.service.impl;
|
||||
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.config.dto.ConfigQuery;
|
||||
import com.agileboot.system.config.dto.ConfigUpdate;
|
||||
import com.agileboot.system.config.entity.SysConfig;
|
||||
import com.agileboot.system.config.mapper.SysConfigMapper;
|
||||
import com.agileboot.system.config.service.ISysConfigService;
|
||||
import com.agileboot.system.config.vo.ConfigVO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
@Service
|
||||
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {
|
||||
|
||||
@Override
|
||||
public String getConfigValueByKey(String key) {
|
||||
if (StringUtils.isBlank(key)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
SysConfig one = this.lambdaQuery().eq(SysConfig::getConfigKey, key).one();
|
||||
if (one == null || one.getConfigValue() == null) {
|
||||
return "";
|
||||
}
|
||||
return one.getConfigValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageR<ConfigVO> getConfigPage(ConfigQuery query) {
|
||||
Page<SysConfig> page = this.page(query.toPage(), query.toQueryWrapper());
|
||||
IPage<ConfigVO> convert = page.convert(ConfigVO::new);
|
||||
return new PageR<>(convert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigVO getConfigInfo(Long id) {
|
||||
return new ConfigVO(this.getById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfig(Long id, ConfigUpdate update) {
|
||||
if (StringUtils.isBlank(update.getConfigValue())) {
|
||||
throw new BizException("");
|
||||
}
|
||||
SysConfig entity = new SysConfig();
|
||||
entity.setId(id);
|
||||
entity.setConfigValue(update.getConfigValue());
|
||||
this.updateById(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.agileboot.system.dept.controller;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.system.dept.dto.AddDeptDTO;
|
||||
import com.agileboot.system.dept.dto.DeptQuery;
|
||||
import com.agileboot.system.dept.dto.UpdateDeptDTO;
|
||||
import com.agileboot.system.dept.service.ISysDeptService;
|
||||
import com.agileboot.system.dept.vo.DeptVO;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 部门信息
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysDeptController {
|
||||
|
||||
private final ISysDeptService sysDeptService;
|
||||
|
||||
/**
|
||||
* 获取部门列表
|
||||
*/
|
||||
@GetMapping("/depts")
|
||||
public R<List<DeptVO>> list(DeptQuery query) {
|
||||
List<DeptVO> deptList = sysDeptService.getDeptList(query);
|
||||
return R.ok(deptList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/dept/{deptId}")
|
||||
public R<DeptVO> getInfo(@PathVariable Long deptId) {
|
||||
DeptVO dept = sysDeptService.getDeptInfo(deptId);
|
||||
return R.ok(dept);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门下拉树列表
|
||||
*/
|
||||
@GetMapping("/depts/dropdown")
|
||||
public R<List<Tree<Long>>> dropdownList() {
|
||||
List<Tree<Long>> deptTree = sysDeptService.getDeptTree();
|
||||
return R.ok(deptTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增部门
|
||||
*/
|
||||
@PostMapping("/dept")
|
||||
public R<Void> add(@RequestBody AddDeptDTO addCommand) {
|
||||
sysDeptService.addDept(addCommand);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改部门
|
||||
*/
|
||||
@PutMapping("/dept/{deptId}")
|
||||
public R<Void> edit(@PathVariable("deptId") Long deptId, @RequestBody UpdateDeptDTO updateCommand) {
|
||||
updateCommand.setDeptId(deptId);
|
||||
sysDeptService.updateDept(updateCommand);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
@DeleteMapping("/dept/{deptId}")
|
||||
public R<Void> remove(@PathVariable @NotNull Long deptId) {
|
||||
sysDeptService.removeDept(deptId);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.agileboot.system.dept.mapper;
|
||||
|
||||
import com.agileboot.system.dept.entity.SysDept;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface SysDeptMapper extends BaseMapper<SysDept> {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.dept.mapper.SysDeptMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.agileboot.system.dept.service;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.system.dept.dto.AddDeptDTO;
|
||||
import com.agileboot.system.dept.dto.DeptQuery;
|
||||
import com.agileboot.system.dept.dto.UpdateDeptDTO;
|
||||
import com.agileboot.system.dept.vo.DeptVO;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISysDeptService {
|
||||
List<DeptVO> getDeptList(DeptQuery query);
|
||||
|
||||
DeptVO getDeptInfo(Long deptId);
|
||||
|
||||
List<Tree<Long>> getDeptTree();
|
||||
|
||||
void addDept(AddDeptDTO addCommand);
|
||||
|
||||
void updateDept(UpdateDeptDTO updateCommand);
|
||||
|
||||
void removeDept(@NotNull Long deptId);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.agileboot.system.dept.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import com.agileboot.common.core.enums.BasicEnumUtil;
|
||||
import com.agileboot.common.core.enums.common.StatusEnum;
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.core.exception.error.ErrorCode;
|
||||
import com.agileboot.system.dept.dto.AddDeptDTO;
|
||||
import com.agileboot.system.dept.dto.DeptQuery;
|
||||
import com.agileboot.system.dept.dto.UpdateDeptDTO;
|
||||
import com.agileboot.system.dept.entity.SysDept;
|
||||
import com.agileboot.system.dept.mapper.SysDeptMapper;
|
||||
import com.agileboot.system.dept.service.ISysDeptService;
|
||||
import com.agileboot.system.dept.vo.DeptVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements ISysDeptService {
|
||||
@Override
|
||||
public List<DeptVO> getDeptList(DeptQuery query) {
|
||||
List<SysDept> list = super.list(query.toQueryWrapper());
|
||||
return list.stream().map(DeptVO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeptVO getDeptInfo(Long deptId) {
|
||||
SysDept one = super.getById(deptId);
|
||||
return new DeptVO(one);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> getDeptTree() {
|
||||
List<SysDept> list = super.list();
|
||||
return TreeUtil.build(list, 0L, (dept, tree) -> {
|
||||
tree.setId(dept.getDeptId());
|
||||
tree.setParentId(dept.getParentId());
|
||||
tree.putExtra("label", dept.getDeptName());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDept(AddDeptDTO addDTO) {
|
||||
Long parentId = addDTO.getParentId();
|
||||
SysDept entity = new SysDept();
|
||||
entity.setParentId(parentId);
|
||||
entity.setDeptName(addDTO.getDeptName());
|
||||
entity.setOrderNum(addDTO.getOrderNum());
|
||||
entity.setLeaderName(addDTO.getLeaderName());
|
||||
entity.setPhone(addDTO.getPhone());
|
||||
entity.setEmail(addDTO.getEmail());
|
||||
entity.setStatus(addDTO.getStatus());
|
||||
|
||||
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery(SysDept.class)
|
||||
.eq(SysDept::getDeptName, addDTO.getDeptName())
|
||||
.eq(parentId != null, SysDept::getDeptId, parentId);
|
||||
if (super.exists(queryWrapper)) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE.message(), addDTO.getDeptName());
|
||||
}
|
||||
SysDept sysDept = generateAncestors(entity);
|
||||
super.save(sysDept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDept(UpdateDeptDTO updateDTO) {
|
||||
Long deptId = updateDTO.getDeptId();
|
||||
Long parentId = updateDTO.getParentId();
|
||||
if (Objects.equals(parentId, deptId)) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF);
|
||||
}
|
||||
Integer status = updateDTO.getStatus();
|
||||
SysDept entity = super.getById(deptId);
|
||||
if (entity == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND.message(), deptId, "部门");
|
||||
}
|
||||
entity.setParentId(parentId);
|
||||
entity.setDeptName(updateDTO.getDeptName());
|
||||
entity.setOrderNum(updateDTO.getOrderNum());
|
||||
entity.setLeaderName(updateDTO.getLeaderName());
|
||||
entity.setPhone(updateDTO.getPhone());
|
||||
entity.setEmail(updateDTO.getEmail());
|
||||
entity.setStatus(Convert.toInt(status, 0));
|
||||
|
||||
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery(SysDept.class)
|
||||
.eq(SysDept::getDeptName, updateDTO.getDeptName())
|
||||
.ne(deptId != null, SysDept::getDeptId, deptId)
|
||||
.eq(parentId != null, SysDept::getDeptId, parentId);
|
||||
if (super.exists(queryWrapper)) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE.message(), updateDTO.getDeptName());
|
||||
}
|
||||
if (StatusEnum.DISABLE.getValue().equals(entity.getStatus()) && this.hasChildrenDept(deptId, true)) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE);
|
||||
}
|
||||
SysDept sysDept = generateAncestors(entity);
|
||||
super.updateById(sysDept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDept(Long deptId) {
|
||||
SysDept entity = super.getById(deptId);
|
||||
if (entity == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND.message(), deptId, "部门");
|
||||
}
|
||||
if (this.hasChildrenDept(entity.getDeptId(), null)) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE);
|
||||
}
|
||||
if (this.isDeptAssignedToUsers(entity.getDeptId())) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE);
|
||||
}
|
||||
super.removeById(deptId);
|
||||
}
|
||||
|
||||
private SysDept generateAncestors(SysDept entity) {
|
||||
Long parentId = entity.getParentId();
|
||||
if (parentId == null || parentId == 0) {
|
||||
entity.setAncestors(String.valueOf(parentId == null ? 0 : parentId));
|
||||
} else {
|
||||
SysDept parentDept = super.getById(parentId);
|
||||
// 检查 parentDept 是否为 null 或者状态为禁用
|
||||
if (parentDept == null || StatusEnum.DISABLE.equals(
|
||||
BasicEnumUtil.fromValue(StatusEnum.class, parentDept.getStatus()))) {
|
||||
throw new BizException(ErrorCode.Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED);
|
||||
}
|
||||
// 处理 parentDept.getAncestors() 可能为 null 的情况
|
||||
String ancestors = parentDept.getAncestors() == null ? "" : parentDept.getAncestors();
|
||||
entity.setAncestors(ancestors + "," + parentId);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private boolean hasChildrenDept(Long deptId, Boolean enabled) {
|
||||
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery(SysDept.class)
|
||||
.eq(enabled != null, SysDept::getStatus, 1)
|
||||
.and(o -> o.eq(SysDept::getParentId, deptId).or()
|
||||
.apply("FIND_IN_SET (" + deptId + " , ancestors)")
|
||||
);
|
||||
return super.exists(queryWrapper);
|
||||
}
|
||||
|
||||
private boolean isDeptAssignedToUsers(Long deptId) {
|
||||
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery(SysDept.class)
|
||||
.eq(SysDept::getDeptId, deptId);
|
||||
return super.exists(queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.agileboot.system.log.controller;
|
||||
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.core.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.log.dto.LoginLogQuery;
|
||||
import com.agileboot.system.log.dto.OperationLogQuery;
|
||||
import com.agileboot.system.log.service.ILogService;
|
||||
import com.agileboot.system.log.vo.LoginLogVO;
|
||||
import com.agileboot.system.log.vo.OperationLogVO;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统访问记录
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/logs")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysLogsController {
|
||||
|
||||
private final ILogService logService;
|
||||
|
||||
/**
|
||||
* 登录日志列表
|
||||
*/
|
||||
@GetMapping("/loginLogs")
|
||||
public R<PageR<LoginLogVO>> loginInfoList(LoginLogQuery query) {
|
||||
PageR<LoginLogVO> page = logService.getLoginInfoList(query);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将登录日志导出到excel
|
||||
*/
|
||||
@GetMapping("/loginLogs/excel")
|
||||
public void loginInfosExcel(HttpServletResponse response, LoginLogQuery query) {
|
||||
PageR<LoginLogVO> page = logService.getLoginInfoList(query);
|
||||
CustomExcelUtil.writeToResponse(page.getRows(), LoginLogVO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除登录日志
|
||||
*/
|
||||
@DeleteMapping("/loginLogs")
|
||||
public R<Void> removeLoginInfos(@RequestParam @NotNull @NotEmpty List<Long> ids) {
|
||||
logService.deleteLoginInfo(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作日志列表
|
||||
*/
|
||||
@GetMapping("/operationLogs")
|
||||
public R<PageR<OperationLogVO>> operationLogs(OperationLogQuery query) {
|
||||
PageR<OperationLogVO> page = logService.getOperationLogList(query);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作日志导出
|
||||
*/
|
||||
@GetMapping("/operationLogs/excel")
|
||||
public void operationLogsExcel(HttpServletResponse response, OperationLogQuery query) {
|
||||
PageR<OperationLogVO> page = logService.getOperationLogList(query);
|
||||
CustomExcelUtil.writeToResponse(page.getRows(), OperationLogVO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除操作日志
|
||||
*/
|
||||
@DeleteMapping("/operationLogs")
|
||||
public R<Void> removeOperationLogs(@RequestParam List<Long> operationIds) {
|
||||
logService.deleteOperationLog(operationIds);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.agileboot.system.log.mapper;
|
||||
|
||||
import com.agileboot.system.log.entity.SysLoginInfo;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统访问记录 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-06
|
||||
*/
|
||||
public interface SysLoginInfoMapper extends BaseMapper<SysLoginInfo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.agileboot.system.log.mapper;
|
||||
|
||||
import com.agileboot.system.log.entity.SysOperationLog;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 操作日志记录 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-08
|
||||
*/
|
||||
public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.log.mapper.SysLoginInfoMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.log.mapper.SysOperationLogMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.agileboot.system.log.service;
|
||||
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.log.dto.LoginLogQuery;
|
||||
import com.agileboot.system.log.dto.OperationLogQuery;
|
||||
import com.agileboot.system.log.vo.LoginLogVO;
|
||||
import com.agileboot.system.log.vo.OperationLogVO;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ILogService {
|
||||
PageR<LoginLogVO> getLoginInfoList(LoginLogQuery query);
|
||||
|
||||
void deleteLoginInfo(@NotNull @NotEmpty List<Long> ids);
|
||||
|
||||
PageR<OperationLogVO> getOperationLogList(OperationLogQuery query);
|
||||
|
||||
void deleteOperationLog(List<Long> operationIds);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.agileboot.system.log.service.impl;
|
||||
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.log.dto.LoginLogQuery;
|
||||
import com.agileboot.system.log.dto.OperationLogQuery;
|
||||
import com.agileboot.system.log.entity.SysLoginInfo;
|
||||
import com.agileboot.system.log.entity.SysOperationLog;
|
||||
import com.agileboot.system.log.mapper.SysLoginInfoMapper;
|
||||
import com.agileboot.system.log.mapper.SysOperationLogMapper;
|
||||
import com.agileboot.system.log.service.ILogService;
|
||||
import com.agileboot.system.log.vo.LoginLogVO;
|
||||
import com.agileboot.system.log.vo.OperationLogVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class LogServiceImpl implements ILogService {
|
||||
|
||||
@Resource
|
||||
private SysLoginInfoMapper sysLoginInfoMapper;
|
||||
@Resource
|
||||
private SysOperationLogMapper sysOperationLogMapper;
|
||||
|
||||
@Override
|
||||
public PageR<LoginLogVO> getLoginInfoList(LoginLogQuery query) {
|
||||
Page<SysLoginInfo> page = sysLoginInfoMapper.selectPage(query.toPage(), query.toQueryWrapper());
|
||||
IPage<LoginLogVO> pageVO = page.convert(LoginLogVO::new);
|
||||
return new PageR<>(pageVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteLoginInfo(List<Long> ids) {
|
||||
LambdaQueryWrapper<SysLoginInfo> wrapper = Wrappers.lambdaQuery(SysLoginInfo.class)
|
||||
.in(SysLoginInfo::getInfoId, ids);
|
||||
sysLoginInfoMapper.delete(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageR<OperationLogVO> getOperationLogList(OperationLogQuery query) {
|
||||
Page<SysOperationLog> page = sysOperationLogMapper.selectPage(query.toPage(), query.toQueryWrapper());
|
||||
IPage<OperationLogVO> pageVO = page.convert(OperationLogVO::new);
|
||||
return new PageR<>(pageVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteOperationLog(List<Long> operationIds) {
|
||||
sysOperationLogMapper.deleteByIds(operationIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.agileboot.system.menu.controller;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.satoken.pojo.LoginUser;
|
||||
import com.agileboot.common.satoken.utils.LoginHelper;
|
||||
import com.agileboot.system.menu.dto.*;
|
||||
import com.agileboot.system.menu.service.ISysMenuService;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 菜单信息
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/menus")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysMenuController {
|
||||
|
||||
private final ISysMenuService sysMenuService;
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
@GetMapping
|
||||
public R<List<MenuDTO>> menuList(MenuQuery menuQuery) {
|
||||
List<MenuDTO> menuList = sysMenuService.getMenuList(menuQuery);
|
||||
return R.ok(menuList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{menuId}")
|
||||
public R<MenuDetailDTO> menuInfo(@PathVariable("menuId") @NotNull Long menuId) {
|
||||
MenuDetailDTO menu = sysMenuService.getMenuInfo(menuId);
|
||||
return R.ok(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉树列表
|
||||
*/
|
||||
@GetMapping("/dropdown")
|
||||
public R<List<Tree<Long>>> dropdownList() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
List<Tree<Long>> dropdownList = sysMenuService.getDropdownList(loginUser);
|
||||
return R.ok(dropdownList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
* 需支持一级菜单以及 多级菜单 子菜单为一个 或者 多个的情况
|
||||
* 隐藏菜单不显示 以及rank排序
|
||||
* 内链 和 外链
|
||||
*/
|
||||
@PostMapping
|
||||
public R<Void> add(@RequestBody AddMenuDTO addCommand) {
|
||||
sysMenuService.addMenu(addCommand);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*/
|
||||
@PostMapping("/{menuId}")
|
||||
public R<Void> edit(@PathVariable("menuId") Long menuId, @RequestBody UpdateMenuDTO updateCommand) {
|
||||
updateCommand.setMenuId(menuId);
|
||||
sysMenuService.updateMenu(updateCommand);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*/
|
||||
@PostMapping("/del/{menuId}")
|
||||
public R<Void> remove(@PathVariable("menuId") Long menuId) {
|
||||
sysMenuService.remove(menuId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.agileboot.system.menu.mapper;
|
||||
|
||||
import com.agileboot.system.menu.entity.SysMenu;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysMenuMapper extends BaseMapper<SysMenu> {
|
||||
|
||||
/**
|
||||
* 根据用户查询出所有菜单
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @return 菜单列表
|
||||
*/
|
||||
@Select("SELECT DISTINCT m.* "
|
||||
+ "FROM sys_menu m "
|
||||
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
|
||||
+ " LEFT JOIN sys_user u ON rm.role_id = u.role_id "
|
||||
+ "WHERE u.user_id = #{userId} "
|
||||
+ " AND m.status = 1 "
|
||||
+ " AND m.deleted = 0 "
|
||||
+ "ORDER BY m.parent_id")
|
||||
List<SysMenu> selectMenuListByUserId(@Param("userId") Long userId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据角色ID查询菜单树信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 选中菜单列表
|
||||
*/
|
||||
@Select("SELECT DISTINCT m.menu_id "
|
||||
+ "FROM sys_menu m "
|
||||
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
|
||||
+ "WHERE rm.role_id = #{roleId} "
|
||||
+ " AND m.deleted = 0 "
|
||||
+ "GROUP BY m.menu_id ")
|
||||
List<Long> selectMenuIdsByRoleId(@Param("roleId") Long roleId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.menu.mapper.SysMenuMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.agileboot.system.menu.service;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.common.satoken.pojo.LoginUser;
|
||||
import com.agileboot.system.menu.dto.*;
|
||||
import com.agileboot.system.menu.vo.RouterVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISysMenuService {
|
||||
List<MenuDTO> getMenuList(MenuQuery menuQuery);
|
||||
|
||||
MenuDetailDTO getMenuInfo(Long menuId);
|
||||
|
||||
List<Tree<Long>> getDropdownList(LoginUser loginUser);
|
||||
|
||||
void addMenu(AddMenuDTO addCommand);
|
||||
|
||||
void updateMenu(UpdateMenuDTO updateCommand);
|
||||
|
||||
void remove(Long menuId);
|
||||
|
||||
List<Long> getMenuIdsByRoleId(Long roleId);
|
||||
|
||||
List<RouterVO> getRouterTree(LoginUser loginUser);
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package com.agileboot.system.menu.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import com.agileboot.common.core.enums.common.MenuTypeEnum;
|
||||
import com.agileboot.common.core.enums.common.StatusEnum;
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.core.exception.error.ErrorCode;
|
||||
import com.agileboot.common.core.utils.jackson.JacksonUtil;
|
||||
import com.agileboot.common.satoken.pojo.LoginUser;
|
||||
import com.agileboot.system.menu.dto.*;
|
||||
import com.agileboot.system.menu.entity.SysMenu;
|
||||
import com.agileboot.system.menu.mapper.SysMenuMapper;
|
||||
import com.agileboot.system.menu.service.ISysMenuService;
|
||||
import com.agileboot.system.menu.vo.RouterVO;
|
||||
import com.agileboot.system.role.mapper.SysRoleMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 菜单应用服务
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
|
||||
|
||||
private final SysRoleMapper roleMapper;
|
||||
|
||||
@Override
|
||||
public List<MenuDTO> getMenuList(MenuQuery query) {
|
||||
List<SysMenu> list = super.list(query.toQueryWrapper());
|
||||
return list.stream().map(MenuDTO::new)
|
||||
.sorted(Comparator.comparing(MenuDTO::getRank, Comparator.nullsLast(Integer::compareTo)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuDetailDTO getMenuInfo(Long menuId) {
|
||||
SysMenu sysMenu = super.getById(menuId);
|
||||
return new MenuDetailDTO(sysMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> getDropdownList(LoginUser loginUser) {
|
||||
List<SysMenu> menuEntityList =
|
||||
// loginUser.isAdmin() ?
|
||||
super.list();
|
||||
// :
|
||||
// this.baseMapper.selectMenuListByUserId(loginUser.getUserId());
|
||||
|
||||
return buildMenuTreeSelect(menuEntityList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMenu(AddMenuDTO addCommand) {
|
||||
SysMenu entity = new SysMenu();
|
||||
BeanUtils.copyProperties(addCommand, entity, "menuId");
|
||||
String metaInfo = JacksonUtil.to(addCommand.getMeta());
|
||||
entity.setMetaInfo(metaInfo);
|
||||
|
||||
this.checkMenuNameUnique(entity.getMenuName(), entity.getMenuId(), entity.getParentId());
|
||||
this.checkAddButtonInIframeOrOutLink(entity.getIsButton(), entity.getParentId());
|
||||
this.checkAddMenuNotInCatalog(entity.getIsButton(), entity.getParentId());
|
||||
|
||||
super.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenu(UpdateMenuDTO dto) {
|
||||
Long menuId = dto.getMenuId();
|
||||
SysMenu byId = super.getById(menuId);
|
||||
if (byId == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, menuId, "菜单");
|
||||
}
|
||||
if (!Objects.equals(byId.getMenuType(), dto.getMenuType()) && !byId.getIsButton()) {
|
||||
throw new BizException(ErrorCode.Business.MENU_CAN_NOT_CHANGE_MENU_TYPE);
|
||||
}
|
||||
BeanUtil.copyProperties(dto, byId, "menuId");
|
||||
String metaInfo = JacksonUtil.to(dto.getMeta());
|
||||
byId.setMetaInfo(metaInfo);
|
||||
|
||||
this.checkMenuNameUnique(byId.getMenuName(), byId.getMenuId(), byId.getParentId());
|
||||
this.checkAddButtonInIframeOrOutLink(byId.getIsButton(), byId.getParentId());
|
||||
this.checkAddMenuNotInCatalog(byId.getIsButton(), byId.getParentId());
|
||||
this.checkParentIdConflict(byId.getMenuId(), byId.getParentId());
|
||||
|
||||
super.updateById(byId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Long menuId) {
|
||||
// 是否存在菜单子节点
|
||||
if (super.lambdaQuery().eq(SysMenu::getParentId, menuId).exists()) {
|
||||
throw new BizException(ErrorCode.Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE);
|
||||
}
|
||||
// 查询菜单是否存在角色
|
||||
if (roleMapper.isMenuAssignToRoles(menuId)) {
|
||||
throw new BizException(ErrorCode.Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE);
|
||||
}
|
||||
super.removeById(menuId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getMenuIdsByRoleId(Long roleId) {
|
||||
return this.baseMapper.selectMenuIdsByRoleId(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RouterVO> getRouterTree(LoginUser loginUser) {
|
||||
List<Tree<Long>> trees = buildMenuEntityTree(loginUser);
|
||||
return buildRouterTree(trees);
|
||||
}
|
||||
|
||||
public List<Tree<Long>> buildMenuEntityTree(LoginUser loginUser) {
|
||||
List<SysMenu> allMenus;
|
||||
if (loginUser.getIsAdmin() == 1) {
|
||||
allMenus = super.list();
|
||||
} else {
|
||||
allMenus = this.baseMapper.selectMenuListByUserId(loginUser.getUserId());
|
||||
}
|
||||
|
||||
// 传给前端的路由排除掉按钮和停用的菜单
|
||||
List<SysMenu> noButtonMenus = allMenus.stream()
|
||||
.filter(menu -> !menu.getIsButton())
|
||||
.filter(menu -> StatusEnum.ENABLE.getValue().equals(menu.getStatus()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
// 默认为id 可以不设置
|
||||
config.setIdKey("menuId");
|
||||
|
||||
return TreeUtil.build(noButtonMenus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
// TODO 可以取meta中的rank来排序
|
||||
// tree.setWeight(menu.getRank());
|
||||
tree.putExtra("entity", menu);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public List<RouterVO> buildRouterTree(List<Tree<Long>> trees) {
|
||||
List<RouterVO> routers = new LinkedList<>();
|
||||
if (CollUtil.isNotEmpty(trees)) {
|
||||
for (Tree<Long> tree : trees) {
|
||||
Object entity = tree.get("entity");
|
||||
if (entity != null) {
|
||||
RouterVO routerDTO = new RouterVO((SysMenu) entity);
|
||||
List<Tree<Long>> children = tree.getChildren();
|
||||
if (CollUtil.isNotEmpty(children)) {
|
||||
routerDTO.setChildren(buildRouterTree(children));
|
||||
}
|
||||
routers.add(routerDTO);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return routers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建前端所需要树结构
|
||||
*
|
||||
* @param menus 菜单列表
|
||||
* @return 树结构列表
|
||||
*/
|
||||
private List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
//默认为id可以不设置
|
||||
config.setIdKey("menuId");
|
||||
return TreeUtil.build(menus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
tree.putExtra("label", menu.getMenuName());
|
||||
});
|
||||
}
|
||||
|
||||
private void checkMenuNameUnique(String menuName, Long menuId, Long parentId) {
|
||||
LambdaQueryWrapper<SysMenu> queryWrapper = Wrappers.lambdaQuery(SysMenu.class)
|
||||
.eq(SysMenu::getMenuName, menuName)
|
||||
.ne(menuId != null, SysMenu::getMenuId, menuId)
|
||||
.eq(parentId != null, SysMenu::getParentId, parentId);
|
||||
if (this.baseMapper.exists(queryWrapper)) {
|
||||
throw new BizException(ErrorCode.Business.MENU_NAME_IS_NOT_UNIQUE, menuName);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkParentIdConflict(Long menuId, Long parentId) {
|
||||
if (menuId.equals(parentId)) {
|
||||
throw new BizException(ErrorCode.Business.MENU_PARENT_ID_NOT_ALLOW_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iframe和外链跳转类型 不允许添加按钮
|
||||
*/
|
||||
private void checkAddButtonInIframeOrOutLink(Boolean isButton, Long parentId) {
|
||||
SysMenu parentMenu = super.getById(parentId);
|
||||
|
||||
if (parentMenu != null && isButton
|
||||
&& (Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.IFRAME.getValue())
|
||||
|| Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.OUTSIDE_LINK_REDIRECT.getValue())
|
||||
)) {
|
||||
throw new BizException(ErrorCode.Business.MENU_NOT_ALLOWED_TO_CREATE_BUTTON_ON_IFRAME_OR_OUT_LINK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 只允许在目录菜单类型底下 添加子菜单
|
||||
*/
|
||||
private void checkAddMenuNotInCatalog(Boolean isButton, Long parentId) {
|
||||
SysMenu parentMenu = super.getById(parentId);
|
||||
|
||||
if (parentMenu != null && !isButton
|
||||
&& (!Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.CATALOG.getValue())
|
||||
)) {
|
||||
throw new BizException(ErrorCode.Business.MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.agileboot.system.monitor.controller;
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.monitor.service.ISysMonitorService;
|
||||
import com.agileboot.system.monitor.vo.OnlineUserVO;
|
||||
import com.agileboot.system.monitor.vo.RedisCacheInfoVO;
|
||||
import com.agileboot.system.monitor.vo.ServerInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 缓存监控
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor")
|
||||
@RequiredArgsConstructor
|
||||
public class MonitorController {
|
||||
|
||||
private final ISysMonitorService sysMonitorService;
|
||||
|
||||
/**
|
||||
* Redis信息
|
||||
*/
|
||||
@GetMapping("/cacheInfo")
|
||||
public R<RedisCacheInfoVO> getRedisCacheInfo() {
|
||||
RedisCacheInfoVO redisCacheInfo = sysMonitorService.getRedisCacheInfo();
|
||||
return R.ok(redisCacheInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 服务器信息
|
||||
*/
|
||||
@GetMapping("/serverInfo")
|
||||
public R<ServerInfo> getServerInfo() {
|
||||
ServerInfo serverInfo = sysMonitorService.getServerInfo();
|
||||
return R.ok(serverInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线用户列表
|
||||
*
|
||||
* @param ipAddress ip地址
|
||||
* @param username 用户名
|
||||
* @return 分页处理后的在线用户信息
|
||||
*/
|
||||
@GetMapping("/onlineUsers")
|
||||
public PageR<OnlineUserVO> onlineUsers(@RequestParam(name = "ipAddress", required = false) String ipAddress, @RequestParam(name = "username", required = false) String username) {
|
||||
List<OnlineUserVO> onlineUserList = sysMonitorService.getOnlineUserList(username, ipAddress);
|
||||
return new PageR<>(onlineUserList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退用户
|
||||
*/
|
||||
@DeleteMapping("/onlineUser/{tokenId}")
|
||||
public R<Void> logoutOnlineUser(@PathVariable String tokenId) {
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.system.monitor.service;
|
||||
|
||||
import com.agileboot.system.monitor.vo.OnlineUserVO;
|
||||
import com.agileboot.system.monitor.vo.RedisCacheInfoVO;
|
||||
import com.agileboot.system.monitor.vo.ServerInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISysMonitorService {
|
||||
RedisCacheInfoVO getRedisCacheInfo();
|
||||
|
||||
ServerInfo getServerInfo();
|
||||
|
||||
List<OnlineUserVO> getOnlineUserList(String username, String ipAddress);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.agileboot.system.monitor.service.impl;
|
||||
|
||||
import com.agileboot.system.monitor.service.ISysMonitorService;
|
||||
import com.agileboot.system.monitor.vo.OnlineUserVO;
|
||||
import com.agileboot.system.monitor.vo.RedisCacheInfoVO;
|
||||
import com.agileboot.system.monitor.vo.ServerInfo;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SysMonitorServiceImpl implements ISysMonitorService {
|
||||
|
||||
@Override
|
||||
public RedisCacheInfoVO getRedisCacheInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerInfo getServerInfo() {
|
||||
return ServerInfo.fillInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OnlineUserVO> getOnlineUserList(String username, String ipAddress) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.agileboot.system.notice.controller;
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.notice.dto.NoticeAddDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeQuery;
|
||||
import com.agileboot.system.notice.dto.NoticeUpdateDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeVO;
|
||||
import com.agileboot.system.notice.service.ISysNoticeService;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告 信息操作处理
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/notices")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysNoticeController {
|
||||
|
||||
private final ISysNoticeService sysNoticeService;
|
||||
|
||||
/**
|
||||
* 获取通知公告列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public PageR<NoticeVO> list(NoticeQuery query) {
|
||||
PageR<NoticeVO> page = sysNoticeService.getNoticeList(query);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通知公告列表
|
||||
* 从从库获取数据 例子 仅供参考
|
||||
*/
|
||||
@GetMapping("/database/slave")
|
||||
public R<PageR<NoticeVO>> listFromSlave(NoticeQuery query) {
|
||||
PageR<NoticeVO> page = sysNoticeService.getNoticeList(query);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据通知公告编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{noticeId}")
|
||||
public R<NoticeVO> getInfo(@PathVariable @NotNull @Positive Long noticeId) {
|
||||
NoticeVO vo = sysNoticeService.getNoticeInfo(noticeId);
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增通知公告
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public R<Void> add(@RequestBody NoticeAddDTO addDTO) {
|
||||
sysNoticeService.addNotice(addDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改通知公告
|
||||
*/
|
||||
@PostMapping("/update/{noticeId}")
|
||||
public R<Void> edit(@PathVariable("noticeId") Long noticeId, @RequestBody NoticeUpdateDTO updateDTO) {
|
||||
updateDTO.setNoticeId(noticeId);
|
||||
sysNoticeService.updateNotice(updateDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除通知公告
|
||||
*/
|
||||
@PostMapping("/del")
|
||||
public R<Void> remove(@RequestBody List<Integer> noticeIds) {
|
||||
sysNoticeService.deleteNotice(noticeIds);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.agileboot.system.notice.mapper;
|
||||
|
||||
import com.agileboot.system.notice.entity.SysNotice;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysNoticeMapper extends BaseMapper<SysNotice> {
|
||||
|
||||
/**
|
||||
* 根据条件分页查询角色关联的用户列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryWrapper 条件选择器
|
||||
* @return 分页处理后的公告列表
|
||||
*/
|
||||
@Select("SELECT n.* "
|
||||
+ "FROM sys_notice n "
|
||||
+ "LEFT JOIN sys_user u ON n.create_by = u.user_id"
|
||||
+ " ${ew.customSqlSegment}")
|
||||
Page<SysNotice> getNoticeList(Page<SysNotice> page, @Param(Constants.WRAPPER) Wrapper<SysNotice> queryWrapper);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.notice.mapper.SysNoticeMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.agileboot.system.notice.service;
|
||||
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.notice.dto.NoticeAddDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeQuery;
|
||||
import com.agileboot.system.notice.dto.NoticeUpdateDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeVO;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISysNoticeService {
|
||||
PageR<NoticeVO> getNoticeList(NoticeQuery query);
|
||||
|
||||
NoticeVO getNoticeInfo(@NotNull @Positive Long noticeId);
|
||||
|
||||
void addNotice(NoticeAddDTO addCommand);
|
||||
|
||||
void updateNotice(NoticeUpdateDTO updateCommand);
|
||||
|
||||
void deleteNotice(List<Integer> noticeIds);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.agileboot.system.notice.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.enums.BasicEnumUtil;
|
||||
import com.agileboot.common.core.enums.common.NoticeTypeEnum;
|
||||
import com.agileboot.common.core.enums.common.StatusEnum;
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.core.exception.error.ErrorCode;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.notice.dto.NoticeAddDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeQuery;
|
||||
import com.agileboot.system.notice.dto.NoticeUpdateDTO;
|
||||
import com.agileboot.system.notice.dto.NoticeVO;
|
||||
import com.agileboot.system.notice.entity.SysNotice;
|
||||
import com.agileboot.system.notice.mapper.SysNoticeMapper;
|
||||
import com.agileboot.system.notice.service.ISysNoticeService;
|
||||
import com.agileboot.system.user.service.ISysUserService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SysNoticeServiceImpl extends ServiceImpl<SysNoticeMapper, SysNotice> implements ISysNoticeService {
|
||||
|
||||
private final ISysUserService userService;
|
||||
|
||||
|
||||
@Override
|
||||
public PageR<NoticeVO> getNoticeList(NoticeQuery query) {
|
||||
QueryWrapper<SysNotice> queryWrapper = new QueryWrapper<SysNotice>()
|
||||
.like(StrUtil.isNotEmpty(query.getNoticeTitle()), "notice_title", query.getNoticeTitle())
|
||||
.eq(StrUtil.isNotEmpty(query.getNoticeType()), "notice_type", query.getNoticeType())
|
||||
.eq("n.deleted", 0)
|
||||
.like(StrUtil.isNotEmpty(query.getCreatorName()), "u.username", query.getCreatorName());
|
||||
Page<SysNotice> page = this.baseMapper.getNoticeList(query.toPage(), queryWrapper);
|
||||
|
||||
Set<Long> userIds = page.getRecords().stream().map(SysNotice::getCreateBy).collect(Collectors.toSet());
|
||||
Map<Long, String> idNameMap = userService.geIdNameByIds(userIds);
|
||||
page.getRecords().forEach(sysNotice -> {
|
||||
Long creatorId = sysNotice.getCreateBy();
|
||||
String creatorName = idNameMap.get(creatorId);
|
||||
sysNotice.setSearchValue(creatorName);
|
||||
});
|
||||
IPage<NoticeVO> convert = page.convert(NoticeVO::new);
|
||||
return new PageR<>(convert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoticeVO getNoticeInfo(Long noticeId) {
|
||||
SysNotice byId = super.getById(noticeId);
|
||||
if (byId == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND.message(), noticeId, "通知公告");
|
||||
}
|
||||
return new NoticeVO(byId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotice(NoticeAddDTO addDTO) {
|
||||
BasicEnumUtil.fromValue(NoticeTypeEnum.class, addDTO.getNoticeType());
|
||||
BasicEnumUtil.fromValue(StatusEnum.class, addDTO.getStatus());
|
||||
|
||||
SysNotice sysNotice = new SysNotice();
|
||||
BeanUtil.copyProperties(addDTO, sysNotice);
|
||||
super.save(sysNotice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotice(NoticeUpdateDTO updateDTO) {
|
||||
BasicEnumUtil.fromValue(NoticeTypeEnum.class, updateDTO.getNoticeType());
|
||||
BasicEnumUtil.fromValue(StatusEnum.class, updateDTO.getStatus());
|
||||
|
||||
Long noticeId = updateDTO.getNoticeId();
|
||||
SysNotice byId = super.getById(noticeId);
|
||||
if (byId == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, noticeId, "通知公告");
|
||||
}
|
||||
BeanUtil.copyProperties(updateDTO, byId, "noticeId");
|
||||
super.updateById(byId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteNotice(List<Integer> noticeIds) {
|
||||
super.removeBatchByIds(noticeIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.agileboot.system.post.controller;
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.core.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.post.dto.AddPostDTO;
|
||||
import com.agileboot.system.post.dto.PostQuery;
|
||||
import com.agileboot.system.post.dto.PostVO;
|
||||
import com.agileboot.system.post.dto.UpdatePostDTO;
|
||||
import com.agileboot.system.post.service.ISysPostService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 岗位信息操作处理
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/post")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysPostController {
|
||||
|
||||
private final ISysPostService sysPostService;
|
||||
|
||||
/**
|
||||
* 获取岗位列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public R<PageR<PostVO>> list(PostQuery query) {
|
||||
PageR<PostVO> page = sysPostService.getPostList(query);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出查询到的所有岗位信息到excel文件
|
||||
*
|
||||
* @param response http响应
|
||||
* @param query 查询参数
|
||||
* @author Kevin Zhang
|
||||
* @date 2023-10-02
|
||||
*/
|
||||
@GetMapping("/excel")
|
||||
public void export(HttpServletResponse response, PostQuery query) {
|
||||
List<PostVO> all = sysPostService.getPostListAll(query);
|
||||
CustomExcelUtil.writeToResponse(all, PostVO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据岗位编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{postId}")
|
||||
public R<PostVO> getInfo(@PathVariable Long postId) {
|
||||
PostVO post = sysPostService.getPostInfo(postId);
|
||||
return R.ok(post);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增岗位
|
||||
*/
|
||||
@PostMapping
|
||||
public R<Void> add(@RequestBody AddPostDTO addDTO) {
|
||||
sysPostService.addPost(addDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改岗位
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public R<Void> edit(@RequestBody UpdatePostDTO updateCommand) {
|
||||
sysPostService.updatePost(updateCommand);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除岗位
|
||||
*/
|
||||
@PostMapping("/del")
|
||||
public R<Void> remove(@RequestBody @NotNull @NotEmpty List<Long> ids) {
|
||||
sysPostService.deletePost(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.agileboot.system.post.mapper;
|
||||
|
||||
import com.agileboot.system.post.entity.SysPost;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysPostMapper extends BaseMapper<SysPost> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?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="com.agileboot.system.post.mapper.SysPostMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.agileboot.system.post.service;
|
||||
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.post.dto.AddPostDTO;
|
||||
import com.agileboot.system.post.dto.PostQuery;
|
||||
import com.agileboot.system.post.dto.PostVO;
|
||||
import com.agileboot.system.post.dto.UpdatePostDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISysPostService {
|
||||
PostVO getPostInfo(Long postId);
|
||||
|
||||
PageR<PostVO> getPostList(PostQuery query);
|
||||
|
||||
List<PostVO> getPostListAll(PostQuery query);
|
||||
|
||||
void addPost(AddPostDTO addDTO);
|
||||
|
||||
void updatePost(UpdatePostDTO updateDTO);
|
||||
|
||||
void deletePost(List<Long> ids);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.agileboot.system.post.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.core.exception.BizException;
|
||||
import com.agileboot.common.core.exception.error.ErrorCode;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.post.dto.AddPostDTO;
|
||||
import com.agileboot.system.post.dto.PostQuery;
|
||||
import com.agileboot.system.post.dto.PostVO;
|
||||
import com.agileboot.system.post.dto.UpdatePostDTO;
|
||||
import com.agileboot.system.post.entity.SysPost;
|
||||
import com.agileboot.system.post.mapper.SysPostMapper;
|
||||
import com.agileboot.system.post.service.ISysPostService;
|
||||
import com.agileboot.system.user.service.ISysUserService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class SysPostServiceImpl extends ServiceImpl<SysPostMapper, SysPost> implements ISysPostService {
|
||||
|
||||
@Resource
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
@Override
|
||||
public PostVO getPostInfo(Long postId) {
|
||||
// sysUserMapper.getPostInfo();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查询
|
||||
*
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PageR<PostVO> getPostList(PostQuery query) {
|
||||
Page<SysPost> page = super.page(query.toPage(), query.toQueryWrapper());
|
||||
IPage<PostVO> convert = page.convert(PostVO::new);
|
||||
return new PageR<>(convert);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询满足条件的所有岗位,不分页
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 满足查询条件的岗位列表
|
||||
* @author Kevin Zhang
|
||||
*/
|
||||
@Override
|
||||
public List<PostVO> getPostListAll(PostQuery query) {
|
||||
List<SysPost> all = super.list(query.toQueryWrapper());
|
||||
List<PostVO> records = all.stream().map(PostVO::new).collect(Collectors.toList());
|
||||
return records;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPost(AddPostDTO addDTO) {
|
||||
SysPost sysPost = new SysPost();
|
||||
BeanUtil.copyProperties(addDTO, sysPost);
|
||||
|
||||
if (this.isPostNameDuplicated(null, sysPost.getPostName())) {
|
||||
throw new BizException(ErrorCode.Business.POST_NAME_IS_NOT_UNIQUE, sysPost.getPostName());
|
||||
}
|
||||
if (this.isPostCodeDuplicated(null, sysPost.getPostCode())) {
|
||||
throw new BizException(ErrorCode.Business.POST_CODE_IS_NOT_UNIQUE, sysPost.getPostCode());
|
||||
}
|
||||
super.save(sysPost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePost(UpdatePostDTO updateDTO) {
|
||||
Long postId = updateDTO.getPostId();
|
||||
SysPost sysPost = super.getById(postId);
|
||||
if (sysPost == null) {
|
||||
throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, postId, "职位");
|
||||
}
|
||||
BeanUtil.copyProperties(updateDTO, sysPost, "postId");
|
||||
if (this.isPostNameDuplicated(postId, sysPost.getPostName())) {
|
||||
throw new BizException(ErrorCode.Business.POST_NAME_IS_NOT_UNIQUE, sysPost.getPostName());
|
||||
}
|
||||
if (this.isPostCodeDuplicated(postId, sysPost.getPostCode())) {
|
||||
throw new BizException(ErrorCode.Business.POST_CODE_IS_NOT_UNIQUE, sysPost.getPostCode());
|
||||
}
|
||||
super.updateById(sysPost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePost(List<Long> ids) {
|
||||
// 检测职位是否分配给用户
|
||||
sysUserService.checkAnyPostIsAssignedToUser(ids);
|
||||
super.removeBatchByIds(ids);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private boolean isPostNameDuplicated(Long postId, String postName) {
|
||||
LambdaQueryWrapper<SysPost> queryWrapper = Wrappers.lambdaQuery(SysPost.class)
|
||||
.ne(postId != null, SysPost::getPostId, postId)
|
||||
.eq(SysPost::getPostName, postName);
|
||||
return baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
private boolean isPostCodeDuplicated(Long postId, String postCode) {
|
||||
LambdaQueryWrapper<SysPost> queryWrapper = Wrappers.lambdaQuery(SysPost.class)
|
||||
.ne(postId != null, SysPost::getPostId, postId)
|
||||
.eq(SysPost::getPostCode, postCode);
|
||||
return baseMapper.exists(queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.agileboot.system.role.controller;
|
||||
|
||||
import com.agileboot.common.core.core.R;
|
||||
import com.agileboot.common.core.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.common.mybatis.core.page.PageR;
|
||||
import com.agileboot.system.role.dto.*;
|
||||
import com.agileboot.system.role.service.ISysRoleService;
|
||||
import com.agileboot.system.role.vo.RoleVO;
|
||||
import com.agileboot.system.user.dto.UserInfo;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色信息
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/role")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
public class SysRoleController {
|
||||
|
||||
private final ISysRoleService sysRoleService;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public PageR<RoleVO> list(RoleQuery query) {
|
||||
PageR<RoleVO> page = sysRoleService.getRoleList(query);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色列表导出
|
||||
*/
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, RoleQuery query) {
|
||||
PageR<RoleVO> page = sysRoleService.getRoleList(query);
|
||||
CustomExcelUtil.writeToResponse(page.getRows(), RoleVO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色编号获取详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{roleId}")
|
||||
public R<RoleVO> getInfo(@PathVariable @NotNull Long roleId) {
|
||||
RoleVO roleInfo = sysRoleService.getRoleInfo(roleId);
|
||||
return R.ok(roleInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public R<Void> add(@RequestBody AddRoleDTO addDTO) {
|
||||
sysRoleService.addRole(addDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除角色
|
||||
*/
|
||||
@PostMapping(value = "/{roleId}")
|
||||
public R<Void> remove(@PathVariable("roleId") List<Long> roleIds) {
|
||||
sysRoleService.deleteRole(roleIds);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存角色
|
||||
*/
|
||||
@PostMapping
|
||||
public R<Void> edit(@Validated @RequestBody UpdateRoleDTO updateDTO) {
|
||||
sysRoleService.updateRole(updateDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存数据权限
|
||||
*/
|
||||
@PostMapping("/{roleId}/dataScope")
|
||||
public R<Void> dataScope(@PathVariable("roleId") Long roleId,
|
||||
@RequestBody UpdateDataScopeDTO updateDTO) {
|
||||
updateDTO.setRoleId(roleId);
|
||||
sysRoleService.updateDataScope(updateDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色状态修改
|
||||
*/
|
||||
@PostMapping("/{roleId}/status")
|
||||
public R<Void> changeStatus(@PathVariable("roleId") Long roleId,
|
||||
@RequestBody UpdateStatusDTO updateDTO) {
|
||||
updateDTO.setRoleId(roleId);
|
||||
|
||||
sysRoleService.updateStatus(updateDTO);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@GetMapping("/{roleId}/allocated/list")
|
||||
public PageR<UserInfo> allocatedUserList(@PathVariable("roleId") Long roleId,
|
||||
AllocatedRoleQuery query) {
|
||||
query.setRoleId(roleId);
|
||||
PageR<UserInfo> page = sysRoleService.getAllocatedUserList(query);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@GetMapping("/{roleId}/unallocated/list")
|
||||
public PageR<UserInfo> unallocatedUserList(@PathVariable("roleId") Long roleId,
|
||||
UnallocatedRoleQuery query) {
|
||||
query.setRoleId(roleId);
|
||||
PageR<UserInfo> page = sysRoleService.getUnallocatedUserList(query);
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量取消授权用户
|
||||
*/
|
||||
@PostMapping("/users/{userIds}/grant/bulk")
|
||||
public R<Void> deleteRoleOfUserByBulk(@PathVariable("userIds") List<Long> userIds) {
|
||||
sysRoleService.deleteRoleOfUserByUserIds(userIds);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@PostMapping("/{roleId}/users/{userIds}/grant/bulk")
|
||||
public R<Void> addRoleForUserByBulk(@PathVariable("roleId") Long roleId,
|
||||
@PathVariable("userIds") List<Long> userIds) {
|
||||
sysRoleService.addRoleOfUserByByUserIds(roleId, userIds);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user