feat: 项目初始化

This commit is contained in:
张云杰 2025-08-28 15:28:10 +08:00
commit 6f8726000d
222 changed files with 12454 additions and 0 deletions

35
.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
*.class
# Package Files #
*.jar
*.war
*.ear
target/
# eclipse
.settings/
.classpath
.project
logs/
# idea
.idea/
*.iml
.murphy.yml
*velocity.log*
### STS ###
.apt_generated
.factorypath
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.ipr
*.log
tmp/
!DmJdbcDriver18.jar
!kingbase8-8.6.0.jar
/upload/

1
README.md Normal file
View File

@ -0,0 +1 @@
## 明君官网java代码

105
cloud-admin/pom.xml Normal file
View File

@ -0,0 +1,105 @@
<?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.byhah</groupId>
<artifactId>cloud</artifactId>
<version>1.0.2-SNAPSHOT</version>
</parent>
<artifactId>cloud-admin</artifactId>
<dependencies>
<!--<dependency>-->
<!-- <groupId>com.byhah.deploy</groupId>-->
<!-- <artifactId>byhah-deploy-basic-email</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-basic-sms</artifactId>
<exclusions>
<exclusion>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-basic-sse</artifactId>
</dependency>
<!--基础依赖-->
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-starter-json</artifactId>
</dependency>
<dependency>
<groupId>com.byhah.deploy</groupId>
<artifactId>byhah-deploy-starter-redisson</artifactId>
</dependency>
<!--本地starter-->
<dependency>
<groupId>com.byhah</groupId>
<artifactId>cloud-starter-orm</artifactId>
</dependency>
<!-- beetl模板引擎 -->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
</dependency>
<!--系统硬件信息-->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
</dependency>
<!-- sa-token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- sa-token 整合 redis 使用jackson序列化方式 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson</artifactId>
</dependency>
<!-- poi-tl -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,19 @@
package com.byhah.cloud.admin;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@MapperScan("com.byhah.cloud.admin.mapper")
@SpringBootApplication
public class AdminApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(AdminApplication.class);
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);
}
}

View File

@ -0,0 +1,85 @@
package com.byhah.cloud.admin.config;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.byhah.cloud.admin.module.dev.util.DevLogUtil;
import com.byhah.cloud.admin.utils.LoginUser;
import com.byhah.cloud.admin.utils.UserUtil;
import io.swagger.v3.oas.annotations.Operation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 业务日志aop切面
*/
@Aspect
@Order
@Component
public class DevLogAop {
/**
* 日志切入点
*/
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
private void getLogPointCut() {
}
/**
* 操作成功返回结果记录日志
*/
@AfterReturning(pointcut = "getLogPointCut()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Operation operation = method.getAnnotation(Operation.class);
if (operation != null) {
String description = operation.description();
if (!description.startsWith("ignore")) {
String userName = "未知";
try {
LoginUser loginUser = UserUtil.getLoginUser();
if (ObjectUtil.isNotNull(loginUser)) {
userName = loginUser.getName();
}
} catch (Exception ignored) {
}
// 异步记录日志
DevLogUtil.executeOperationLog(operation.summary(), userName, joinPoint, JSONUtil.toJsonStr(result));
}
}
}
/**
* 操作发生异常记录日志
*/
@AfterThrowing(pointcut = "getLogPointCut()", throwing = "exception")
public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Operation operation = method.getAnnotation(Operation.class);
if (operation != null) {
String description = operation.description();
if (!description.startsWith("ignore")) {
String userName = "未知";
try {
LoginUser loginUser = UserUtil.getLoginUser();
if (ObjectUtil.isNotNull(loginUser)) {
userName = loginUser.getName();
}
} catch (Exception ignored) {
}
// 异步记录日志
DevLogUtil.executeExceptionLog(operation.summary(), userName, joinPoint, exception);
}
}
}
}

View File

@ -0,0 +1,116 @@
package com.byhah.cloud.admin.config;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import com.byhah.cloud.admin.utils.UserUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* 配置
**/
@Configuration
public class GlobalConfigure implements WebMvcConfigurer {
/**
* 无需登录的接口地址集合
*/
private static final String[] NO_LOGIN_PATH_ARR = {
/* 主入口 */
"/",
/* 静态资源 */
"/favicon.ico",
"/doc.html",
"/webjars/**",
"/swagger-resources/**",
"/v3/api-docs",
"/v3/api-docs/**",
"/v3/api-docs-ext",
/* 认证相关 */
"/auth/getPhoneValidCode",
"/auth/doLogin",
/* 系统基础配置 */
"/dev/config/sysBaseList",
/* 系统字典树 */
"/dev/dict/tree",
/* 文件下载 */
"/dev/file/download",
"/anon/**",
// 健康检测
"/actuator/health"
};
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns(NO_LOGIN_PATH_ARR);
}
/**
* 权限认证接口实现类集成权限认证功能
**/
@Component
public static class StpInterfaceImpl implements StpInterface {
/**
* 返回一个账号所拥有的权限码集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
return CollUtil.newArrayList(UserUtil.getLoginUser().getPermissionCodeList());
}
/**
* 返回一个账号所拥有的角色标识集合
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
return CollUtil.newArrayList(UserUtil.getLoginUser().getRoleCodeList());
}
}
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.setBeforeAuth(obj -> {
// ---------- 设置跨域响应头 ----------
SaHolder.getResponse()
// 是否启用浏览器默认XSS防护 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时停止渲染页面
.setHeader("X-XSS-Protection", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
// 允许指定域访问跨域资源
.setHeader("Access-Control-Allow-Origin", "*")
// 允许所有请求方式
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
// 有效时间
.setHeader("Access-Control-Max-Age", "3600")
// 允许的header参数
.setHeader("Access-Control-Allow-Headers", "*");
// 如果是预检请求则立即返回到前端
SaRouter.match(SaHttpMethod.OPTIONS)
// OPTIONS预检请求不做处理
.free(r -> {
})
.back();
});
}
}

View File

@ -0,0 +1,166 @@
package com.byhah.cloud.admin.config;
import cn.dev33.satoken.exception.DisableServiceException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.starter.web.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import java.util.Iterator;
import java.util.Objects;
/**
* 全局异常处理器
**/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 数据验证异常 400
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
public R<String> requestException(Exception e) {
log.warn("[参数异常] {}", e.getMessage());
BindingResult bindingResult = null;
if (e instanceof BindException) {
bindingResult = ((BindException) e).getBindingResult();
} else if (e instanceof MethodArgumentNotValidException) {
bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
}
String errText = e.getMessage();
if (Objects.nonNull(bindingResult)) {
Iterator<FieldError> iterator = bindingResult.getFieldErrors().iterator();
if (!iterator.hasNext()) {
errText = "";
} else {
StringBuilder sb = new StringBuilder();
sb.append('[');
while (true) {
FieldError fieldError = iterator.next();
sb.append(fieldError.getDefaultMessage());
if (!iterator.hasNext()) {
sb.append(']');
errText = sb.toString();
break;
}
sb.append(',').append(' ');
}
}
}
return R.error(String.format("请求参数错误:%s", errText));
}
/**
* 未传参 400
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public R<Void> httpMessageNotReadableException() {
return R.error("传入数据有误");
}
/**
* 400
* controller 入参转换异常
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({MethodArgumentTypeMismatchException.class, ConversionFailedException.class})
public R<Void> methodArgumentTypeMismatchException(Exception e) {
log.warn("[全局异常] - 入参类型转换异常: [{}]", e.getMessage());
return R.error("参数类型错误");
}
/**
* 未登录 401
*/
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(NotLoginException.class)
public R<String> notLoginException() {
return R.error("未登录");
}
/**
* 没有权限 403
*/
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler({NotRoleException.class, NotPermissionException.class, DisableServiceException.class})
public R<String> forbidden() {
return R.error("权限不足");
}
/**
* 无接口 404
*/
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({NoResourceFoundException.class})
public R<String> notFound() {
return R.error("无路径");
}
/**
* 请求方法错误 405
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<String> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
return R.error("不支持的请求方法");
}
/**
* 不支持的MediaType 415
*/
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler({HttpMediaTypeNotSupportedException.class})
public R<String> httpMessageNotReadableException(Exception e) {
return R.error("不支持的MediaType");
}
/**
* 业务异常
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(CommonException.class)
public R<String> handlerCommonException(CommonException e) {
log.warn("[业务异常] {}", e.getMessage());
return R.error(e.getMsg());
}
/**
* 运行时异常
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class)
public R<String> runtimeException(RuntimeException e) {
log.error("[运行时异常] ", e);
return R.error(e.getMessage());
}
/**
* 未知异常
**/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public R<String> handleException(Exception e) {
log.error("[未知异常] ", e);
return R.error("未知错误");
}
}

View File

@ -0,0 +1,120 @@
package com.byhah.cloud.admin.listener;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.byhah.cloud.admin.module.dev.util.DevLogUtil;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import com.byhah.cloud.admin.module.sys.service.SysUserService;
import java.util.Objects;
/**
* 自定义登录监听器
**/
@Component
@RequiredArgsConstructor
public class AuthListener implements SaTokenListener {
private final SysUserService userService;
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
// 更新用户的登录时间和登录ip等信息
userService.updateUserLoginInfo(Convert.toLong(loginId), loginModel.getDevice());
// 记录登录日志
Object name = loginModel.getExtra("name");
if (ObjectUtil.isNotEmpty(name)) {
DevLogUtil.executeLoginLog(Convert.toStr(name));
} else {
DevLogUtil.executeLoginLog(null);
}
}
/**
* 每次注销时触发
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
// 记录登出日志
SysUser user = userService.getById(Convert.toLong(loginId));
if (Objects.nonNull(user)) {
DevLogUtil.executeLogoutLog(user.getName());
} else {
DevLogUtil.executeLogoutLog(null);
}
}
/**
* 每次被踢下线时触发
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
// ...
}
/**
* 每次被顶下线时触发
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
// ...
}
/**
* 每次被封禁时触发
*/
@Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
// ...
}
/**
* 每次被解封时触发
*/
@Override
public void doUntieDisable(String loginType, Object loginId, String service) {
// ...
}
@Override
public void doOpenSafe(String s, String s1, String s2, long l) {
}
@Override
public void doCloseSafe(String s, String s1, String s2) {
}
/**
* 每次创建Session时触发
*/
@Override
public void doCreateSession(String id) {
// ...
}
/**
* 每次注销Session时触发
*/
@Override
public void doLogoutSession(String id) {
// ...
}
/**
* 每次Token续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
// ...
}
}

View File

@ -0,0 +1,18 @@
package com.byhah.cloud.admin.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSearchDto;
import com.byhah.cloud.admin.module.dev.vo.DevMessageVo;
import org.apache.ibatis.annotations.Param;
import org.springframework.context.annotation.Primary;
import com.byhah.cloud.orm.mapper.dev.IDevMessageMapper;
/**
* 站内信Mapper接口
**/
@Primary
public interface DevMessageMapper extends IDevMessageMapper {
IPage<DevMessageVo> messages(Page<?> page, @Param("dto") DevMessageSearchDto dto);
}

View File

@ -0,0 +1,22 @@
package com.byhah.cloud.admin.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.cloud.admin.module.sys.dto.SysOrgSearchDto;
import com.byhah.cloud.admin.module.sys.dto.SysUserSearchDto;
import com.byhah.cloud.admin.module.sys.vo.SysOrgVo;
import com.byhah.cloud.admin.module.sys.vo.SysUserVo;
import com.byhah.cloud.orm.mapper.sys.ISysUserMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.context.annotation.Primary;
import java.util.Set;
@Primary
public interface SysUserMapper extends ISysUserMapper {
IPage<SysUserVo> sysUsers(Page<?> page, @Param("dto") SysUserSearchDto dto);
IPage<SysOrgVo> sysOrgs(Page<?> page, @Param("dto") SysOrgSearchDto dto);
Set<String> selectPermissionCodeByRoles(@Param("roles") Set<String> roles);
}

View File

@ -0,0 +1,51 @@
package com.byhah.cloud.admin.module.auth.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.auth.dto.PwdLoginDto;
import com.byhah.cloud.admin.module.auth.service.AuthService;
import com.byhah.cloud.admin.module.auth.vo.LoginResult;
import com.byhah.cloud.admin.utils.LoginUser;
import com.byhah.cloud.admin.utils.UserUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 登录
*/
@Tag(name = "登录")
@RestController
@RequestMapping("/auth")
@Validated
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@Operation(summary = "账号密码登录")
@PostMapping("/doLogin")
public R<LoginResult> doLogin(@RequestBody @Valid PwdLoginDto dto) {
return R.ok(authService.doLogin(dto));
}
@Operation(summary = "退出")
@SaCheckLogin
@GetMapping("/doLogout")
public R<String> doLogout() {
StpUtil.logout();
return R.ok();
}
@Operation(summary = "获取用户信息")
@SaCheckLogin
@GetMapping("/getLoginUser")
public R<LoginUser> getLoginUser() {
return R.ok(UserUtil.getLoginUser());
}
}

View File

@ -0,0 +1,58 @@
package com.byhah.cloud.admin.module.auth.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.byhah.cloud.admin.module.auth.vo.AuthSessionAnalysisVo;
import com.byhah.cloud.admin.module.auth.vo.AuthSessionVo;
import com.byhah.cloud.admin.module.auth.service.AuthSessionService;
import com.byhah.deploy.starter.web.R;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
@Tag(name = "会话治理")
@RestController
@RequestMapping("/auth/session")
@Validated
@RequiredArgsConstructor
public class AuthSessionController {
private final AuthSessionService authSessionService;
@Operation(summary = "会话统计")
@GetMapping("/analysis")
public R<AuthSessionAnalysisVo> analysis() {
return R.ok(authSessionService.analysis());
}
@Operation(summary = "查询会话")
@GetMapping("/page")
public R<Page<AuthSessionVo>> pageForB() {
return R.ok(authSessionService.pageForB(PageUtils.toPage()));
}
@Operation(summary = "强退会话")
@PostMapping("/exit")
public R<String> exitSessionForB(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> dto) {
authSessionService.exitSession(dto);
return R.ok();
}
@Operation(summary = "强退token")
@PostMapping("/exitToken")
public R<String> exitTokenForB(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<String> dto) {
authSessionService.exitToken(dto);
return R.ok();
}
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* Session退出参数
*
*/
@Data
public class AuthExitSessionDto {
/** 用户id */
@Schema(description = "用户id", required = true)
@NotBlank(message = "userId不能为空")
private String userId;
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* Token退出参数
*
*/
@Data
public class AuthExitTokenDto {
/** token值 */
@Schema(description = "token值", required = true)
@NotBlank(message = "tokenValue不能为空")
private String tokenValue;
}

View File

@ -0,0 +1,35 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 获取手机验证码参数
**/
@Data
public class AuthPhoneDto {
/**
* 手机号
*/
@Schema(description = "手机号", required = true)
@NotBlank(message = "手机号不能为空")
private String phone;
/**
* 验证码
*/
@Schema(description = "验证码", required = true)
@NotBlank(message = "验证码不能为空")
private String validCode;
/**
* 验证码请求号
*/
@Schema(description = "验证码请求号", required = true)
@NotBlank(message = "验证码请求号不能为空")
private String validCodeReqNo;
}

View File

@ -0,0 +1,14 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 会话查询参数
*
**/
@Data
public class AuthSessionPageParam {
private String searchKey;
}

View File

@ -0,0 +1,32 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
@Data
public class PhoneLoginDto {
/**
* 手机号
*/
@Schema(description = "手机号", required = true)
@NotBlank(message = "手机号不能为空")
private String phone;
/**
* 验证码
*/
@Schema(description = "验证码", required = true)
@NotBlank(message = "验证码不能为空")
private String validCode;
/**
* 验证码请求号
*/
@Schema(description = "验证码请求号", required = true)
@NotBlank(message = "验证码请求号不能为空")
private String validCodeReqNo;
}

View File

@ -0,0 +1,23 @@
package com.byhah.cloud.admin.module.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 账号密码登录参数
**/
@Data
public class PwdLoginDto {
@Schema(description = "账号", required = true)
@NotBlank(message = "账号不能为空")
private String account;
@Schema(description = "密码", required = true)
@NotBlank(message = "密码不能为空")
private String password;
@Schema(description = "登录选取的目标id")
private Long targetId;
}

View File

@ -0,0 +1,133 @@
package com.byhah.cloud.admin.module.auth.service;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.byhah.cloud.admin.mapper.SysUserMapper;
import com.byhah.cloud.admin.module.auth.dto.PwdLoginDto;
import com.byhah.cloud.admin.module.auth.vo.LoginResult;
import com.byhah.cloud.admin.module.sys.service.SysUserService;
import com.byhah.cloud.admin.utils.LoginDataScope;
import com.byhah.cloud.admin.utils.LoginUser;
import com.byhah.cloud.basic.constant.ConfigKey;
import com.byhah.cloud.basic.constant.RoleCode;
import com.byhah.cloud.basic.core.entity.system.SysRole;
import com.byhah.cloud.basic.core.entity.system.SysTenant;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import com.byhah.cloud.basic.core.enums.Gender;
import com.byhah.cloud.basic.core.enums.PlatformType;
import com.byhah.cloud.basic.core.enums.auth.AuthExceptionEnum;
import com.byhah.cloud.basic.core.util.CryptogramUtil;
import com.byhah.cloud.orm.mapper.sys.ISysTenantMapper;
import com.byhah.cloud.orm.support.service.DevSupportService;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.core.utils.Asserts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.*;
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {
private final ISysTenantMapper tenantMapper;
private final SysUserMapper sysUserMapper;
private final SysUserService userService;
private final DevSupportService devSupportService;
public LoginResult doLogin(PwdLoginDto dto) {
String account = dto.getAccount();
String password = dto.getPassword();
String passwordHash;
try {
// 做哈希值
passwordHash = CryptogramUtil.doHashValue(password);
} catch (Exception e) {
throw new CommonException(AuthExceptionEnum.PWD_DECRYPT_ERROR.getValue());
}
SysUser user = userService.getUserByAccount(account);
Asserts.notNull(user, AuthExceptionEnum.ACCOUNT_ERROR.getValue());
Asserts.isEquals(user.getPassword(), passwordHash, AuthExceptionEnum.PWD_ERROR.getValue());
// 执行登录
return execLogin(user, dto.getTargetId());
}
/**
* 执行登录
**/
private LoginResult execLogin(SysUser user, Long targetId) {
String account = user.getAccount();
// 校验状态
Asserts.isTrue(user.getStatus(), AuthExceptionEnum.ACCOUNT_DISABLED.getValue());
List<LoginResult.LoginOrgItem> orgItems = new ArrayList<>();
// 填充系统级
List<SysRole> roleList = userService.getRoleList(user.getId());
if (CollUtil.isNotEmpty(roleList)) {
orgItems.add(new LoginResult.LoginOrgItem(-1L, "不选择", 1));
}
// 租户级
SysTenant tenant = tenantMapper.lambdaQueryChain().eq(SysTenant::getAccount, account).one();
if (Objects.nonNull(tenant)) {
orgItems.add(new LoginResult.LoginOrgItem(tenant.getId(), tenant.getName(), 2));
}
Set<String> roles = new HashSet<>();
// 登录的类型 1-系统 2-租户
Integer userType;
// 选择了具体登录对象
if (Objects.nonNull(targetId)) {
if (targetId.equals(-1L)) {
userType = 1;
} else {
// 选择了对象
Long finalTargetId = targetId;
Optional<LoginResult.LoginOrgItem> any = orgItems.stream().filter(x -> finalTargetId.equals(x.getId())).findAny();
Asserts.isTrue(any.isPresent(), "选择部门不存在,请刷新后重试");
LoginResult.LoginOrgItem orgItem = any.get();
userType = orgItem.getType();
}
} else if (orgItems.size() == 1) {
// 只有一个部门 直接登录
userType = orgItems.getFirst().getType();
targetId = orgItems.getFirst().getId();
} else {
Asserts.isTrue(CollUtil.isNotEmpty(orgItems), "无角色信息");
return new LoginResult(orgItems);
}
LoginDataScope dataScope = new LoginDataScope();
if (userType == 1) {
roles.addAll(roleList.stream().map(SysRole::getCode).toList());
} else if (userType == 2) {
roles.add(RoleCode.TENANT);
dataScope.setTenantId(targetId);
}
Asserts.isTrue(CollUtil.isNotEmpty(roles), "用户无角色信息");
// 执行登录
StpUtil.login(user.getId(), new SaLoginModel().setDevice(String.valueOf(PlatformType.ADMIN.getType())).setExtra("name", user.getName()));
// 角色码集合
LoginUser loginUser = new LoginUser();
BeanUtils.copyProperties(user, loginUser);
loginUser.setGender(Optional.ofNullable(user.getGender()).map(Gender::getType).orElse(null));
// 工作台快捷方式
if (Objects.isNull(user.getWorkBenchData())) {
String dataStr = devSupportService.getConfig(ConfigKey.Sys.SYS_DEFAULT_WORKBENCH_DATA_KEY);
user.setWorkBenchData(JSONUtil.toBean(dataStr, SysUser.WorkBenchData.class));
}
// 获取权限码
loginUser.setPermissionCodeList(sysUserMapper.selectPermissionCodeByRoles(roles));
// 获取角色码
loginUser.setRoleCodeList(roles);
loginUser.setDataScope(dataScope);
// 缓存用户信息此处使用TokenSession为了指定时间内无操作则自动下线
StpUtil.getTokenSession().set("user", loginUser);
// 返回token
return new LoginResult(StpUtil.getTokenInfo().tokenValue);
}
}

View File

@ -0,0 +1,125 @@
package com.byhah.cloud.admin.module.auth.service;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.*;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.byhah.cloud.admin.module.auth.vo.AuthSessionAnalysisVo;
import com.byhah.cloud.admin.module.auth.vo.AuthSessionVo;
import com.byhah.cloud.admin.module.sys.service.SysUserService;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* 会话治理Service接口实现类
*/
@Service
@RequiredArgsConstructor
public class AuthSessionService {
private final SysUserService userService;
public AuthSessionAnalysisVo analysis() {
AuthSessionAnalysisVo vo = new AuthSessionAnalysisVo();
List<JSONObject> sessionList = StpUtil.searchSessionId("", -1, -1, true).stream().map(sessionId -> {
JSONObject jsonObject = JSONUtil.createObj();
String userId = StrUtil.split(sessionId, StrUtil.COLON).get(3);
SaSession saSession = StpUtil.getSessionByLoginId(userId, false);
int tokenCount = saSession.getTokenSignList().size();
long createTime = saSession.getCreateTime();
jsonObject.set("userId", userId);
jsonObject.set("tokenCount", tokenCount);
jsonObject.set("createTime", DateTime.of(createTime));
return jsonObject;
}).toList();
List<Integer> tokenCountList = CollectionUtil.newArrayList();
tokenCountList.addAll(sessionList.stream().map(jsonObject -> jsonObject.getInt("tokenCount")).collect(Collectors.toList()));
CollectionUtil.sort(tokenCountList, Comparator.comparingInt(Integer::intValue));
int currentSessionTotalCount = sessionList.size();
vo.setCurrentSessionTotalCount(Convert.toStr(currentSessionTotalCount));
vo.setMaxTokenCount(Convert.toStr(tokenCountList.get(tokenCountList.size() - 1)));
List<Date> sessionCreateTimeList = CollectionUtil.newArrayList();
sessionCreateTimeList.addAll(sessionList.stream().map(jsonObject -> jsonObject.getDate("createTime")).collect(Collectors.toList()));
DateTime oneHourAgo = DateUtil.offset(DateTime.now(), DateField.HOUR, -1);
vo.setOneHourNewlyAdded(Convert.toStr(sessionCreateTimeList.stream().filter(date -> DateUtil.compare(oneHourAgo, date) <= 0).count()));
return vo;
}
public Page<AuthSessionVo> pageForB(Page<AuthSessionVo> defaultPage) {
long current = defaultPage.getCurrent();
int total = StpUtil.searchSessionId("", -1, Convert.toInt(defaultPage.getSize()), true).size();
if (ObjectUtil.isNotEmpty(total)) {
defaultPage = new Page<>(current, defaultPage.getSize(), total);
List<Long> userIdList = StpUtil.searchSessionId("",
Convert.toInt((current - 1) * defaultPage.getSize()),
Convert.toInt(defaultPage.getSize()), true).stream().map(sessionId ->
Long.valueOf(StrUtil.split(sessionId, StrUtil.COLON).get(3))).collect(Collectors.toList());
if (ObjectUtil.isNotEmpty(userIdList)) {
List<AuthSessionVo> vo = userService.listByIds(userIdList).stream().map(userJsonObject -> {
SaSession saSession = StpUtil.getSessionByLoginId(userJsonObject.getId(), false);
AuthSessionVo res = new AuthSessionVo();
BeanUtils.copyProperties(userJsonObject, res);
res.setSessionId(saSession.getId());
res.setSessionCreateTime(LocalDateTimeUtil.of(saSession.getCreateTime()));
long sessionTimeOut = saSession.getTimeout();
if (sessionTimeOut == -1) {
res.setSessionTimeout("永久");
} else {
res.setSessionTimeout(DateUtil.formatBetween(saSession.getTimeout(), BetweenFormatter.Level.SECOND));
}
List<AuthSessionVo.TokenSignInfo> tokenInfoList = saSession.getTokenSignList().stream().map(tokenSign -> {
AuthSessionVo.TokenSignInfo tokenSignInfo = new AuthSessionVo.TokenSignInfo();
tokenSignInfo.setTokenValue(tokenSign.getValue());
tokenSignInfo.setTokenDevice(tokenSign.getDevice());
long tokenTimeout = SaManager.getSaTokenDao().getTimeout(StpUtil.stpLogic.splicingKeyTokenValue(tokenSign.getValue()));
long tokenTimeoutConfig = StpUtil.stpLogic.getConfigOrGlobal().getTimeout();
if (tokenTimeout == -1) {
tokenSignInfo.setTokenTimeout("永久");
tokenSignInfo.setTokenTimeoutPercent(100d);
} else {
tokenSignInfo.setTokenTimeout(DateUtil.formatBetween(SaManager.getSaTokenDao()
.getTimeout(StpUtil.stpLogic.splicingKeyTokenValue(tokenSign.getValue())), BetweenFormatter.Level.SECOND));
if (tokenTimeoutConfig == -1) {
tokenSignInfo.setTokenTimeoutPercent(0d);
} else {
tokenSignInfo.setTokenTimeoutPercent(NumberUtil.div(tokenTimeout, tokenTimeoutConfig));
}
}
return tokenSignInfo;
}).collect(Collectors.toList());
res.setTokenSignList(tokenInfoList);
return res;
}).collect(Collectors.toList());
defaultPage.setRecords(vo);
}
}
return defaultPage;
}
public void exitSession(List<Long> dto) {
dto.forEach(StpUtil::logout);
}
public void exitToken(List<String> dto) {
dto.forEach(StpUtil::logoutByTokenValue);
}
}

View File

@ -0,0 +1,26 @@
package com.byhah.cloud.admin.module.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 图片验证码结果
**/
@Data
@AllArgsConstructor
public class AuthPicValidCodeVo {
/**
* 验证码图片Base64
*/
@Schema(description = "验证码图片Base64")
private String validCodeBase64;
/**
* 验证码请求号
*/
@Schema(description = "验证码请求号")
private String validCodeReqNo;
}

View File

@ -0,0 +1,25 @@
package com.byhah.cloud.admin.module.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 会话统计结果
*
**/
@Data
public class AuthSessionAnalysisVo {
/** 当前会话总数量 */
@Schema(description = "当前会话总数量")
private String currentSessionTotalCount;
/** 最大签发令牌数 */
@Schema(description = "最大签发令牌数")
private String maxTokenCount;
/** 最近1小时会话数 */
@Schema(description = "最近1小时会话数")
private String oneHourNewlyAdded;
}

View File

@ -0,0 +1,70 @@
package com.byhah.cloud.admin.module.auth.vo;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 会话结果集
**/
@Data
public class AuthSessionVo {
@Schema(description = "id")
private Long id;
@Schema(description = "头像")
private String avatar;
@Schema(description = "账号")
private String account;
@Schema(description = "姓名")
private String name;
private SysUser.UserLoginInfo lastLoginInfo;
private SysUser.UserLoginInfo latestLoginInfo;
@Schema(description = "会话id")
private String sessionId;
@Schema(description = "会话创建时间")
private LocalDateTime sessionCreateTime;
@Schema(description = "会话剩余有效期")
private String sessionTimeout;
@Schema(description = "令牌信息集合")
private List<TokenSignInfo> tokenSignList;
@Data
public static class TokenSignInfo {
/**
* token值
*/
@Schema(description = "token值")
private String tokenValue;
/**
* 登录设备
*/
@Schema(description = "登录设备")
private String tokenDevice;
/**
* token剩余有效期
*/
@Schema(description = "token剩余有效期")
private String tokenTimeout;
/**
* token剩余有效期百分比
*/
@Schema(description = "token剩余有效期百分比")
private Double tokenTimeoutPercent;
}
}

View File

@ -0,0 +1,45 @@
package com.byhah.cloud.admin.module.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
public class LoginResult {
@Schema(description = "登录token")
private String token;
@Schema(description = "是否需要重新登录")
private boolean reLogin;
@Schema(description = "可供选择的登录对象")
private List<LoginOrgItem> orgItems;
@Data
@NoArgsConstructor
public static class LoginOrgItem {
private Long id;
private String name;
/**
* 1-系统级直接根据绑定角色查权限不区分数据权限 2-租户/tenant
*/
private Integer type;
public LoginOrgItem(Long id, String name, Integer type) {
this.id = id;
this.name = name;
this.type = type;
}
}
public LoginResult(String token) {
this.token = token;
}
public LoginResult(List<LoginOrgItem> items) {
this.orgItems = items;
this.reLogin = true;
}
}

View File

@ -0,0 +1,17 @@
package com.byhah.cloud.admin.module.common.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* excel通用处理service
*
* @author ZYJ
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ExcelCommonService {
}

View File

@ -0,0 +1,89 @@
package com.byhah.cloud.admin.module.dev.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.cloud.admin.module.dev.dto.*;
import com.byhah.cloud.admin.module.dev.service.DevConfigService;
import com.byhah.cloud.admin.module.dev.dto.DevConfigBatchParam;
import com.byhah.cloud.admin.module.dev.dto.DevConfigDto;
import com.byhah.cloud.admin.module.dev.dto.DevConfigSearchDto;
import com.byhah.cloud.basic.constant.ConfigKey;
import com.byhah.cloud.basic.core.entity.dev.DevConfig;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.deploy.starter.web.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Tag(name = "配置")
@RestController
@RequestMapping("/dev/config")
@RequiredArgsConstructor
public class DevConfigController {
private final DevConfigService service;
@Operation(summary = "获取配置分页")
@GetMapping("/page")
public R<Page<DevConfig>> page(DevConfigSearchDto dto) {
dto.setCategory(ConfigKey.SysCategory.BIZ_DEFINE);
return R.ok(service.page(PageUtils.toPage(), dto));
}
@Operation(summary = "获取系统基础配置")
@GetMapping("/sysBaseList")
public R<List<DevConfig>> sysBaseList() {
DevConfigSearchDto dto = new DevConfigSearchDto();
dto.setCategory(ConfigKey.SysCategory.SYS_BASE);
return R.ok(service.page(PageUtils.toNoSizePage(), dto).getRecords());
}
@Operation(summary = "获取配置列表")
@GetMapping("/list")
public R<List<DevConfig>> list(DevConfigSearchDto dto) {
return R.ok(service.page(PageUtils.toNoSizePage(), dto).getRecords());
}
@Operation(summary = "添加配置")
@PostMapping("/add")
public R<String> add(@RequestBody @Valid DevConfigDto dto) {
service.add(dto);
return R.ok();
}
@Operation(summary = "编辑配置")
@PostMapping("/edit")
public R<String> edit(@RequestBody @Validated(Update.class) DevConfigDto dto) {
service.edit(dto);
return R.ok();
}
@Operation(summary = "删除配置")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
service.delete(ids);
return R.ok();
}
@Operation(summary = "获取配置详情")
@GetMapping("/detail")
public R<DevConfig> detail(Long id) {
return R.ok(service.detail(id));
}
@Operation(summary = "配置批量更新")
@PostMapping("/editBatch")
public R<String> editBatch(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<DevConfigBatchParam> devConfigBatchParamList) {
service.editBatch(devConfigBatchParamList);
return R.ok();
}
}

View File

@ -0,0 +1,19 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.byhah.cloud.admin.module.dev.service.DevService;
import com.byhah.cloud.basic.constant.SystemKey;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "开发")
@RestController
@RequestMapping("/dev")
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class DevController {
private final static String PWD = "&h..C)Mk0TtZZPxv";
private final DevService devService;
}

View File

@ -0,0 +1,79 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.cloud.admin.module.dev.dto.DevDictDto;
import com.byhah.cloud.admin.module.dev.dto.DevDictSearchDto;
import com.byhah.cloud.admin.module.dev.service.DevDictService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.byhah.cloud.basic.core.entity.dev.DevDict;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.cloud.admin.module.dev.dto.*;
import com.byhah.deploy.starter.web.R;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Tag(name = "字典")
@RestController
@RequestMapping("/dev/dict")
@RequiredArgsConstructor
public class DevDictController {
private final DevDictService devDictService;
@Operation(summary = "获取字典分页")
@GetMapping("/page")
public R<IPage<DevDict>> page(DevDictSearchDto dto) {
return R.ok(devDictService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "获取字典列表")
@GetMapping("/list")
public R<List<DevDict>> list(DevDictSearchDto dto) {
return R.ok(devDictService.page(PageUtils.toNoSizePage(), dto).getRecords());
}
@Operation(summary = "获取字典树")
@GetMapping("/tree")
public R<List<Tree<Long>>> tree() {
return R.ok(devDictService.tree());
}
@Operation(summary = "添加字典")
@PostMapping("/add")
public R<String> add(@RequestBody @Validated(Insert.class) DevDictDto dto) {
devDictService.add(dto);
return R.ok();
}
@Operation(summary = "编辑字典")
@PostMapping("/edit")
public R<String> edit(@RequestBody @Validated(Update.class) DevDictDto dto) {
devDictService.edit(dto);
return R.ok();
}
@Operation(summary = "删除字典")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
devDictService.delete(ids);
return R.ok();
}
@Operation(summary = "获取字典详情")
@GetMapping("/detail")
public R<DevDict> detail(Long id) {
return R.ok(devDictService.detail(id));
}
}

View File

@ -0,0 +1,72 @@
package com.byhah.cloud.admin.module.dev.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.dev.dto.DevFileSearchDto;
import com.byhah.cloud.admin.module.dev.service.DevFileService;
import com.byhah.cloud.basic.core.entity.dev.DevFile;
import com.byhah.cloud.orm.support.service.DevSupportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
@Tag(name = "文件")
@RequestMapping("/dev/file")
@RestController
@RequiredArgsConstructor
public class DevFileController {
private final DevFileService devFileService;
private final DevSupportService devSupportService;
@Operation(summary = "上传文件返回url或id",description = "ignore")
@PostMapping("/upload")
R<String> upload(@RequestParam(required = false) Integer engine,@RequestParam(required = false) Long maxSize, @RequestParam(defaultValue = "false") Boolean returnId, @RequestPart("file") MultipartFile file) throws IOException {
return R.ok(devSupportService.upload(engine, returnId, maxSize, file));
}
@Operation(summary = "获取文件分页列表")
@GetMapping("/page")
R<Page<DevFile>> page(DevFileSearchDto dto) {
return R.ok(devFileService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "获取文件列表")
@GetMapping("/list")
R<List<DevFile>> list(DevFileSearchDto dto) {
return R.ok(devFileService.page(PageUtils.toNoSizePage(), dto).getRecords());
}
@Operation(summary = "下载文件")
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
void download(Long id, HttpServletResponse response) {
devFileService.download(id, response);
}
@Operation(summary = "删除文件")
@PostMapping(value = "/delete")
R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
devFileService.delete(ids);
return R.ok();
}
@Operation(summary = "获取文件详情")
@GetMapping("/detail")
R<DevFile> detail(Long id) {
return R.ok(devFileService.detail(id));
}
}

View File

@ -0,0 +1,32 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.cloud.admin.module.dev.dto.DevLogSearchDto;
import com.byhah.cloud.basic.constant.SystemKey;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.byhah.cloud.basic.core.entity.dev.DevLog;
import com.byhah.cloud.admin.module.dev.service.DevLogService;
import com.byhah.deploy.starter.web.R;
@Tag(name = "日志")
@RestController
@RequestMapping("/dev/log")
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class DevLogController {
private final DevLogService devLogService;
@Operation(summary = "获取日志分页")
@GetMapping("/page")
public R<Page<DevLog>> page(@Validated DevLogSearchDto dto) {
return R.ok(devLogService.page(PageUtils.toPage(), dto));
}
}

View File

@ -0,0 +1,57 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSearchDto;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSendDto;
import com.byhah.cloud.admin.module.dev.vo.DevMessageVo;
import com.byhah.cloud.basic.constant.SystemKey;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.cloud.admin.module.dev.service.DevMessageService;
import com.byhah.deploy.starter.web.R;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
@Tag(name = "站内信")
@RequestMapping("/dev/message")
@RestController
@SaCheckRole(value = SystemKey.SYS_ROLE)
@RequiredArgsConstructor
public class DevMessageController {
private final DevMessageService devMessageService;
@Operation(summary = "发送站内信")
@PostMapping("/send")
public R<Void> send(@RequestBody @Valid DevMessageSendDto dto) {
devMessageService.send(dto);
return R.ok();
}
@Operation(summary = "获取站内信分页")
@GetMapping("/page")
public R<IPage<DevMessageVo>> page(DevMessageSearchDto dto) {
return R.ok(devMessageService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "删除站内信")
@PostMapping("/delete")
public R<Void> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
devMessageService.delete(ids);
return R.ok();
}
@Operation(summary = "获取站内信详情")
@GetMapping("/detail")
public R<DevMessageVo> detail(Long id) {
return R.ok(devMessageService.detail(id));
}
}

View File

@ -0,0 +1,30 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.byhah.cloud.admin.module.dev.vo.DevMonitorServerVo;
import com.byhah.cloud.basic.constant.SystemKey;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.byhah.cloud.admin.module.dev.service.DevMonitorService;
import com.byhah.deploy.starter.web.R;
@Tag(name = "监控")
@RestController
@RequestMapping("/dev/monitor")
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class DevMonitorController {
private final DevMonitorService devMonitorService;
@Operation(summary = "获取服务器监控信息")
@GetMapping("/serverInfo")
public R<DevMonitorServerVo> serverInfo() {
return R.ok(devMonitorService.serverInfo());
}
}

View File

@ -0,0 +1,61 @@
package com.byhah.cloud.admin.module.dev.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.cloud.admin.module.dev.dto.DevSmsSearchDto;
import com.byhah.cloud.admin.module.dev.dto.DevSmsSendDto;
import com.byhah.cloud.admin.module.dev.service.DevSmsService;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.dev.DevSms;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.starter.web.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
/**
* 短信
**/
@Tag(name = "短信")
@RestController
@SaCheckRole(value = SystemKey.SYS_ROLE)
@RequestMapping("/dev/sms")
@RequiredArgsConstructor
public class DevSmsController {
private final DevSmsService devSmsService;
@Operation(summary = "发送短信")
@PostMapping("/send")
R<Void> send(@RequestBody @Validated DevSmsSendDto dto) {
devSmsService.send(dto);
return R.ok();
}
@Operation(summary = "获取短信分页")
@GetMapping("/page")
public R<Page<DevSms>> page(DevSmsSearchDto dto) {
return R.ok(devSmsService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "删除短信")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
devSmsService.delete(ids);
return R.ok();
}
@Operation(summary = "获取短信详情")
@GetMapping("/detail")
public R<DevSms> detail(Long id) {
return R.ok(devSmsService.detail(id));
}
}

View File

@ -0,0 +1,25 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 配置批量更新参数
**/
@Data
public class DevConfigBatchParam {
/** 配置键 */
@Schema(description = "配置键", required = true)
@NotBlank(message = "configKey不能为空")
private String configKey;
/** 配置值 */
@Schema(description = "配置值", required = true)
@NotBlank(message = "configValue不能为空")
private String configValue;
}

View File

@ -0,0 +1,37 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* 配置添加参数
*/
@Data
public class DevConfigDto {
@Null(groups = Insert.class, message = "id必须为空")
@NotNull(groups = Update.class, message = "id不能为空")
private Long id;
@Schema(description = "配置键", required = true)
@NotBlank(message = "configKey不能为空")
private String configKey;
@Schema(description = "配置值", required = true)
@NotBlank(message = "configValue不能为空")
private String configValue;
@Schema(description = "备注")
private String remark;
@Schema(description = "排序码", required = true)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
}

View File

@ -0,0 +1,19 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 配置列表参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevConfigSearchDto extends CommonSearch {
/** 配置分类 */
@Schema(description = "配置分类")
private String category;
}

View File

@ -0,0 +1,39 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* 字典添加参数
*/
@Data
public class DevDictDto {
@Schema(description = "id")
@NotNull(message = "id不能为空", groups = Update.class)
@Null(message = "id不能为空", groups = Insert.class)
private Long id;
@Schema(description = "父id")
private Long parentId;
@Schema(description = "字典文字")
@NotBlank(message = "dictLabel不能为空")
private String label;
@Schema(description = "字典值")
@NotBlank(message = "dictValue不能为空")
private String value;
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,22 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 字典查询参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevDictSearchDto extends CommonSearch {
@Schema(description = "父id")
private Long parentId;
/** 字典分类 */
@Schema(description = "字典分类")
private String category;
}

View File

@ -0,0 +1,17 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 邮件查询参数
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevEmailSearchDto extends CommonSearch {
@Schema(description = "邮件引擎")
private Integer engine;
}

View File

@ -0,0 +1,58 @@
package com.byhah.cloud.admin.module.dev.dto;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import jakarta.validation.constraints.NotBlank;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
@Data
public class DevEmailSendDto {
@Schema(description = "发送引擎 1-本地 2-阿里 3-腾讯")
@Range(min = 1,max = 3)
private Integer engine;
@Schema(description = "发送类型 1-纯文本 2-html 3-模板")
@Range(min = 1,max = 3)
private Integer type;
@Schema(description = "发件人昵称 阿里和腾讯才有")
private String sendUser;
@Schema(description = "接收人邮箱地址,多个逗号拼接")
@NotBlank(message = "receiveAccounts不能为空")
private String receiveAccounts;
@Schema(description = "邮件主题")
@NotBlank(message = "subject不能为空")
private String subject;
@Schema(description = "邮件正文")
@NotBlank(message = "content不能为空")
private String content;
@Schema(description = "预先创建且通过审核的模板名称", required = true)
private String templateName;
@Schema(description = "预先创建且通过审核的模板的参数json")
private String templateParam;
@Schema(description = "标签名")
private String tagName;
@Schema(description = "图片展位符 本地html有")
private Map<String, InputStream> imageMap = MapUtil.newHashMap();
@Schema(description = "附件列表 本地邮件有")
private List<File> files = CollectionUtil.newArrayList();
@Schema(description = "附件列表 腾讯邮件有")
List<JSONObject> attachmentList = CollectionUtil.newArrayList();
}

View File

@ -0,0 +1,10 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class DevFileDto {
@Schema(description = "上传引擎,默认取系统设置 1-本地 2-阿里 3-腾讯 4-MINIO")
private Integer engine;
}

View File

@ -0,0 +1,18 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 文件分页列表参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevFileSearchDto extends CommonSearch {
@Schema(description = "文件引擎")
private Integer engine;
}

View File

@ -0,0 +1,21 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.NotNull;
/**
* 日志查询参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevLogSearchDto extends CommonSearch {
@Schema(description = "日志分类")
@NotNull
private Integer category;
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 站内信查询参数
**/
@Data
public class DevMessageSearchDto {
@Schema(description = "站内信分类")
private Integer category;
@Schema(description = "主题关键词")
private String searchKey;
@Schema(description = "接收用户id")
private Long receiveUserId;
}

View File

@ -0,0 +1,32 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 站内信发送参数
**/
@Data
public class DevMessageSendDto {
@Schema(description = "主题", required = true)
@NotBlank(message = "subject不能为空")
private String subject;
@Schema(description = "接收人id集合", required = true)
@NotEmpty(message = "receiverIdList不能为空")
private List<Long> receiverIdList;
@Schema(description = "正文")
private String content;
@Schema(description = "分类")
@NotNull(message = "category不能为空")
private Integer category;
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.dev.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信查询参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DevSmsSearchDto extends CommonSearch {
@Schema(description = "短信引擎")
private Integer engine;
@Schema(description = "手机号关键词")
private String searchKey;
}

View File

@ -0,0 +1,33 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 短信发送阿里云参数
*
*/
@Data
public class DevSmsSendAliyunParam {
/** 手机号 */
@Schema(description = "手机号,多个逗号拼接", required = true)
@NotBlank(message = "phoneNumbers不能为空")
private String phoneNumbers;
/** 模板编码 */
@Schema(description = "短信服务控制台配置且审核通过的模板编码", required = true)
@NotBlank(message = "templateCode不能为空")
private String templateCode;
/** 发送参数 */
@Schema(description = "短信模板变量对应的实际值JSON格式")
private String templateParam;
/** 短信签名 */
@Schema(description = "短信服务控制台配置且审核通过的短信签名")
private String signName;
}

View File

@ -0,0 +1,32 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DevSmsSendDto {
private Integer engine;
@Schema(description = "手机号,多个逗号拼接")
@NotBlank(message = "phoneNumbers不能为空")
private String phoneNumbers;
@Schema(description = "短信服务控制台配置且审核通过的模板编码")
@NotBlank(message = "templateCode不能为空")
private String templateCode;
@Schema(description = "短信模板变量对应的实际值JSON格式")
private String templateParam;
@Schema(description = "短信服务控制台配置且审核通过的短信签名")
private String signName;
@Schema(description = "在短信控制台添加应用后生成的实际SdkAppId 腾讯才有")
private String sdkAppId;
}

View File

@ -0,0 +1,37 @@
package com.byhah.cloud.admin.module.dev.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 短信发送阿里云参数
*
*/
@Data
public class DevSmsSendTencentParam {
/** 手机号 */
@Schema(description = "手机号,多个逗号拼接", required = true)
@NotBlank(message = "phoneNumbers不能为空")
private String phoneNumbers;
/** 模板编码 */
@Schema(description = "短信服务控制台配置且审核通过的模板编码", required = true)
@NotBlank(message = "templateCode不能为空")
private String templateCode;
/** 发送参数 */
@Schema(description = "短信模板变量对应的顺序。支持传入多个参数,逗号拼接")
private String templateParam;
/** sdkAppId */
@Schema(description = "在短信控制台添加应用后生成的实际SdkAppId")
private String sdkAppId;
/** 短信签名 */
@Schema(description = "短信服务控制台配置且审核通过的短信签名")
private String signName;
}

View File

@ -0,0 +1,12 @@
package com.byhah.cloud.admin.module.dev.dto.dev;
import lombok.Data;
import java.time.LocalDate;
@Data
public class PushMsgDto {
private Long targetId;
private Integer type;
private LocalDate date;
}

View File

@ -0,0 +1,15 @@
package com.byhah.cloud.admin.module.dev.dto.dev;
import lombok.Data;
import java.util.Map;
@Data
public class WxMpMsgDto {
private String wxMpAppId;
private String templateId;
private String toUsers;
private String page;
private Map<String, String> data;
private String appId;
}

View File

@ -0,0 +1,110 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.cloud.admin.module.dev.dto.DevConfigBatchParam;
import com.byhah.cloud.admin.module.dev.dto.DevConfigDto;
import com.byhah.cloud.admin.module.dev.dto.DevConfigSearchDto;
import com.byhah.cloud.basic.constant.ConfigKey;
import com.byhah.cloud.basic.core.entity.dev.DevConfig;
import com.byhah.cloud.orm.mapper.dev.IDevConfigMapper;
import com.byhah.cloud.orm.support.service.DevSupportService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class DevConfigService extends ServiceImpl<IDevConfigMapper, DevConfig> {
private final DevSupportService devSupportService;
public Page<DevConfig> page(Page<DevConfig> page, DevConfigSearchDto dto) {
String searchKey = dto.getSearchKey();
String category = dto.getCategory();
return lambdaQuery().eq(StrUtil.isNotBlank(searchKey), DevConfig::getConfigKey, searchKey)
.eq(StrUtil.isNotBlank(category), DevConfig::getCategory, category)
.orderByAsc(DevConfig::getSortCode)
.page(page);
}
public void add(DevConfigDto dto) {
checkParam(dto);
DevConfig devConfig = BeanUtil.toBean(dto, DevConfig.class);
devConfig.setCategory(ConfigKey.SysCategory.BIZ_DEFINE);
save(devConfig);
}
public void edit(DevConfigDto dto) {
DevConfig devConfig = queryEntity(dto.getId());
checkParam(dto);
BeanUtil.copyProperties(dto, devConfig);
devConfig.setCategory(ConfigKey.SysCategory.BIZ_DEFINE);
updateById(devConfig);
// 移除对应的缓存
devSupportService.removeConfigCache(devConfig.getConfigKey());
}
private void checkParam(DevConfigDto dto) {
boolean hasSameConfig = count(new LambdaQueryWrapper<DevConfig>()
.eq(DevConfig::getConfigKey, dto.getConfigKey())
.ne(Objects.nonNull(dto.getId()), DevConfig::getId, dto.getId())) > 0;
if (hasSameConfig) {
throw new CommonException("存在重复的配置,配置键为:{}", dto.getConfigKey());
}
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> ids) {
if (CollUtil.isNotEmpty(ids)) {
List<DevConfig> devConfigList = listByIds(ids);
if (ObjectUtil.isNotEmpty(devConfigList)) {
List<String> devConfigResultList = CollUtil.newArrayList(devConfigList.stream()
.map(DevConfig::getCategory).collect(Collectors.toSet()));
if (devConfigResultList.size() != 1 || !devConfigResultList.get(0).equals(ConfigKey.SysCategory.BIZ_DEFINE)) {
throw new CommonException("不可删除系统内置配置");
}
List<DevConfig> deleteDevConfigList = listByIds(ids);
// 执行删除
removeByIds(ids);
deleteDevConfigList.forEach(x -> devSupportService.removeConfigCache(x.getConfigKey()));
}
}
}
public DevConfig detail(Long id) {
return queryEntity(id);
}
public DevConfig queryEntity(Long id) {
DevConfig devConfig = getById(id);
if (ObjectUtil.isEmpty(devConfig)) {
throw new CommonException("配置不存在id值为{}", id);
}
return devConfig;
}
public void editBatch(List<DevConfigBatchParam> configs) {
configs.forEach(config -> {
lambdaUpdate().eq(DevConfig::getConfigKey, config.getConfigKey())
.set(DevConfig::getConfigValue, config.getConfigValue()).update();
// 移除对应的缓存
devSupportService.removeConfigCache(config.getConfigKey());
});
}
}

View File

@ -0,0 +1,116 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.core.utils.Asserts;
import com.byhah.cloud.admin.module.dev.dto.DevDictDto;
import com.byhah.cloud.admin.module.dev.dto.DevDictSearchDto;
import com.byhah.cloud.basic.core.entity.dev.DevDict;
import com.byhah.cloud.orm.mapper.dev.IDevDictMapper;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 字典Service接口实现类
**/
@Service
public class DevDictService extends ServiceImpl<IDevDictMapper, DevDict> {
public IPage<DevDict> page(Page<DevDict> page, DevDictSearchDto dto) {
return lambdaQuery().eq(Objects.nonNull(dto.getParentId()), DevDict::getParentId, dto.getParentId())
.like(StrUtil.isNotBlank(dto.getSearchKey()), DevDict::getLabel, dto.getSearchKey()).page(page);
}
public List<DevDict> list(DevDictSearchDto dto) {
LambdaQueryWrapper<DevDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
if (ObjectUtil.isNotEmpty(dto.getParentId())) {
lambdaQueryWrapper.eq(DevDict::getParentId, dto.getParentId());
}
return this.list(lambdaQueryWrapper);
}
public List<Tree<Long>> tree() {
LambdaQueryWrapper<DevDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.orderByAsc(DevDict::getSortCode);
List<DevDict> devDictList = this.list(lambdaQueryWrapper);
List<TreeNode<Long>> treeNodeList = devDictList.stream().map(devDict ->
new TreeNode<>(devDict.getId(), devDict.getParentId(),
devDict.getLabel(), devDict.getSortCode()).setExtra(JSONUtil.parseObj(devDict)))
.collect(Collectors.toList());
return TreeUtil.build(treeNodeList, 0L);
}
public void add(DevDictDto dto) {
checkParam(dto);
if (Objects.isNull(dto.getParentId())) {
dto.setParentId(0L);
}
DevDict devDict = BeanUtil.toBean(dto, DevDict.class);
this.save(devDict);
}
private void checkParam(DevDictDto dto) {
final Long id = dto.getId();
final Long parentId = dto.getParentId();
final String label = dto.getLabel();
final String value = dto.getValue();
Long count = lambdaQuery().eq(DevDict::getParentId, parentId)
.eq(DevDict::getLabel, label)
.ne(Objects.nonNull(id), DevDict::getId, id)
.count();
Asserts.isTrue(count == 0, String.format("存在重复的字典文字,名称为:%s", label));
count = lambdaQuery().eq(DevDict::getParentId, parentId)
.eq(DevDict::getValue, value)
.ne(Objects.nonNull(id), DevDict::getId, id)
.count();
Asserts.isTrue(count == 0, String.format("存在重复的字典值,名称为:%s", value));
}
public void edit(DevDictDto dto) {
DevDict devDict = this.queryEntity(dto.getId());
if (Objects.isNull(dto.getParentId())) {
dto.setParentId(0L);
}
checkParam(dto);
BeanUtil.copyProperties(dto, devDict);
this.updateById(devDict);
}
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
this.removeByIds(ids);
}
}
public DevDict detail(Long id) {
return this.queryEntity(id);
}
public DevDict queryEntity(Long id) {
DevDict devDict = this.getById(id);
if (ObjectUtil.isEmpty(devDict)) {
throw new CommonException("字典不存在id值为{}", id);
}
return devDict;
}
}

View File

@ -0,0 +1,74 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.dev.dto.DevFileSearchDto;
import com.byhah.cloud.orm.mapper.dev.IDevFileMapper;
import com.byhah.cloud.basic.core.entity.dev.DevFile;
import com.byhah.cloud.basic.core.enums.dev.DevFileEngine;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.util.web.DownloadUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.Objects;
/**
* 文件Service接口实现类
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class DevFileService extends ServiceImpl<IDevFileMapper, DevFile> {
public Page<DevFile> page(Page<DevFile> page, DevFileSearchDto dto) {
return lambdaQuery().eq(Objects.nonNull(dto.getEngine()), DevFile::getEngine, dto.getEngine())
.like(StrUtil.isNotBlank(dto.getSearchKey()), DevFile::getName, dto.getSearchKey())
.page(page);
}
public void download(Long id, HttpServletResponse response) {
DevFile devFile;
try {
devFile = queryEntity(id);
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
if (devFile.getEngine() != DevFileEngine.LOCAL) {
throw new CommonException("非本地文件不支持此方式下载id值为" + devFile.getId());
}
File file = FileUtil.file(devFile.getStoragePath());
if (!FileUtil.exist(file)) {
throw new CommonException("找不到存储的文件id值为" + devFile.getId());
}
DownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
}
public void delete(List<Long> ids) {
removeByIds(ids);
}
public DevFile detail(Long id) {
return queryEntity(id);
}
public DevFile queryEntity(Long id) {
DevFile devFile = getById(id);
if (ObjectUtil.isEmpty(devFile)) {
throw new CommonException("文件不存在id值为{}", id);
}
return devFile;
}
}

View File

@ -0,0 +1,24 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.dev.dto.DevLogSearchDto;
import com.byhah.cloud.orm.mapper.dev.IDevLogMapper;
import com.byhah.cloud.basic.core.entity.dev.DevLog;
import org.springframework.stereotype.Service;
/**
* 日志Service接口实现类
*/
@Service
public class DevLogService extends ServiceImpl<IDevLogMapper, DevLog> {
public Page<DevLog> page(Page<DevLog> page, DevLogSearchDto dto) {
return lambdaQuery().eq(DevLog::getCategory, dto.getCategory())
.like(StrUtil.isNotBlank(dto.getSearchKey()), DevLog::getName, dto.getSearchKey())
.orderByDesc(DevLog::getCreatedAt)
.page(page);
}
}

View File

@ -0,0 +1,118 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.mapper.DevMessageMapper;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSearchDto;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSendDto;
import com.byhah.cloud.admin.module.dev.vo.DevMessageVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.byhah.cloud.orm.mapper.dev.IDevMessageUserMapper;
import com.byhah.cloud.orm.mapper.sys.ISysUserMapper;
import com.byhah.cloud.basic.core.entity.dev.DevMessage;
import com.byhah.cloud.basic.core.entity.dev.DevMessageUser;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import com.byhah.cloud.basic.core.enums.dev.DevMessageType;
import com.byhah.deploy.basic.core.exception.CommonException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 站内信Service接口实现类
**/
@Service
@RequiredArgsConstructor
public class DevMessageService extends ServiceImpl<DevMessageMapper, DevMessage> {
private final ISysUserMapper sysUserMapper;
private final IDevMessageUserMapper messageUserMapper;
@Transactional(rollbackFor = Exception.class)
public void send(DevMessageSendDto dto) {
dto.setContent(ObjectUtil.isEmpty(dto.getContent()) ?
dto.getSubject() : dto.getContent());
dto.setCategory(ObjectUtil.isEmpty(dto.getCategory()) ?
DevMessageType.SYS.getType() : dto.getCategory());
DevMessage message = BeanUtil.toBean(dto, DevMessage.class);
save(message);
List<Long> receiverIds = dto.getReceiverIdList();
if (CollUtil.isNotEmpty(receiverIds)) {
for (Long receiverId : receiverIds) {
DevMessageUser messageUser = new DevMessageUser();
messageUser.setUserId(receiverId);
messageUser.setMessageId(message.getId());
messageUserMapper.insert(messageUser);
}
}
}
public IPage<DevMessageVo> page(Page<?> page, DevMessageSearchDto dto) {
return baseMapper.messages(page, dto);
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
// 清除站内信与用户关联关系
messageUserMapper.lambdaUpdateChain().in(DevMessageUser::getMessageId, ids).remove();
// 执行删除
removeByIds(ids);
}
}
@Transactional(rollbackFor = Exception.class)
public DevMessageVo detail(Long id) {
DevMessageVo devMessageResult = new DevMessageVo();
DevMessage devMessage = queryEntity(id);
BeanUtil.copyProperties(devMessage, devMessageResult);
DevMessageUser myMessage = messageUserMapper.lambdaQueryChain().eq(DevMessageUser::getMessageId, id)
.eq(DevMessageUser::getUserId, StpUtil.getLoginIdAsLong())
.one();
if (ObjectUtil.isNotEmpty(myMessage)) {
// 设置为已读
myMessage.setRead(true);
myMessage.setReadAt(LocalDateTime.now());
messageUserMapper.updateById(myMessage);
}
List<DevMessageVo.DevReceiveInfo> receiveInfoList = messageUserMapper.lambdaQueryChain().eq(DevMessageUser::getMessageId, id).list()
.stream().map(messageUser -> {
Long userId = messageUser.getUserId();
DevMessageVo.DevReceiveInfo receiveInfo = new DevMessageVo.DevReceiveInfo();
Optional<SysUser> user = sysUserMapper.lambdaQueryChain().eq(SysUser::getId, userId).oneOpt();
String userName = user.map(SysUser::getName).orElse("未知用户");
receiveInfo.setReceiveUserId(userId);
receiveInfo.setReceiveUserName(userName);
receiveInfo.setRead(messageUser.getRead());
return receiveInfo;
}).collect(Collectors.toList());
devMessageResult.setReceiveInfoList(receiveInfoList);
return devMessageResult;
}
public DevMessage queryEntity(Long id) {
DevMessage devMessage = getById(id);
if (ObjectUtil.isEmpty(devMessage)) {
throw new CommonException("站内信不存在id值为{}", id);
}
return devMessage;
}
public void readAll(Long userId) {
messageUserMapper.lambdaUpdateChain().eq(DevMessageUser::getUserId, userId).set(DevMessageUser::getRead, userId).update();
}
}

View File

@ -0,0 +1,151 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.JvmInfo;
import cn.hutool.system.OsInfo;
import cn.hutool.system.RuntimeInfo;
import cn.hutool.system.SystemUtil;
import com.byhah.cloud.admin.module.dev.vo.DevMonitorServerVo;
import org.springframework.stereotype.Service;
import com.byhah.deploy.basic.util.NetWorkUtil;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* 监控Service接口实现类
*
*
*
*/
@Service
public class DevMonitorService {
public DevMonitorServerVo serverInfo() {
DevMonitorServerVo vo = new DevMonitorServerVo();
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
CentralProcessor cpu = hal.getProcessor();
// CPU信息
DevMonitorServerVo.DevMonitorCpuInfo devMonitorCpuInfo = new DevMonitorServerVo.DevMonitorCpuInfo();
devMonitorCpuInfo.setCupName(StrUtil.trim(cpu.getProcessorIdentifier().getName()));
devMonitorCpuInfo.setCupNum(cpu.getPhysicalPackageCount() + "颗物理CPU");
devMonitorCpuInfo.setCpuPhysicalCoreNum(cpu.getPhysicalProcessorCount() + "个物理核心");
devMonitorCpuInfo.setCpuLogicalCoreNum(cpu.getLogicalProcessorCount() + "个逻辑核心");
long[] prevTicks = cpu.getSystemCpuLoadTicks();
Util.sleep(1000);
long[] ticks = cpu.getSystemCpuLoadTicks();
long nice = ticks[CentralProcessor.TickType.NICE.getIndex()]
- prevTicks[CentralProcessor.TickType.NICE.getIndex()];
long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()]
- prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()]
- prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()]
- prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()]
- prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
long user = ticks[CentralProcessor.TickType.USER.getIndex()]
- prevTicks[CentralProcessor.TickType.USER.getIndex()];
long ioWait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()]
- prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()]
- prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
long totalCpu = user + nice + sys + idle + ioWait + irq + softIrq + steal;
devMonitorCpuInfo.setCpuSysUseRate(NumberUtil.div(NumberUtil.mul(sys, 100), totalCpu, 2) + "%");
devMonitorCpuInfo.setCpuUserUseRate(NumberUtil.div(NumberUtil.mul(user, 100), totalCpu, 2) + "%");
devMonitorCpuInfo.setCpuTotalUseRate(NumberUtil.div(NumberUtil.mul(NumberUtil.add(sys, user), 100), totalCpu, 2));
devMonitorCpuInfo.setCpuWaitRate(NumberUtil.div(NumberUtil.mul(ioWait, 100), totalCpu, 2) + "%");
devMonitorCpuInfo.setCpuFreeRate(NumberUtil.div(NumberUtil.mul(idle, 100), totalCpu, 2) + "%");
vo.setDevMonitorCpuInfo(devMonitorCpuInfo);
// 内存信息
GlobalMemory memory = hal.getMemory();
DevMonitorServerVo.DevMonitorMemoryInfo devMonitorMemoryInfo = new DevMonitorServerVo.DevMonitorMemoryInfo();
long used = memory.getTotal() - memory.getAvailable();
devMonitorMemoryInfo.setMemoryTotal(FileUtil.readableFileSize(memory.getTotal()));
devMonitorMemoryInfo.setMemoryUsed(FileUtil.readableFileSize(used));
devMonitorMemoryInfo.setMemoryFree(FileUtil.readableFileSize(memory.getAvailable()));
devMonitorMemoryInfo.setMemoryUseRate(NumberUtil.mul(NumberUtil.div(used, memory.getTotal(), 4), 100));
vo.setDevMonitorMemoryInfo(devMonitorMemoryInfo);
// 存储信息
DevMonitorServerVo.DevMonitorStorageInfo devMonitorStorageInfo = new DevMonitorServerVo.DevMonitorStorageInfo();
OperatingSystem operatingSystem = si.getOperatingSystem();
FileSystem fileSystem = operatingSystem.getFileSystem();
AtomicLong storageTotal = new AtomicLong();
AtomicLong storageUsed = new AtomicLong();
AtomicLong storageFree = new AtomicLong();
fileSystem.getFileStores().forEach(osFileStore -> {
long totalSpace = osFileStore.getTotalSpace();
long usableSpace = osFileStore.getUsableSpace();
long freeSpace = osFileStore.getFreeSpace();
long usedSpace = totalSpace - usableSpace;
storageTotal.addAndGet(totalSpace);
storageUsed.addAndGet(usedSpace);
storageFree.addAndGet(freeSpace);
});
devMonitorStorageInfo.setStorageTotal(FileUtil.readableFileSize(storageTotal.get()));
devMonitorStorageInfo.setStorageUsed(FileUtil.readableFileSize(storageUsed.get()));
devMonitorStorageInfo.setStorageFree(FileUtil.readableFileSize(storageFree.get()));
devMonitorStorageInfo.setStorageUseRate(NumberUtil.mul(NumberUtil.div(storageUsed.doubleValue(), storageTotal.doubleValue(), 4), 100));
vo.setDevMonitorStorageInfo(devMonitorStorageInfo);
// 网络信息
DevMonitorServerVo.DevMonitorNetworkInfo devMonitorNetworkInfo = new DevMonitorServerVo.DevMonitorNetworkInfo();
Map<String, String> networkUpRate = NetWorkUtil.getNetworkUpRate();
devMonitorNetworkInfo.setUpLinkRate(networkUpRate.get("UP"));
devMonitorNetworkInfo.setDownLinkRate(networkUpRate.get("DOWN"));
vo.setDevMonitorNetworkInfo(devMonitorNetworkInfo);
// 服务器信息
OsInfo osInfo = SystemUtil.getOsInfo();
DevMonitorServerVo.DevMonitorServerInfo devMonitorServerInfo = new DevMonitorServerVo.DevMonitorServerInfo();
devMonitorServerInfo.setServerName(NetUtil.getLocalHostName());
devMonitorServerInfo.setServerOs(osInfo.getName());
devMonitorServerInfo.setServerIp(NetUtil.getLocalhostStr());
devMonitorServerInfo.setServerArchitecture(osInfo.getArch());
vo.setDevMonitorServerInfo(devMonitorServerInfo);
// JVM信息
DevMonitorServerVo.DevMonitorJvmInfo devMonitorJvmInfo = new DevMonitorServerVo.DevMonitorJvmInfo();
RuntimeInfo runtimeInfo = SystemUtil.getRuntimeInfo();
JvmInfo jvmInfo = SystemUtil.getJvmInfo();
devMonitorJvmInfo.setJvmName(jvmInfo.getName());
devMonitorJvmInfo.setJvmVersion(jvmInfo.getVersion());
long totalMemory = runtimeInfo.getTotalMemory();
devMonitorJvmInfo.setJvmMemoryTotal(FileUtil.readableFileSize(totalMemory));
devMonitorJvmInfo.setJvmMemoryFree(FileUtil.readableFileSize(runtimeInfo.getFreeMemory()));
long jvmMemoryUsed = NumberUtil.sub(new BigDecimal(runtimeInfo
.getTotalMemory()), new BigDecimal(runtimeInfo.getFreeMemory())).longValue();
devMonitorJvmInfo.setJvmMemoryUsed(FileUtil.readableFileSize(jvmMemoryUsed));
double jvmUseRate = NumberUtil.mul(NumberUtil.div(jvmMemoryUsed, totalMemory, 4), 100);
devMonitorJvmInfo.setJvmUseRate(jvmUseRate);
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
DateTime startTime = DateUtil.date(runtimeMXBean.getStartTime());
devMonitorJvmInfo.setJvmStartTime(DateUtil.formatDateTime(startTime));
devMonitorJvmInfo.setJvmRunTime(DateUtil.formatBetween(startTime, DateTime.now()));
devMonitorJvmInfo.setJavaVersion(SystemUtil.get("java.version", false));
devMonitorJvmInfo.setJavaPath(SystemUtil.get("java.home", false));
vo.setDevMonitorJvmInfo(devMonitorJvmInfo);
return vo;
}
}

View File

@ -0,0 +1,11 @@
package com.byhah.cloud.admin.module.dev.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class DevService {
}

View File

@ -0,0 +1,108 @@
package com.byhah.cloud.admin.module.dev.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.dev.dto.DevSmsSearchDto;
import com.byhah.cloud.admin.module.dev.dto.DevSmsSendDto;
import com.byhah.cloud.basic.core.entity.dev.DevSms;
import com.byhah.cloud.basic.core.enums.dev.DevSmsEngine;
import com.byhah.cloud.orm.mapper.dev.IDevSmsMapper;
import com.byhah.cloud.orm.support.service.DevSupportService;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.sms.client.SmsAliyunClient;
import com.byhah.deploy.basic.sms.client.SmsTencentClient;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
import static com.byhah.cloud.basic.constant.ConfigKey.Sms.*;
/**
* 短信Service接口实现类
**/
@Service
@RequiredArgsConstructor
public class DevSmsService extends ServiceImpl<IDevSmsMapper, DevSms> {
private final DevSupportService devSupportService;
public void send(DevSmsSendDto dto) {
validPhone(dto.getPhoneNumbers());
DevSmsEngine engine = DevSmsEngine.forValue(dto.getEngine());
String receipt = send(engine, dto);
DevSms devSms = new DevSms();
BeanUtil.copyProperties(dto, devSms);
devSms.setEngine(DevSmsEngine.ALIYUN);
devSms.setReceiptInfo(receipt);
save(devSms);
}
private String send(DevSmsEngine engine, DevSmsSendDto dto) {
if (engine == DevSmsEngine.ALIYUN) {
String accessKeyId = devSupportService.getConfig(SMS_ALIYUN_ACCESS_KEY_ID_KEY);
String accessKeySecret = devSupportService.getConfig(SMS_ALIYUN_ACCESS_KEY_SECRET_KEY);
String endPoint = devSupportService.getConfig(SMS_ALIYUN_END_POINT_KEY);
String signName = dto.getSignName();
if (StrUtil.isBlank(signName)) {
signName = devSupportService.getConfig(SMS_ALIYUN_DEFAULT_SIGN_NAME_KEY);
}
SmsAliyunClient client = new SmsAliyunClient(accessKeyId, accessKeySecret, endPoint);
return client.sendSms(dto.getPhoneNumbers(), signName, dto.getTemplateCode(), dto.getTemplateParam());
} else if (engine == DevSmsEngine.TENCENT) {
String secretId = devSupportService.getConfig(SMS_TENCENT_SECRET_ID_KEY);
String secretKey = devSupportService.getConfig(SMS_TENCENT_SECRET_KEY_KEY);
String regionId = devSupportService.getConfig(SMS_TENCENT_REGION_ID_KEY);
String sdkAppId = devSupportService.getConfig(SMS_TENCENT_DEFAULT_SDK_APP_ID_KEY);
String signName = dto.getSignName();
if (StrUtil.isBlank(signName)) {
signName = devSupportService.getConfig(SMS_TENCENT_DEFAULT_SIGN_NAME_KEY);
}
SmsTencentClient client = new SmsTencentClient(secretId, secretKey, regionId, sdkAppId);
return client.sendSms(dto.getPhoneNumbers(), signName, dto.getTemplateCode(), dto.getTemplateParam());
}
return null;
}
public Page<DevSms> page(Page<DevSms> page, DevSmsSearchDto dto) {
return lambdaQuery().eq(Objects.nonNull(dto.getEngine()), DevSms::getEngine, dto.getEngine())
.like(CharSequenceUtil.isNotBlank(dto.getSearchKey()), DevSms::getPhoneNumbers, dto.getSearchKey())
.page(page);
}
public void delete(List<Long> ids) {
removeByIds(ids);
}
public DevSms detail(Long id) {
return queryEntity(id);
}
public DevSms queryEntity(Long id) {
DevSms devSms = getById(id);
if (ObjectUtil.isEmpty(devSms)) {
throw new CommonException("短信不存在id值为%s", id);
}
return devSms;
}
/**
* 校验手机格式
**/
private void validPhone(String phones) {
StrUtil.split(phones, StrUtil.COMMA).forEach(phone -> {
if (!PhoneUtil.isMobile(phone)) {
throw new CommonException("手机号码:%s格式错误", phone);
}
});
}
}

View File

@ -0,0 +1,125 @@
package com.byhah.cloud.admin.module.dev.util;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.byhah.deploy.basic.util.IpAddressUtil;
import com.byhah.deploy.basic.util.web.ServletUtils;
import com.byhah.deploy.basic.util.web.UaUtil;
import com.byhah.cloud.admin.module.dev.service.DevLogService;
import com.byhah.cloud.basic.core.entity.dev.DevLog;
import com.byhah.cloud.basic.core.enums.dev.DevLogType;
import com.byhah.cloud.basic.core.util.CommonJoinPointUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import java.time.LocalDateTime;
/**
* 日志工具类
*/
public class DevLogUtil {
private static final DevLogService devLogService = SpringUtil.getBean(DevLogService.class);
/**
* 记录操作日志
*/
public static void executeOperationLog(String methodName, String userName, JoinPoint joinPoint, String resultJson) {
HttpServletRequest request = ServletUtils.getRequest();
DevLog devLog = genBasOpLog();
ThreadUtil.execute(() -> {
devLog.setCategory(DevLogType.OPERATE);
devLog.setName(methodName);
devLog.setExeStatus(true);
devLog.setClassName(joinPoint.getTarget().getClass().getName());
devLog.setMethodName(joinPoint.getSignature().getName());
devLog.setReqMethod(request.getMethod());
devLog.setReqUrl(request.getRequestURI());
devLog.setParamJson(CommonJoinPointUtil.getArgsJsonString(joinPoint));
devLog.setResultJson(resultJson);
devLog.setOpTime(LocalDateTime.now());
devLog.setOpUser(userName);
devLogService.save(devLog);
});
}
/**
* 记录异常日志
*/
public static void executeExceptionLog(String methodName, String userName, JoinPoint joinPoint, Exception exception) {
HttpServletRequest request = ServletUtils.getRequest();
DevLog devLog = genBasOpLog();
ThreadUtil.execute(() -> {
devLog.setCategory(DevLogType.EXCEPTION);
devLog.setName(methodName);
devLog.setExeStatus(false);
devLog.setExeMessage(ExceptionUtil.stacktraceToString(exception, Integer.MAX_VALUE));
devLog.setClassName(joinPoint.getTarget().getClass().getName());
devLog.setMethodName(joinPoint.getSignature().getName());
devLog.setReqMethod(request.getMethod());
devLog.setReqUrl(request.getRequestURI());
devLog.setParamJson(CommonJoinPointUtil.getArgsJsonString(joinPoint));
devLog.setOpTime(LocalDateTime.now());
devLog.setOpUser(userName);
devLogService.save(devLog);
});
}
/**
* 记录登录日志
*/
public static void executeLoginLog(String userName) {
DevLog devLog = genBasOpLog();
ThreadUtil.execute(() -> {
devLog.setCategory(DevLogType.LOGIN);
devLog.setName("用户登录");
devLog.setExeStatus(true);
devLog.setOpTime(LocalDateTime.now());
devLog.setOpUser(userName);
devLogService.save(devLog);
});
}
/**
* 记录登出日志
*/
public static void executeLogoutLog(String userName) {
DevLog devLog = genBasOpLog();
ThreadUtil.execute(() -> {
devLog.setCategory(DevLogType.LOGOUT);
devLog.setName("用户登出");
devLog.setExeStatus(true);
devLog.setOpTime(LocalDateTime.now());
devLog.setOpUser(userName);
devLogService.save(devLog);
});
}
/**
* 构建基础操作日志
*/
private static DevLog genBasOpLog() {
HttpServletRequest request = ServletUtils.getRequest();
String ip = ServletUtils.getClientIP(request);
long loginId;
try {
loginId = StpUtil.getLoginIdAsLong();
if (ObjectUtil.isEmpty(loginId)) {
loginId = -1L;
}
} catch (Exception e) {
loginId = -1L;
}
DevLog devLog = new DevLog();
devLog.setOpIp(ip);
devLog.setOpAddress(IpAddressUtil.getCityInfo(ip));
devLog.setOpBrowser(UaUtil.getBrowser(request));
devLog.setOpOs(UaUtil.getOs(request));
devLog.setCreatedBy(loginId);
return devLog;
}
}

View File

@ -0,0 +1,46 @@
package com.byhah.cloud.admin.module.dev.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class DevMessageVo {
private Long id;
private String category;
private String subject;
private String content;
private LocalDateTime createdAt;
@Schema(description = "当前用户是否已读")
private Boolean read;
@Schema(description = "接收信息集合")
private List<DevReceiveInfo> receiveInfoList;
/**
* 接收信息类
*/
@Data
public static class DevReceiveInfo {
/**
* 接收人ID
*/
@Schema(description = "接收人ID")
private Long receiveUserId;
/**
* 接收人姓名
*/
@Schema(description = "接收人姓名")
private String receiveUserName;
/**
* 是否已读
*/
@Schema(description = "是否已读")
private Boolean read;
}
}

View File

@ -0,0 +1,232 @@
package com.byhah.cloud.admin.module.dev.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 服务器监控结果
*/
@Data
public class DevMonitorServerVo {
/* ==============概览数据============ */
/** CPU信息 */
@Schema(description = "CPU信息")
private DevMonitorCpuInfo devMonitorCpuInfo;
/** 内存信息 */
@Schema(description = "内存信息")
private DevMonitorMemoryInfo devMonitorMemoryInfo;
/** 存储信息 */
@Schema(description = "存储信息")
private DevMonitorStorageInfo devMonitorStorageInfo;
/** 网络信息 */
@Schema(description = "网络信息")
private DevMonitorNetworkInfo devMonitorNetworkInfo;
/* ==============服务器数据============ */
/** 服务器信息 */
@Schema(description = "服务器信息")
private DevMonitorServerInfo devMonitorServerInfo;
/* ==============JVM数据============ */
/** JVM信息 */
@Schema(description = "JVM信息")
private DevMonitorJvmInfo devMonitorJvmInfo;
/**
* CPU信息类
*
*
*
*/
@Data
public static class DevMonitorCpuInfo {
/** CPU名称 */
@Schema(description = "CPU名称")
private String cupName;
/** CPU数量 */
@Schema(description = "CPU数量")
private String cupNum;
/** CPU物理核心数 */
@Schema(description = "CPU物理核心数")
private String cpuPhysicalCoreNum;
/** CPU逻辑核心数 */
@Schema(description = "CPU逻辑核心数")
private String cpuLogicalCoreNum;
/** CPU系统使用率 */
@Schema(description = "CPU系统使用率")
private String cpuSysUseRate;
/** CPU用户使用率 */
@Schema(description = "CPU用户使用率")
private String cpuUserUseRate;
/** CPU当前总使用率 */
@Schema(description = "CPU当前总使用率")
private Double cpuTotalUseRate;
/** CPU当前等待率 */
@Schema(description = "CPU当前等待率")
private String cpuWaitRate;
/** CPU当前空闲率 */
@Schema(description = "CPU当前空闲率")
private String cpuFreeRate;
}
/**
* 内存信息类
*
*
*
*/
@Data
public static class DevMonitorMemoryInfo {
/** 内存总量 */
@Schema(description = "内存总量")
private String memoryTotal;
/** 内存已用 */
@Schema(description = "内存已用")
private String memoryUsed;
/** 内存剩余 */
@Schema(description = "内存剩余")
private String memoryFree;
/** 内存使用率 */
@Schema(description = "内存使用率")
private Double memoryUseRate;
}
/**
* 存储信息
*
*
*
*/
@Data
public static class DevMonitorStorageInfo {
/** 存储总量 */
@Schema(description = "存储总量")
private String storageTotal;
/** 存储已用 */
@Schema(description = "存储已用")
private String storageUsed;
/** 存储剩余 */
@Schema(description = "存储剩余")
private String storageFree;
/** 存储使用率 */
@Schema(description = "存储使用率")
private Double storageUseRate;
}
/**
* 网络信息类
*
*
*
*/
@Data
public static class DevMonitorNetworkInfo {
/** 上行速率 */
@Schema(description = "上行速率")
private String upLinkRate;
/** 下行速率 */
@Schema(description = "下行速率")
private String downLinkRate;
}
/**
* 服务器信息类
*
*
*
*/
@Data
public static class DevMonitorServerInfo {
/** 服务器名称 */
@Schema(description = "服务器名称")
private String serverName;
/** 服务器操作系统 */
@Schema(description = "服务器操作系统")
private String serverOs;
/** 服务器IP */
@Schema(description = "服务器IP")
private String serverIp;
/** 服务器架构 */
@Schema(description = "服务器架构")
private String serverArchitecture;
}
/**
* JVM信息类
*
*
*
*/
@Data
public static class DevMonitorJvmInfo {
/** JVM名称 */
@Schema(description = "JVM名称")
private String jvmName;
/** JVM版本 */
@Schema(description = "JVM版本")
private String jvmVersion;
/** JVM总分配内存 */
@Schema(description = "JVM总分配内存")
private String jvmMemoryTotal;
/** JVM已用内存 */
@Schema(description = "JVM已用内存")
private String jvmMemoryUsed;
/** JVM剩余内存 */
@Schema(description = "JVM剩余内存")
private String jvmMemoryFree;
/** JVM内存使用率 */
@Schema(description = "JVM内存使用率")
private Double jvmUseRate;
/** JVM启动时间 */
@Schema(description = "JVM启动时间")
private String jvmStartTime;
/** JVM运行时长 */
@Schema(description = "JVM运行时长")
private String jvmRunTime;
/** Java版本 */
@Schema(description = "Java版本")
private String javaVersion;
/** Java安装路径 */
@Schema(description = "Java安装路径")
private String javaPath;
}
}

View File

@ -0,0 +1,94 @@
package com.byhah.cloud.admin.module.gen.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.cloud.admin.module.gen.dto.GenBasicDto;
import com.byhah.cloud.admin.module.gen.service.GenBasicService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import com.byhah.cloud.basic.core.entity.gen.GenBasic;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.cloud.admin.module.gen.dto.*;
import com.byhah.cloud.admin.module.gen.vo.GenBasicPreviewVo;
import com.byhah.cloud.admin.module.gen.vo.GenBasicTableColumnVo;
import com.byhah.cloud.admin.module.gen.vo.GenBasicTableVo;
import com.byhah.deploy.starter.web.R;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
* 代码生成基础
**/
@Tag(name = "代码生成基础")
@RestController
@RequiredArgsConstructor
@RequestMapping("/gen/basic")
public class GenBasicController {
private final GenBasicService genBasicService;
@Operation(summary = "获取代码生成基础分页")
@GetMapping("/page")
public R<IPage<GenBasic>> page() {
return R.ok(genBasicService.page(PageUtils.toPage()));
}
@Operation(summary = "添加代码生成基础")
@PostMapping("/add")
public R<GenBasic> add(@RequestBody @Valid GenBasicDto dto) {
return R.ok(genBasicService.add(dto));
}
@Operation(summary = "编辑代码生成基础")
@PostMapping("/edit")
public R<GenBasic> edit(@RequestBody @Valid GenBasicDto dto) {
return R.ok(genBasicService.edit(dto));
}
@Operation(summary = "删除代码生成基础")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
genBasicService.delete(ids);
return R.ok();
}
@Operation(summary = "获取代码生成基础详情")
@GetMapping("/detail")
public R<GenBasic> detail(Long id) {
return R.ok(genBasicService.detail(id));
}
@Operation(summary = "获取所有表信息")
@GetMapping("/tables")
public R<List<GenBasicTableVo>> dbsTable() {
return R.ok(genBasicService.tables());
}
@Operation(summary = "获取表内所有字段信息")
@GetMapping("/tableColumns")
public R<List<GenBasicTableColumnVo>> tableColumns(String tableName) {
return R.ok(genBasicService.tableColumns(tableName));
}
@Operation(summary = "执行代码生成(压缩包)")
@GetMapping(value = "/execGenZip", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void execGenZip(Long id, HttpServletResponse response) {
genBasicService.execGenZip(id, response);
}
@Operation(summary = "预览代码生成")
@GetMapping(value = "/previewGen")
public R<GenBasicPreviewVo> previewGen(@Valid Long id) {
return R.ok(genBasicService.previewGen(id));
}
}

View File

@ -0,0 +1,60 @@
package com.byhah.cloud.admin.module.gen.controller;
import com.byhah.cloud.admin.module.gen.dto.GenConfigDto;
import com.byhah.cloud.admin.module.gen.service.GenConfigService;
import com.byhah.cloud.basic.core.entity.gen.GenConfig;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.starter.web.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Tag(name = "代码生成详细配置")
@RestController
@RequestMapping("/gen/config")
@RequiredArgsConstructor
public class GenConfigController {
private final GenConfigService genConfigService;
@Operation(summary = "获取代码生成详细配置分页")
@GetMapping("/list")
public R<List<GenConfig>> list(Long basicId) {
return R.ok(genConfigService.lambdaQuery().eq(GenConfig::getBasicId, basicId).list());
}
@Operation(summary = "编辑代码生成详细配置")
@PostMapping("/edit")
public R<String> edit(@RequestBody @Valid GenConfigDto dto) {
genConfigService.edit(dto);
return R.ok();
}
@Operation(summary = "删除代码生成详细配置")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
genConfigService.delete(ids);
return R.ok();
}
@Operation(summary = "获取代码生成详细配置详情")
@GetMapping("/detail")
public R<GenConfig> detail(@Valid Long id) {
return R.ok(genConfigService.detail(id));
}
@Operation(summary = "批量编辑代码生成详细配置")
@PostMapping("/editBatch")
public R<String> editBatch(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<GenConfigDto> dto) {
genConfigService.editBatch(dto);
return R.ok();
}
}

View File

@ -0,0 +1,123 @@
package com.byhah.cloud.admin.module.gen.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* 代码生成基础添加参数
**/
@Data
public class GenBasicDto {
@Schema(description = "id", required = true)
@NotNull(message = "id不能为空", groups = Update.class)
@Null(message = "id必须为空", groups = Insert.class)
private Long id;
/**
* 主表名称
*/
@Schema(description = "主表名称", required = true)
@NotNull(message = "dbTable不能为空")
private String dbTable;
/**
* 主表主键
*/
@Schema(description = "主表主键", required = true)
@NotNull(message = "dbTableKey不能为空")
private String dbTableKey;
/**
* 模块名
*/
@Schema(description = "模块名", required = true)
@NotNull(message = "moduleName不能为空")
private String moduleName;
/**
* 表前缀移除
*/
@Schema(description = "表前缀移除", required = true)
@NotNull(message = "tablePrefix不能为空")
private Boolean tablePrefix;
/**
* 生成方式
*/
@Schema(description = "生成方式", required = true)
@NotNull(message = "generateType不能为空")
private String generateType;
/**
* 所属模块
*/
@Schema(description = "所属模块", required = true)
@NotNull(message = "module不能为空")
private Long module;
/**
* 上级目录
*/
@Schema(description = "上级目录", required = true)
@NotNull(message = "menuPid不能为空")
private String menuPid;
/**
* 功能名
*/
@Schema(description = "功能名", required = true)
@NotNull(message = "functionName不能为空")
private String functionName;
/**
* 业务名
*/
@Schema(description = "业务名", required = true)
@NotNull(message = "busName不能为空")
private String busName;
/**
* 类名
*/
@Schema(description = "类名", required = true)
@NotNull(message = "className不能为空")
private String className;
/**
* 表单布局
*/
@Schema(description = "表单布局", required = true)
@NotNull(message = "formLayout不能为空")
private String formLayout;
/**
* 使用栅格
*/
@Schema(description = "使用栅格", required = true)
@NotNull(message = "gridWhether不能为空")
private Boolean gridWhether;
/**
* 排序
*/
@Schema(description = "排序", required = true)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/**
* 作者名
*/
@Schema(description = "作者名", required = true)
private String authorName;
/**
* 包名
*/
@Schema(description = "包名", required = true)
private String packageName;
}

View File

@ -0,0 +1,124 @@
package com.byhah.cloud.admin.module.gen.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 代码生成详细配置编辑参数
**/
@Data
public class GenConfigDto {
/**
* id
*/
@Schema(description = "id", required = true)
@NotNull(message = "id不能为空")
private Long id;
/**
* 基础ID
*/
@Schema(description = "基础ID", required = true)
@NotNull(message = "basicId不能为空")
private Long basicId;
/**
* 是否主键
*/
@Schema(description = "是否主键", required = true)
@NotNull(message = "isTableKey不能为空")
private Boolean isTableKey;
/**
* 字段
*/
@Schema(description = "字段", required = true)
@NotBlank(message = "fieldName不能为空")
private String fieldName;
/**
* 注释
*/
@Schema(description = "注释", required = true)
// @NotBlank(message = "fieldRemark不能为空")
private String fieldRemark;
/**
* 类型
*/
@Schema(description = "类型", required = true)
@NotBlank(message = "fieldType不能为空")
private String fieldType;
/**
* 实体类型
*/
@Schema(description = "实体类型", required = true)
@NotBlank(message = "fieldJavaType不能为空")
private String fieldJavaType;
/**
* 作用类型
*/
@Schema(description = "作用类型", required = true)
@NotBlank(message = "effectType不能为空")
private String effectType;
@Schema(description = "选择器数据源一级分类", required = true)
private String firstDataType;
@Schema(description = "选择器数据源二级分类", required = true)
private String secondDataType;
/**
* 列表显示
*/
@Schema(description = "列表显示", required = true)
@NotNull(message = "whetherTable不能为空")
private Boolean whetherTable;
/**
* 列省略
*/
@Schema(description = "列省略", required = true)
@NotNull(message = "whetherRetract不能为空")
private Boolean whetherRetract;
/**
* 增改
*/
@Schema(description = "增改", required = true)
@NotNull(message = "whetherAddUpdate不能为空")
private Boolean whetherAddUpdate;
/**
* 必填
*/
@Schema(description = "必填", required = true)
@NotNull(message = "whetherRequired不能为空")
private Boolean whetherRequired;
/**
* 查询
*/
@Schema(description = "查询", required = true)
@NotNull(message = "queryWhether不能为空")
private Boolean queryWhether;
/**
* 查询方式
*/
@Schema(description = "查询方式", required = true)
private String queryType;
/**
* 排序
*/
@Schema(description = "排序", required = true)
private Integer sortCode;
}

View File

@ -0,0 +1,522 @@
package com.byhah.cloud.admin.module.gen.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.gen.dto.GenBasicDto;
import com.byhah.cloud.admin.module.gen.dto.GenConfigDto;
import com.byhah.cloud.admin.utils.GenDbTypeUtil;
import lombok.RequiredArgsConstructor;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.byhah.cloud.orm.mapper.gen.GenBasicMapper;
import com.byhah.cloud.basic.core.entity.gen.GenBasic;
import com.byhah.cloud.basic.core.entity.gen.GenConfig;
import com.byhah.cloud.basic.core.enums.gen.GenEffectType;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.util.web.DownloadUtil;
import com.byhah.cloud.admin.module.gen.vo.GenBasicPreviewVo;
import com.byhah.cloud.admin.module.gen.vo.GenBasicTableColumnVo;
import com.byhah.cloud.admin.module.gen.vo.GenBasicTableVo;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 代码生成基础Service接口实现类
**/
@Service
@RequiredArgsConstructor
public class GenBasicService extends ServiceImpl<GenBasicMapper, GenBasic> {
private static final String DB_URL_KEY = "spring.datasource.url";
private static final String DB_USERNAME_KEY = "spring.datasource.username";
private static final String DB_PASSWORD_KEY = "spring.datasource.password";
private static final List<JSONObject> GEN_SQL_FILE_LIST = CollectionUtil.newArrayList(
Collections.singleton(JSONUtil.createObj().set("name", "Menu.sql.btl")));
private static final List<JSONObject> GEN_FRONT_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Api.js.btl").set("path", "api"),
JSONUtil.createObj().set("name", "form.vue.btl").set("path", "views/biz"),
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "views/biz"));
private static final List<JSONObject> GEN_BACKEND_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Controller.java.btl").set("path", "controller"),
JSONUtil.createObj().set("name", "Entity.java.btl").set("path", "entity"),
JSONUtil.createObj().set("name", "Mapper.java.btl").set("path", "mapper"),
JSONUtil.createObj().set("name", "Mapper.xml.btl").set("path", "mapper" + File.separator + "mapping"),
JSONUtil.createObj().set("name", "Dto.java.btl").set("path", "dto"),
JSONUtil.createObj().set("name", "Vo.java.btl").set("path", "vo"),
JSONUtil.createObj().set("name", "SearchDto.java.btl").set("path", "dto"),
JSONUtil.createObj().set("name", "Service.java.btl").set("path", "service"));
private static final String SORT_CODE_KEY = "sort_code";
private static final String CREATE_USER_KEY = "created_by";
private static final String CREATE_TIME_KEY = "created_at";
private static final String UPDATE_USER_KEY = "updated_by";
private static final String UPDATE_TIME_KEY = "updated_at";
private static final String DELETE_FLAG_KEY = "deleted";
private final Environment environment;
private final GenConfigService genConfigService;
@Transactional(rollbackFor = Exception.class)
public GenBasic add(GenBasicDto dto) {
GenBasic genBasic = BeanUtil.toBean(dto, GenBasic.class);
save(genBasic);
addGenConfig(genBasic);
return genBasic;
}
@Transactional(rollbackFor = Exception.class)
public GenBasic edit(GenBasicDto dto) {
GenBasic genBasic = queryEntity(dto.getId());
if (!genBasic.getDbTable().equals(dto.getDbTable())) {
// 删除配置表内该表的字段
QueryWrapper<GenConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(GenConfig::getBasicId, genBasic.getId());
genConfigService.remove(queryWrapper);
// 新增新表的数据字段
addGenConfig(genBasic);
}
BeanUtil.copyProperties(dto, genBasic);
updateById(genBasic);
return genBasic;
}
/**
* 新增表字段至配置内
*/
private void addGenConfig(GenBasic genBasic) {
List<GenBasicTableColumnVo> resultList = tableColumns(genBasic.getDbTable());
for (int i = 0; i < resultList.size(); i++) {
GenBasicTableColumnVo item = resultList.get(i);
GenConfigDto dto = new GenConfigDto();
dto.setBasicId(genBasic.getId());
dto.setIsTableKey(item.getColumnName().equals(genBasic.getDbTableKey()));
dto.setFieldName(item.getColumnName());
dto.setFieldType(item.getTypeName());
dto.setFieldRemark(item.getColumnRemark());
dto.setFieldJavaType(GenDbTypeUtil.getJavaTypeBySqlType(item.getTypeName()));
dto.setEffectType(GenEffectType.INPUT.getValue().toLowerCase());
// 除主键删除标志创建人创建时间修改人和修改时间外所有默认在列表显示在增改显示非列省略非必填非查询
boolean flag = genBasic.getDbTableKey().equalsIgnoreCase(item.getColumnName()) ||
DELETE_FLAG_KEY.equalsIgnoreCase(item.getColumnName()) ||
CREATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
CREATE_TIME_KEY.equalsIgnoreCase(item.getColumnName()) ||
UPDATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
UPDATE_TIME_KEY.equalsIgnoreCase(item.getColumnName());
dto.setWhetherTable(!flag);
dto.setWhetherAddUpdate(!flag);
dto.setWhetherRetract(false);
dto.setWhetherRequired(false);
dto.setQueryWhether(false);
dto.setSortCode(i);
GenConfig genConfig = BeanUtil.toBean(dto, GenConfig.class);
genConfigService.save(genConfig);
}
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
// 级联删除配置
genConfigService.remove(new LambdaQueryWrapper<GenConfig>().in(GenConfig::getBasicId, ids));
// 执行删除
removeByIds(ids);
}
}
public GenBasic detail(Long id) {
return queryEntity(id);
}
public GenBasic queryEntity(Long id) {
GenBasic genBasic = getById(id);
if (ObjectUtil.isEmpty(genBasic)) {
throw new CommonException("代码生成基础不存在id值为{}", id);
}
return genBasic;
}
public List<GenBasicTableVo> tables() {
Connection conn = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
DatabaseMetaData metaData = conn.getMetaData();
String url = metaData.getURL();
String schema = null;
if (url.toLowerCase().contains("jdbc:oracle")) {
schema = metaData.getUserName();
}
List<GenBasicTableVo> tables = new ArrayList<>();
rs = metaData.getTables(null, schema, "%", new String[]{"TABLE"});
while (rs.next()) {
String tableName = rs.getString("TABLE_NAME");
if (!StrUtil.startWithIgnoreCase(tableName, "ACT_")) {
GenBasicTableVo vo = new GenBasicTableVo();
vo.setTableName(tableName);
String remarks = rs.getString("REMARKS");
if (ObjectUtil.isEmpty(remarks)) {
vo.setTableRemark(tableName);
} else {
vo.setTableRemark(remarks);
}
tables.add(vo);
}
}
return tables;
} catch (SQLException sqlException) {
sqlException.printStackTrace();
throw new CommonException("获取数据库表失败");
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeConnection(conn);
}
}
public List<GenBasicTableColumnVo> tableColumns(String tableName) {
Connection conn = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
DatabaseMetaData metaData = conn.getMetaData();
String url = metaData.getURL();
String schema = null;
if (url.toLowerCase().contains("jdbc:oracle")) {
schema = metaData.getUserName();
}
List<GenBasicTableColumnVo> columns = new ArrayList<>();
rs = metaData.getColumns(null, schema, tableName, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME").toLowerCase();
GenBasicTableColumnVo res = new GenBasicTableColumnVo();
res.setColumnName(columnName);
String remarks = rs.getString("REMARKS");
if (ObjectUtil.isEmpty(remarks)) {
res.setColumnRemark(columnName);
} else {
res.setColumnRemark(remarks);
}
String typeName = rs.getString("TYPE_NAME").toLowerCase();
if (ObjectUtil.isEmpty(typeName)) {
res.setTypeName("none");
} else {
res.setTypeName(typeName);
}
columns.add(res);
}
return columns;
} catch (SQLException sqlException) {
sqlException.printStackTrace();
throw new CommonException("获取数据库表字段失败,表名称:{}", tableName);
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeConnection(conn);
}
}
@Transactional(rollbackFor = Exception.class)
public void execGenZip(Long id, HttpServletResponse response) {
try {
File tempFolder = genTempFolder(id);
if (tempFolder == null) {
throw new CommonException("代码生成基础不存在id值为" + id);
}
// 压缩
File zip = ZipUtil.zip(tempFolder);
// 压缩完毕删除临时目录
FileUtil.del(tempFolder);
// 下载
DownloadUtil.download(zip, response);
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 获取临时目录
*/
private File genTempFolder(Long id) {
GenBasic genBasic = getById(id);
if (ObjectUtil.isEmpty(genBasic)) {
// 如果是压缩包下载应该使用CommonResponseUtil渲染异常
return null;
}
GenBasicPreviewVo vo = previewGen(id);
// 先删除压缩包
FileUtil.del(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName() + ".zip");
// 生成临时目录
File tempFolder = FileUtil.file(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName());
// 生成SQL代码到临时目录
vo.getGenBasicCodeSqlResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator +
genBasicCodeResult.getCodeFileWithPathName())));
// 生成前端代码到临时目录
vo.getGenBasicCodeFrontendResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "frontend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
// 生成后端代码到临时目录
vo.getGenBasicCodeBackendResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "backend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
return tempFolder;
}
public GenBasicPreviewVo previewGen(Long id) {
GenBasic genBasic = queryEntity(id);
JSONObject bindingJsonObject = getBindingJsonObject(genBasic);
GenBasicPreviewVo vo = new GenBasicPreviewVo();
try {
// SQL基础路径
String genSqlBasicPath = "sql";
// SQL
GroupTemplate groupTemplateSql = new GroupTemplate(new ClasspathResourceLoader("sqlend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewVo.GenBasicCodeResult> genBasicCodeSqlResultList = CollectionUtil.newArrayList();
GEN_SQL_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
GenBasicPreviewVo.GenBasicCodeResult genBasicCodeSqlResult = new GenBasicPreviewVo.GenBasicCodeResult();
Template templateSql = groupTemplateSql.getTemplate(fileTemplateName);
templateSql.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
genBasicCodeSqlResult.setCodeFileName(resultName);
genBasicCodeSqlResult.setCodeFileWithPathName(genSqlBasicPath + File.separator + resultName);
genBasicCodeSqlResult.setCodeFileContent(templateSql.render());
genBasicCodeSqlResultList.add(genBasicCodeSqlResult);
});
vo.setGenBasicCodeSqlResultList(genBasicCodeSqlResultList);
// 前端基础路径
String genFrontBasicPath = "";
// 前端
GroupTemplate groupTemplateFront = new GroupTemplate(new ClasspathResourceLoader("frontend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewVo.GenBasicCodeResult> genBasicCodeFrontendResultList = CollectionUtil.newArrayList();
GEN_FRONT_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
String fileTemplatePath = fileJsonObject.getStr("path") + File.separator + genBasic.getModuleName();
GenBasicPreviewVo.GenBasicCodeResult genBasicCodeFrontResult = new GenBasicPreviewVo.GenBasicCodeResult();
Template templateFront = groupTemplateFront.getTemplate(fileTemplateName);
templateFront.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
if (fileTemplateName.equalsIgnoreCase("Api.js.btl")) {
resultName = StrUtil.lowerFirst(genBasic.getClassName()) + resultName;
genBasicCodeFrontResult.setCodeFileName(resultName);
genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + resultName);
} else {
genBasicCodeFrontResult.setCodeFileName(resultName);
genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + genBasic.getBusName() + File.separator + resultName);
}
genBasicCodeFrontResult.setCodeFileContent(templateFront.render());
genBasicCodeFrontendResultList.add(genBasicCodeFrontResult);
});
vo.setGenBasicCodeFrontendResultList(genBasicCodeFrontendResultList);
// 后端基础路径
String genBackendBasicPath = StrUtil.replace(genBasic.getPackageName(), StrUtil.DOT, File.separator) + File.separator + "module"
+ File.separator + genBasic.getModuleName() + File.separator;
// 后端
GroupTemplate groupTemplateBackEnd = new GroupTemplate(new ClasspathResourceLoader("backend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewVo.GenBasicCodeResult> genBasicCodeBackendResultList = CollectionUtil.newArrayList();
GEN_BACKEND_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
String fileTemplatePath = fileJsonObject.getStr("path");
GenBasicPreviewVo.GenBasicCodeResult res = new GenBasicPreviewVo.GenBasicCodeResult();
Template templateBackend = groupTemplateBackEnd.getTemplate(fileTemplateName);
templateBackend.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
if (fileTemplateName.equalsIgnoreCase("Entity.java.btl")) {
resultName = ".java";
}
String fileName = genBasic.getClassName() + resultName;
if (fileTemplateName.equalsIgnoreCase("Mapper.java.btl")) {
fileName = "I" + fileName;
}
res.setCodeFileName(fileName);
res.setCodeFileWithPathName(genBackendBasicPath + fileTemplatePath + File.separator + fileName);
res.setCodeFileContent(templateBackend.render());
genBasicCodeBackendResultList.add(res);
});
vo.setGenBasicCodeBackendResultList(genBasicCodeBackendResultList);
} catch (Exception e) {
log.error(">>> 代码生成异常:", e);
throw new CommonException("代码生成异常");
}
return vo;
}
/**
* 根据代码生成基础获取构造的参数
*/
public JSONObject getBindingJsonObject(GenBasic genBasic) {
JSONObject bindingJsonObject = JSONUtil.createObj();
// 代码模块名
bindingJsonObject.set("moduleName", genBasic.getModuleName());
// 功能名
bindingJsonObject.set("functionName", genBasic.getFunctionName());
// 业务名
bindingJsonObject.set("busName", genBasic.getBusName());
// 包名
bindingJsonObject.set("packageName", genBasic.getPackageName());
// 库名
bindingJsonObject.set("dbTable", genBasic.getDbTable());
// 类名
bindingJsonObject.set("className", genBasic.getClassName());
// 类首字母小写名
bindingJsonObject.set("classNameFirstLower", StrUtil.lowerFirst(genBasic.getClassName()));
// 主键名
bindingJsonObject.set("dbTableKey", genBasic.getDbTableKey());
// 主键Java类型
bindingJsonObject.set("dbTableKeyJavaType", "String");
// 主键名驼峰
bindingJsonObject.set("dbTableKeyCamelCase", StrUtil.toCamelCase(genBasic.getDbTableKey().toLowerCase()));
// 主键首字母大写名
bindingJsonObject.set("dbTableKeyFirstUpper", StrUtil.upperFirst(StrUtil.toCamelCase(genBasic.getDbTableKey().toLowerCase())));
// 主键注释
bindingJsonObject.set("dbTableKeyRemark", genBasic.getDbTableKey());
// 表单布局
bindingJsonObject.set("formLayout", genBasic.getFormLayout());
// 使用栅格
bindingJsonObject.set("gridWhether", genBasic.getGridWhether());
// 父菜单ID
Long menuPid = genBasic.getMenuPid();
bindingJsonObject.set("parentId", menuPid == 0 ? genBasic.getModule() : menuPid);
// 菜单ID
bindingJsonObject.set("menuId", IdWorker.getIdStr());
// 菜单编码
bindingJsonObject.set("menuCode", RandomUtil.randomString(10));
// 菜单路径
bindingJsonObject.set("menuPath", StrUtil.SLASH + genBasic.getModuleName() + StrUtil.SLASH + genBasic.getBusName());
// 菜单组件
bindingJsonObject.set("menuComponent", "biz" + StrUtil.SLASH + genBasic.getModuleName() + StrUtil.SLASH + genBasic.getBusName() + StrUtil.SLASH + "index");
// 模块ID
bindingJsonObject.set("moduleId", genBasic.getModule());
// 添加按钮ID
bindingJsonObject.set("addButtonId", IdWorker.getIdStr());
// 编辑按钮ID
bindingJsonObject.set("editButtonId", IdWorker.getIdStr());
// 删除按钮ID
bindingJsonObject.set("deleteButtonId", IdWorker.getIdStr());
// 作者
bindingJsonObject.set("authorName", genBasic.getAuthorName());
// 生成时间
bindingJsonObject.set("genTime", DateUtil.format(DateTime.now(), " yyyy/MM/dd HH:mm"));
// 定义配置详情列表
List<JSONObject> configList = CollectionUtil.newArrayList();
// 定义是否有排序字段
AtomicBoolean hasSortCodeField = new AtomicBoolean(false);
genConfigService.list(new LambdaQueryWrapper<GenConfig>().eq(GenConfig::getBasicId, genBasic.getId()))
.forEach(genConfig -> {
// 定义字段信息
JSONObject configItem = JSONUtil.createObj();
if (genConfig.getFieldName().equalsIgnoreCase(SORT_CODE_KEY)) {
hasSortCodeField.set(true);
}
// 如果是主键则无需作为添加参数需要作为编辑参数需要主键注解
if (genConfig.getFieldName().equalsIgnoreCase(genBasic.getDbTableKey())) {
configItem.set("needAdd", false);
configItem.set("needEdit", true);
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", true);
configItem.set("needTableId", true);
bindingJsonObject.set("dbTableKeyJavaType", genConfig.getFieldJavaType());
bindingJsonObject.set("dbTableKeyRemark", genConfig.getFieldRemark());
} else {
// 排除删除标志
String logicDeleteField = "deleted";
if (genConfig.getFieldName().equalsIgnoreCase(logicDeleteField)) {
configItem.set("needAdd", false);
configItem.set("needEdit", false);
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", false);
configItem.set("needTableId", false);
} else {
configItem.set("needAdd", genConfig.getWhetherAddUpdate());
configItem.set("needEdit", genConfig.getWhetherAddUpdate());
configItem.set("needPage", genConfig.getQueryWhether());
configItem.set("needPageType", genConfig.getQueryType());
configItem.set("required", genConfig.getWhetherRequired());
configItem.set("needTableId", false);
}
}
// 列显示
configItem.set("whetherTable", genConfig.getWhetherTable());
// 列省略
configItem.set("whetherRetract", genConfig.getWhetherRetract());
// 增改
configItem.set("whetherAddUpdate", genConfig.getWhetherAddUpdate());
// 作用类型
configItem.set("effectType", genConfig.getEffectType());
// 一二级数据分类
configItem.set("firstDataType", genConfig.getFirstDataType());
configItem.set("secondDataType", genConfig.getSecondDataType());
// 实体类型
configItem.set("fieldJavaType", genConfig.getFieldJavaType());
// 字段驼峰名
configItem.set("fieldNameCamelCase", StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase()));
// 字段驼峰首字母大写名
configItem.set("fieldNameCamelCaseFirstUpper", StrUtil.upperFirst(StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase())));
// 字段注释
configItem.set("fieldRemark", genConfig.getFieldRemark());
// 是否需要自动插入
configItem.set("needAutoInsert", CREATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
CREATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
// 是否需要自动更新
configItem.set("needAutoUpdate", UPDATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
UPDATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
// 是否需要逻辑删除
configItem.set("needLogicDelete", DELETE_FLAG_KEY.equalsIgnoreCase(genConfig.getFieldName()));
configList.add(configItem);
});
// 配置信息
bindingJsonObject.set("configList", configList);
// 有排序字段
bindingJsonObject.set("hasSortCodeField", hasSortCodeField.get());
return bindingJsonObject;
}
}

View File

@ -0,0 +1,56 @@
package com.byhah.cloud.admin.module.gen.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.gen.dto.GenConfigDto;
import com.byhah.cloud.orm.mapper.gen.GenConfigMapper;
import com.byhah.cloud.basic.core.entity.gen.GenConfig;
import com.byhah.deploy.basic.core.exception.CommonException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 代码生成详情配置Service接口实现类
*
**/
@Service
public class GenConfigService extends ServiceImpl<GenConfigMapper, GenConfig> {
@Transactional(rollbackFor = Exception.class)
public void edit(GenConfigDto dto) {
GenConfig genConfig = this.queryEntity(dto.getId());
BeanUtil.copyProperties(dto, genConfig);
this.updateById(genConfig);
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
// 执行删除
this.removeByIds(ids);
}
}
public GenConfig detail(Long id) {
return this.queryEntity(id);
}
public GenConfig queryEntity(Long id) {
GenConfig genConfig = this.getById(id);
if (ObjectUtil.isEmpty(genConfig)) {
throw new CommonException("代码生成详情配置不存在id值为{}", id);
}
return genConfig;
}
@Transactional(rollbackFor = Exception.class)
public void editBatch(List<GenConfigDto> dto) {
dto.forEach(this::edit);
}
}

View File

@ -0,0 +1,55 @@
package com.byhah.cloud.admin.module.gen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 预览代码生成结果
**/
@Data
public class GenBasicPreviewVo {
/**
* SQL代码结果集
*/
@Schema(description = "SQL代码结果集")
private List<GenBasicCodeResult> genBasicCodeSqlResultList;
/**
* 前端代码结果集
*/
@Schema(description = "前端代码结果集")
private List<GenBasicCodeResult> genBasicCodeFrontendResultList;
/**
* 后端代码结果集
*/
@Schema(description = "后端代码结果集")
private List<GenBasicCodeResult> genBasicCodeBackendResultList;
@Data
public static class GenBasicCodeResult {
/**
* 代码文件名称
*/
@Schema(description = "代码文件名称")
private String codeFileName;
/**
* 代码文件带路径名称
*/
@Schema(description = "代码文件带路径名称")
private String codeFileWithPathName;
/**
* 代码文件内容
*/
@Schema(description = "代码文件内容")
private String codeFileContent;
}
}

View File

@ -0,0 +1,25 @@
package com.byhah.cloud.admin.module.gen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据库表字段结果
*
**/
@Data
public class GenBasicTableColumnVo {
/** 字段名称 */
@Schema(description = "字段名称")
private String columnName;
/** 字段类型 */
@Schema(description = "字段类型")
private String typeName;
/** 字段注释 */
@Schema(description = "字段注释")
private String columnRemark;
}

View File

@ -0,0 +1,21 @@
package com.byhah.cloud.admin.module.gen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据库表结果
*
**/
@Data
public class GenBasicTableVo {
/** 表名称 */
@Schema(description = "表名称")
private String tableName;
/** 表注释 */
@Schema(description = "表注释")
private String tableRemark;
}

View File

@ -0,0 +1,71 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSearchDto;
import com.byhah.cloud.admin.module.dev.service.DevMessageService;
import com.byhah.cloud.admin.module.dev.vo.DevMessageVo;
import com.byhah.cloud.admin.module.sys.service.SysIndexService;
import com.byhah.cloud.basic.core.entity.dev.DevLog;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.starter.web.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.List;
;
/**
* 系统首页
*/
@Tag(name = "系统首页")
@RequestMapping("/sys/index")
@RestController
@Validated
@RequiredArgsConstructor
public class SysIndexController {
private final SysIndexService sysIndexService;
private final DevMessageService messageService;
@Operation(summary = "获取当前用户站内信列表")
@GetMapping("/message/list")
R<List<DevMessageVo>> messageList() {
DevMessageSearchDto dto = new DevMessageSearchDto();
dto.setReceiveUserId(StpUtil.getLoginIdAsLong());
return R.ok(messageService.page(PageUtils.toNoSizePage(), dto).getRecords());
}
@Operation(summary = "获取站内信详情")
@GetMapping("/message/detail")
R<DevMessageVo> messageDetail(Long id) {
return R.ok(messageService.detail(id));
}
@Operation(summary = "站内信全部标记已读")
@PostMapping("/message/allMessageMarkRead")
R<String> allMessageMarkRead() {
messageService.readAll(StpUtil.getLoginIdAsLong());
return R.ok();
}
@Operation(summary = "获取当前用户访问日志列表")
@GetMapping("/visLog/list")
R<List<DevLog>> visLogList() {
return R.ok(sysIndexService.visLogList());
}
@Operation(summary = "获取当前用户操作日志列表")
@GetMapping("/opLog/list")
R<List<DevLog>> opLogList() {
return R.ok(sysIndexService.opLogList());
}
}

View File

@ -0,0 +1,74 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.cloud.admin.module.sys.vo.SysOrgVo;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.cloud.basic.constant.SystemKey;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.cloud.admin.module.sys.dto.SysOrgDto;
import com.byhah.cloud.admin.module.sys.dto.SysOrgSearchDto;
import com.byhah.cloud.admin.module.sys.service.SysOrgService;
import com.byhah.deploy.starter.web.R;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
* 组织
*/
@Tag(name = "组织")
@RequestMapping("/sys/org")
@RestController
@RequiredArgsConstructor
public class SysOrgController {
private final SysOrgService sysOrgService;
@Operation(summary = "获取组织分页")
@GetMapping("/page")
@SaCheckRole(value = SystemKey.SYS_ROLE)
R<IPage<SysOrgVo>> page(SysOrgSearchDto dto) {
return R.ok(sysOrgService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "获取组织树")
@GetMapping("/tree")
R<List<Tree<Long>>> tree() {
return R.ok(sysOrgService.tree());
}
@Operation(summary = "添加组织")
@PostMapping("/add")
@SaCheckRole(value = SystemKey.SYS_ROLE)
R<Void> add(@RequestBody @Validated(Insert.class) SysOrgDto dto) {
sysOrgService.add(dto);
return R.ok();
}
@Operation(summary = "编辑组织")
@PostMapping("/edit")
@SaCheckRole(value = SystemKey.SYS_ROLE)
R<Void> edit(@RequestBody @Validated(Update.class) SysOrgDto dto) {
sysOrgService.edit(dto);
return R.ok();
}
@Operation(summary = "删除组织")
@PostMapping("/delete")
@SaCheckRole(value = SystemKey.SYS_ROLE)
R<String> delete(@RequestBody @Validated @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
sysOrgService.delete(ids);
return R.ok();
}
}

View File

@ -0,0 +1,89 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.cloud.admin.module.sys.dto.ChangeModuleDto;
import com.byhah.cloud.admin.module.sys.dto.ResourceTreeDto;
import com.byhah.cloud.admin.module.sys.dto.SysResourceDto;
import com.byhah.cloud.admin.module.sys.dto.SysResourceSearchDto;
import com.byhah.cloud.admin.module.sys.service.SysResourceService;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.system.SysResource;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.deploy.starter.web.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Tag(name = "菜单")
@RestController
@RequestMapping("/sys/resource")
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class SysResourceController {
private final SysResourceService sysMenuService;
@Operation(summary = "获取菜单分页")
@GetMapping("/page")
public R<Page<SysResource>> page(SysResourceSearchDto dto) {
return R.ok(sysMenuService.page(dto));
}
@Operation(summary = "获取菜单列表")
@GetMapping("/list")
public R<List<SysResource>> list(SysResourceSearchDto dto) {
return R.ok(sysMenuService.page(dto).getRecords());
}
@Operation(summary = "获取菜单树")
@GetMapping("/tree")
public R<List<Tree<Long>>> tree(ResourceTreeDto dto) {
return R.ok(sysMenuService.menuTreeSelector(dto));
}
@Operation(summary = "添加菜单")
@PostMapping("/add")
public R<String> add(@RequestBody @Validated(Insert.class) SysResourceDto dto) {
sysMenuService.add(dto);
return R.ok();
}
@Operation(summary = "编辑菜单")
@PostMapping("/edit")
public R<String> edit(@RequestBody @Validated(Update.class) SysResourceDto dto) {
sysMenuService.edit(dto);
return R.ok();
}
@Operation(summary = "更改菜单所属模块")
@PostMapping("/changeModule")
public R<String> changeModule(@RequestBody @Valid ChangeModuleDto dto) {
sysMenuService.changeModule(dto);
return R.ok();
}
@Operation(summary = "删除菜单")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
sysMenuService.delete(ids);
return R.ok();
}
@Operation(summary = "获取菜单详情")
@GetMapping("/detail")
public R<SysResource> detail(Long id) {
return R.ok(sysMenuService.getById(id));
}
}

View File

@ -0,0 +1,102 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.sys.dto.SysRoleDto;
import com.byhah.cloud.admin.module.sys.dto.SysRoleGrantResourceDto;
import com.byhah.cloud.admin.module.sys.dto.SysRoleGrantUserDto;
import com.byhah.cloud.admin.module.sys.service.SysRoleService;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.system.SysResource;
import com.byhah.cloud.basic.core.entity.system.SysRole;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 角色
*/
@Tag(name = "角色")
@RestController
@RequestMapping("/sys/role")
@Validated
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class SysRoleController {
private final SysRoleService sysRoleService;
@Operation(summary = "获取角色分页")
@GetMapping("/page")
public R<Page<SysRole>> page(@RequestParam(required = false) String searchKey) {
return R.ok(sysRoleService.lambdaQuery().like(CharSequenceUtil.isNotBlank(searchKey), SysRole::getName, searchKey).orderByAsc(SysRole::getSortCode).page(PageUtils.toPage()));
}
@Operation(summary = "添加角色")
@PostMapping("/add")
public R<String> add(@RequestBody @Validated(Insert.class) SysRoleDto dto) {
sysRoleService.add(dto);
return R.ok();
}
@Operation(summary = "编辑角色")
@PostMapping("/edit")
public R<String> edit(@RequestBody @Validated(Update.class) SysRoleDto dto) {
sysRoleService.edit(dto);
return R.ok();
}
@Operation(summary = "删除角色")
@PostMapping("/delete")
public R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
sysRoleService.delete(ids);
return R.ok();
}
@Operation(summary = "获取角色详情")
@GetMapping("/detail")
public R<SysRole> detail(Long id) {
return R.ok(sysRoleService.detail(id));
}
@Operation(summary = "获取角色拥有资源")
@GetMapping("/ownResource")
public R<List<SysResource>> ownResource(Long id) {
return R.ok(sysRoleService.ownResource(id));
}
@Operation(summary = "给角色授权资源")
@PostMapping("/grantResource")
public R<String> grantResource(@RequestBody @Valid SysRoleGrantResourceDto dto) {
sysRoleService.grantResource(dto);
return R.ok();
}
@Operation(summary = "获取角色下的用户")
@GetMapping("/ownUser")
public R<List<Long>> ownUser(Long id) {
return R.ok(sysRoleService.ownUser(id));
}
@Operation(summary = "给角色授权用户")
@PostMapping("/grantUser")
public R<String> grantUser(@RequestBody @Valid SysRoleGrantUserDto dto) {
sysRoleService.grantUser(dto);
return R.ok();
}
}

View File

@ -0,0 +1,68 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.sys.dto.SysTenantDto;
import com.byhah.cloud.admin.module.sys.service.SysTenantService;
import com.byhah.cloud.admin.module.sys.vo.SysTenantVo;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.system.SysTenant;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "租户")
@RestController
@SaCheckRole(value = SystemKey.SYS_ROLE)
@RequiredArgsConstructor
@RequestMapping("/sys/tenant")
public class SysTenantController {
private final SysTenantService sysTenantService;
@Operation(summary = "获取租户分页")
@GetMapping("/page")
R<IPage<SysTenantVo>> page() {
return R.ok(sysTenantService.page(PageUtils.toPage()).convert(SysTenantVo::new));
}
@Operation(summary = "添加租户")
@SaCheckPermission("sys:tenant:add")
@PostMapping("/add")
R<Void> add(@RequestBody @Validated(Insert.class) SysTenantDto dto) {
sysTenantService.add(dto);
return R.ok();
}
@Operation(summary = "编辑租户")
@SaCheckPermission("sys:tenant:edit")
@PostMapping("/edit")
R<Void> edit(@RequestBody @Validated(Update.class) SysTenantDto dto) {
sysTenantService.edit(dto);
return R.ok();
}
@Operation(summary = "删除租户")
@SaCheckPermission("sys:tenant:delete")
@PostMapping("/delete")
R<String> delete(@RequestBody @Validated @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
sysTenantService.delete(ids);
return R.ok();
}
@Operation(summary = "获取租户详情")
@GetMapping("/detail")
R<SysTenant> detail(Long id) {
return R.ok(sysTenantService.detail(id));
}
}

View File

@ -0,0 +1,100 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.dev.dto.DevMessageSearchDto;
import com.byhah.cloud.admin.module.dev.service.DevMessageService;
import com.byhah.cloud.admin.module.dev.vo.DevMessageVo;
import com.byhah.cloud.admin.module.sys.dto.SysUserSignatureDto;
import com.byhah.cloud.admin.module.sys.dto.SysUserUpdateInfoDto;
import com.byhah.cloud.admin.module.sys.dto.SysUserUpdatePwdDto;
import com.byhah.cloud.admin.module.sys.service.SysUserService;
import com.byhah.cloud.admin.utils.UserUtil;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 用户个人
**/
@Tag(name = "用户个人")
@RequestMapping("/sys/userCenter")
@RestController
@Validated
@RequiredArgsConstructor
public class SysUserCenterController {
private final SysUserService sysUserService;
private final DevMessageService messageService;
@Operation(summary = "修改用户密码")
@PostMapping("/updatePassword")
public R<String> updatePassword(@RequestBody @Valid SysUserUpdatePwdDto dto) {
sysUserService.updatePassword(dto);
return R.ok();
}
@Operation(summary = "修改用户头像")
@PostMapping("/updateAvatar")
public R<String> updateAvatar(@RequestPart("file") MultipartFile file) {
return R.ok(sysUserService.updateAvatar(file));
}
@Operation(summary = "修改用户签名图片")
@PostMapping("/updateSignature")
public R<String> updateSignature(@RequestBody @Valid SysUserSignatureDto dto) {
sysUserService.updateSignature(dto);
return R.ok();
}
@Operation(summary = "获取登录用户菜单")
@GetMapping("/loginMenu")
public R<List<Tree<Long>>> loginMenu() {
return R.ok(sysUserService.ownMenu(UserUtil.getLoginUser()));
}
@Operation(summary = "获取登录用户组织树")
@GetMapping("/loginOrgTree")
public R<List<Tree<Long>>> loginOrgTree() {
return R.ok(sysUserService.loginOrgTree(StpUtil.getLoginIdAsLong()));
}
@Operation(summary = "编辑个人信息")
@PostMapping("/updateUserInfo")
public R<String> updateUserInfo(@RequestBody @Valid SysUserUpdateInfoDto dto) {
dto.setId(StpUtil.getLoginIdAsLong());
sysUserService.updateUserInfo(dto);
return R.ok();
}
@Operation(summary = "获取登录用户的站内信分页")
@GetMapping("/loginUnreadMessagePage")
public R<IPage<DevMessageVo>> loginMessagePage(DevMessageSearchDto dto) {
dto.setReceiveUserId(StpUtil.getLoginIdAsLong());
return R.ok(messageService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "读取登录用户站内信详情")
@GetMapping("/loginUnreadMessageDetail")
public R<DevMessageVo> loginMessageDetail(Long id) {
return R.ok(messageService.detail(id));
}
@Operation(summary = "根据id集合获取用户集合")
@PostMapping("/getUserListByIdList")
public R<List<SysUser>> getUserListByIdList(@RequestBody CommonValidList<Long> ids) {
return R.ok(sysUserService.getUserListByIdList(ids));
}
}

View File

@ -0,0 +1,108 @@
package com.byhah.cloud.admin.module.sys.controller;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.byhah.deploy.basic.util.web.PageUtils;
import com.byhah.deploy.basic.validation.entity.CommonValidList;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import com.byhah.deploy.starter.web.R;
import com.byhah.cloud.admin.module.sys.dto.SysUserDto;
import com.byhah.cloud.admin.module.sys.dto.SysUserGrantRoleDto;
import com.byhah.cloud.admin.module.sys.dto.SysUserSearchDto;
import com.byhah.cloud.admin.module.sys.service.SysUserService;
import com.byhah.cloud.admin.module.sys.vo.SysUserVo;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.system.SysRole;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户
**/
@Tag(name = "用户")
@RestController
@RequestMapping("/sys/user")
@RequiredArgsConstructor
@SaCheckRole(value = SystemKey.SYS_ROLE)
public class SysUserController {
private final SysUserService sysUserService;
@Operation(summary = "获取用户分页")
@GetMapping("/page")
R<IPage<SysUserVo>> page(SysUserSearchDto dto) {
return R.ok(sysUserService.page(PageUtils.toPage(), dto));
}
@Operation(summary = "添加用户")
@PostMapping("/add")
R<String> add(@RequestBody @Validated(Insert.class) SysUserDto dto) {
sysUserService.add(dto);
return R.ok();
}
@Operation(summary = "编辑用户")
@PostMapping("/edit")
R<String> edit(@RequestBody @Validated(Update.class) SysUserDto dto) {
sysUserService.edit(dto);
return R.ok();
}
@Operation(summary = "删除用户")
@PostMapping("/delete")
R<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<Long> ids) {
sysUserService.delete(ids);
return R.ok();
}
@Operation(summary = "获取用户详情")
@GetMapping("/detail")
R<SysUser> detail(Long id) {
return R.ok(sysUserService.detail(id));
}
@Operation(summary = "禁用用户")
@PostMapping("/disableUser/{id}")
R<String> disableUser(@PathVariable Long id) {
sysUserService.disableUser(id);
return R.ok();
}
@Operation(summary = "启用用户")
@PostMapping("/enableUser/{id}")
R<String> enableUser(@PathVariable Long id) {
sysUserService.enableUser(id);
return R.ok();
}
@Operation(summary = "重置用户密码")
@PostMapping("/resetPassword/{id}")
R<String> resetPassword(@PathVariable Long id) {
sysUserService.resetPassword(id);
return R.ok();
}
@Operation(summary = "获取用户拥有角色")
@GetMapping("/ownRole")
R<List<SysRole>> ownRole(Long id) {
return R.ok(sysUserService.ownRole(id));
}
@Operation(summary = "给用户授权角色")
@PostMapping("/grantRole")
R<String> grantRole(@RequestBody @Valid SysUserGrantRoleDto dto) {
sysUserService.grantRole(dto);
return R.ok();
}
}

View File

@ -0,0 +1,13 @@
package com.byhah.cloud.admin.module.sys.dto;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Data
public class ChangeModuleDto {
@NotNull
private Long id;
@NotNull
private Long module;
}

View File

@ -0,0 +1,17 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class ResourceTreeDto {
@Schema(description = "筛选模块 传入是不会查出模块层资源")
private Long module;
@Schema(description = "排除掉的资源类型")
private List<Integer> excludeCategory;
private String searchKey;
}

View File

@ -0,0 +1,32 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* 组织添加参数
**/
@Data
public class SysOrgDto {
@Schema(description = "id")
@NotNull(message = "id不能为空", groups = Update.class)
@Null(message = "id必须为空", groups = Insert.class)
private Long id;
@Schema(description = "父id")
private Long parentId;
@Schema(description = "名称")
@NotBlank(message = "name不能为空")
private String name;
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
@Schema(description = "主管id")
private Long directorId;
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 组织查询参数
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class SysOrgSearchDto extends CommonSearch {
/**
* 父id
*/
@Schema(description = "父id")
private Long parentId;
}

View File

@ -0,0 +1,83 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import org.hibernate.validator.constraints.Range;
/**
* 菜单添加参数
**/
@Data
public class SysResourceDto {
@NotNull(groups = Update.class)
@Null(groups = Insert.class)
private Long id;
/**
* 父id
*/
@Schema(description = "父id", required = true)
// @NotNull(message = "parentId不能为空")
private Long parentId;
/**
* 标题
*/
@Schema(description = "标题", required = true)
@NotBlank(message = "title不能为空")
private String title;
/**
* 菜单类型
*/
@Schema(description = "菜单类型", required = true)
// @NotBlank(message = "menuType不能为空")
private Integer menuType;
/**
* 路径
*/
@Schema(description = "路径", required = true)
// @NotBlank(message = "path不能为空")
private String path;
/**
* 排序码
*/
@Schema(description = "排序码", required = true)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/**
* 别名
*/
@Schema(description = "别名")
private String name;
/**
* 组件
*/
@Schema(description = "组件")
private String component;
private Long module;
/**
* 图标
*/
@Schema(description = "图标")
private String icon;
private String code;
@Range(min = 1, max = 4)
private Integer category;
}

View File

@ -0,0 +1,26 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 菜单查询参数
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class SysResourceSearchDto extends CommonSearch {
/**
* 模块
*/
@Schema(description = "模块")
private Long module;
@Schema(description = "菜单类型 1模块 2菜单 3按钮 4单页面")
private Integer category;
private Long parentId;
}

View File

@ -0,0 +1,33 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* 角色添加参数
**/
@Data
public class SysRoleDto {
@NotNull(message = "id不能为空",groups = Update.class)
@Null(message = "id必须为空",groups = Insert.class)
private Long id;
@Schema(description = "名称", required = true)
@NotBlank(message = "name不能为空")
private String name;
@NotBlank(message = "权限代码不能为空")
private String code;
@Schema(description = "排序码", required = true)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
}

View File

@ -0,0 +1,31 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 角色授权资源参数
**/
@Data
public class SysRoleGrantResourceDto {
/**
* 角色id
*/
@Schema(description = "角色id", required = true)
@NotNull(message = "id不能为空")
private Long id;
/**
* 授权资源信息
*/
@Valid
@Schema(description = "授权资源信息", required = true)
@NotNull(message = "grantInfoList不能为空")
private List<Long> resourceIds;
}

View File

@ -0,0 +1,30 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 角色授权用户参数
*
**/
@Data
public class SysRoleGrantUserDto {
/**
* 角色id
*/
@Schema(description = "角色id", required = true)
@NotNull(message = "id不能为空")
private Long id;
/**
* 授权用户信息
*/
@Schema(description = "授权用户信息", required = true)
@NotNull(message = "grantInfoList不能为空")
private List<Long> grantInfoList;
}

View File

@ -0,0 +1,28 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
/**
* sys_tenant编辑参数
**/
@Data
public class SysTenantDto {
@NotNull(message = "id不能为空", groups = Update.class)
@Null(message = "id必须为空", groups = Insert.class)
private Long id;
@NotBlank
private String name;
@NotBlank
private String phone;
@NotBlank
private String account;
}

View File

@ -0,0 +1,72 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.deploy.basic.validation.group.Insert;
import com.byhah.deploy.basic.validation.group.Update;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import java.time.LocalDate;
/**
* 用户添加参数
**/
@Data
public class SysUserDto {
@Schema(description = "id", required = true)
@NotNull(message = "id不能为空",groups = Update.class)
@Null(message = "id必须为空",groups = Insert.class)
private Long id;
/**
* 账号
*/
@Schema(description = "账号")
@NotBlank(message = "account不能为空")
private String account;
/**
* 姓名
*/
@Schema(description = "姓名", required = true)
@NotBlank(message = "name不能为空")
private String name;
/**
* 组织id
*/
@Schema(description = "组织id")
private Long orgId;
/**
* 头像
*/
@Schema(description = "头像图片base64")
private String avatar;
/**
* 签名
*/
@Schema(description = "签名图片base64")
private String signature;
/**
* 性别
*/
@Schema(description = "性别")
private Integer gender;
/**
* 手机
*/
@Schema(description = "手机")
private String phone;
/**
* 排序码
*/
@Schema(description = "排序码")
private Integer sortCode;
}

View File

@ -0,0 +1,26 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 用户授权角色参数
*
**/
@Data
public class SysUserGrantRoleDto {
/** id */
@Schema(description = "id", required = true)
@NotNull(message = "id不能为空")
private Long id;
/** 角色id集合 */
@Schema(description = "角色id集合", required = true)
@NotNull(message = "roleIdList不能为空")
private List<Long> roleIdList;
}

View File

@ -0,0 +1,31 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.cloud.basic.core.model.CommonSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 用户查询参数
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class SysUserSearchDto extends CommonSearch {
/**
* 用户状态
*/
@Schema(description = "用户状态")
private String userStatus;
/**
* 所属组织
*/
@Schema(description = "所属组织")
private Long orgId;
private List<Long> ids;
}

View File

@ -0,0 +1,20 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 用户修改签名图片接口
*
**/
@Data
public class SysUserSignatureDto {
/** 签名图片base64编码 */
@Schema(description = "signature", required = true)
@NotBlank(message = "signature签名图片不能为空")
private String signature;
}

View File

@ -0,0 +1,27 @@
package com.byhah.cloud.admin.module.sys.dto;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 编辑个人信息参数
**/
@Data
public class SysUserUpdateInfoDto {
private Long id;
@Schema(description = "姓名", required = true)
@NotBlank(message = "name不能为空")
private String name;
@Schema(description = "手机")
private String phone;
@Schema(description = "性别")
private Integer gender;
@Schema(description = "签名图片base64")
private String signature;
private SysUser.WorkBenchData workBenchData;
}

View File

@ -0,0 +1,24 @@
package com.byhah.cloud.admin.module.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 用户修改密码参数
**/
@Data
public class SysUserUpdatePwdDto {
/** 旧密码 */
@Schema(description = "旧密码", required = true)
@NotBlank(message = "password不能为空")
private String password;
/** 新密码 */
@Schema(description = "新密码", required = true)
@NotBlank(message = "newPassword不能为空")
private String newPassword;
}

View File

@ -0,0 +1,40 @@
package com.byhah.cloud.admin.module.sys.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.byhah.cloud.admin.module.dev.service.DevLogService;
import com.byhah.cloud.admin.utils.UserUtil;
import com.byhah.cloud.basic.core.entity.dev.DevLog;
import com.byhah.cloud.basic.core.enums.dev.DevLogType;
import com.byhah.deploy.basic.util.web.PageUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 系统首页Service接口实现类
*/
@Service
@RequiredArgsConstructor
public class SysIndexService {
private final DevLogService devLogApi;
public List<DevLog> visLogList() {
return devLogApi.page(PageUtils.toPage(), new LambdaQueryWrapper<DevLog>()
.eq(DevLog::getOpUser, UserUtil.getLoginUser().getName())
.in(DevLog::getCategory, DevLogType.LOGIN, DevLogType.LOGOUT)
.orderByDesc(DevLog::getCreatedAt))
.getRecords();
}
public List<DevLog> opLogList() {
return devLogApi.page(PageUtils.toPage(), new LambdaQueryWrapper<DevLog>()
.select(DevLog::getId, DevLog::getCategory, DevLog::getName, DevLog::getOpTime, DevLog::getExeStatus)
.eq(DevLog::getOpUser, UserUtil.getLoginUser().getName())
.in(DevLog::getCategory, DevLogType.OPERATE, DevLogType.EXCEPTION)
.orderByDesc(DevLog::getCreatedAt))
.getRecords();
}
}

View File

@ -0,0 +1,146 @@
package com.byhah.cloud.admin.module.sys.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.mapper.SysUserMapper;
import com.byhah.cloud.admin.module.sys.dto.SysOrgDto;
import com.byhah.cloud.admin.module.sys.dto.SysOrgSearchDto;
import com.byhah.cloud.admin.module.sys.vo.SysOrgVo;
import com.byhah.cloud.orm.mapper.sys.ISysOrgMapper;
import com.byhah.cloud.orm.mapper.sys.ISysUserMapper;
import com.byhah.cloud.basic.core.entity.system.SysOrg;
import com.byhah.cloud.basic.core.entity.system.SysUser;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.core.utils.Asserts;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 组织Service接口实现类
**/
@Service
@RequiredArgsConstructor
public class SysOrgService extends ServiceImpl<ISysOrgMapper, SysOrg> {
private final SysUserMapper sysUserMapper;
private final ISysUserMapper userMapper;
public IPage<SysOrgVo> page(Page<?> page, SysOrgSearchDto dto) {
return sysUserMapper.sysOrgs(page, dto);
}
public List<Tree<Long>> tree() {
List<SysOrg> sysOrgList = list();
List<TreeNode<Long>> treeNodeList = sysOrgList.stream().map(sysOrg ->
new TreeNode<>(sysOrg.getId(), sysOrg.getParentId(),
sysOrg.getName(), sysOrg.getSortCode()).setExtra(JSONUtil.parseObj(sysOrg)))
.collect(Collectors.toList());
return TreeUtil.build(treeNodeList, 0L);
}
@Transactional(rollbackFor = Exception.class)
public void add(SysOrgDto dto) {
if (Objects.isNull(dto.getParentId())) {
dto.setParentId(0L);
}
SysOrg sysOrg = BeanUtil.toBean(dto, SysOrg.class);
Long count = lambdaQuery().eq(SysOrg::getParentId, dto.getParentId()).eq(SysOrg::getName, dto.getName()).count();
Asserts.isTrue(count == 0, "存在重复的同级组织");
sysOrg.setCode(RandomUtil.randomString(10));
save(sysOrg);
}
@Transactional(rollbackFor = Exception.class)
public void edit(SysOrgDto dto) {
if (Objects.isNull(dto.getParentId())) {
dto.setParentId(0L);
}
SysOrg dbOrg = queryEntity(dto.getId());
BeanUtil.copyProperties(dto, dbOrg);
Long count = lambdaQuery().eq(SysOrg::getParentId, dto.getParentId()).ne(SysOrg::getId, dto.getId()).eq(SysOrg::getName, dto.getName()).count();
Asserts.isTrue(count == 0, "存在重复的同级组织");
List<SysOrg> originDataList = getAllOrgList();
boolean errorLevel = getChildListById(originDataList, dbOrg.getId(), true).stream()
.map(SysOrg::getId).toList().contains(dbOrg.getParentId());
if (errorLevel) {
throw new CommonException("不可选择上级组织:{}", getById(originDataList, dbOrg.getParentId()).getName());
}
updateById(dbOrg);
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> orgIdList) {
if (ObjectUtil.isNotEmpty(orgIdList)) {
List<SysOrg> allOrgList = getAllOrgList();
// 获取所有子组织
List<Long> toDeleteOrgIdList = CollectionUtil.newArrayList();
orgIdList.forEach(orgId -> toDeleteOrgIdList.addAll(getChildListById(allOrgList, orgId, true).stream()
.map(SysOrg::getId).toList()));
// 组织下有人不能删除直属组织
boolean hasOrgUser = userMapper.lambdaQueryChain().in(SysUser::getOrgId, toDeleteOrgIdList).count() > 0;
if (hasOrgUser) {
throw new CommonException("请先删除组织下的用户");
}
// 执行删除
removeByIds(toDeleteOrgIdList);
}
}
public SysOrg queryEntity(Long id) {
SysOrg sysOrg = getById(id);
if (ObjectUtil.isEmpty(sysOrg)) {
throw new CommonException("组织不存在id值为{}", id);
}
return sysOrg;
}
public List<SysOrg> getAllOrgList() {
return list(new LambdaQueryWrapper<SysOrg>().orderByAsc(SysOrg::getSortCode));
}
/* ====以下为各种递归方法==== */
public List<SysOrg> getChildListById(List<SysOrg> originDataList, Long id, boolean includeSelf) {
List<SysOrg> resultList = CollectionUtil.newArrayList();
execRecursionFindChild(originDataList, id, resultList);
if (includeSelf) {
SysOrg self = getById(originDataList, id);
if (ObjectUtil.isNotEmpty(self)) {
resultList.add(self);
}
}
return resultList;
}
public void execRecursionFindChild(List<SysOrg> originDataList, Long id, List<SysOrg> resultList) {
originDataList.forEach(item -> {
if (item.getParentId().equals(id)) {
resultList.add(item);
execRecursionFindChild(originDataList, item.getId(), resultList);
}
});
}
public SysOrg getById(List<SysOrg> originDataList, Long id) {
int index = CollStreamUtil.toList(originDataList, SysOrg::getId).indexOf(id);
return index == -1 ? null : originDataList.get(index);
}
}

View File

@ -0,0 +1,86 @@
package com.byhah.cloud.admin.module.sys.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.basic.core.enums.sys.SysRelationType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.byhah.cloud.orm.mapper.sys.ISysRelationMapper;
import com.byhah.cloud.basic.core.entity.system.SysRelation;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 关系Service接口实现类
**/
@Service
public class SysRelationService extends ServiceImpl<ISysRelationMapper, SysRelation> {
@Transactional(rollbackFor = Exception.class)
public void saveRelationBatch(Long objectId, List<Long> targetIdList, SysRelationType category, boolean clear) {
// 是否需要先删除关系
if (clear) {
this.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getObjectId, objectId)
.eq(SysRelation::getCategory, category));
}
List<SysRelation> sysRelationList = CollectionUtil.newArrayList();
for (Long id : targetIdList) {
SysRelation sysRelation = new SysRelation();
sysRelation.setObjectId(objectId);
sysRelation.setTargetId(id);
sysRelation.setCategory(category);
sysRelationList.add(sysRelation);
}
if (ObjectUtil.isNotEmpty(sysRelationList)) {
this.saveBatch(sysRelationList);
}
}
public List<SysRelation> getRelationListByObjectIdAndCategory(Long objectId, SysRelationType category) {
LambdaQueryWrapper<SysRelation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysRelation::getObjectId, objectId);
if (Objects.nonNull(category)) {
lambdaQueryWrapper.eq(SysRelation::getCategory, category);
}
return this.list(lambdaQueryWrapper);
}
public List<SysRelation> getRelationListByObjectIdListAndCategory(List<Long> objectIdList, SysRelationType category) {
LambdaQueryWrapper<SysRelation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(SysRelation::getObjectId, objectIdList);
if (Objects.nonNull(category)) {
lambdaQueryWrapper.eq(SysRelation::getCategory, category);
}
return this.list(lambdaQueryWrapper);
}
public List<SysRelation> getRelationListByTargetIdAndCategory(Long targetId, SysRelationType category) {
LambdaQueryWrapper<SysRelation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysRelation::getTargetId, targetId);
if (ObjectUtil.isNotEmpty(category)) {
lambdaQueryWrapper.eq(SysRelation::getCategory, category);
}
return this.list(lambdaQueryWrapper);
}
public List<Long> getRelationTargetIdListByObjectIdAndCategory(Long objectId, SysRelationType category) {
return this.getRelationListByObjectIdAndCategory(objectId, category).stream()
.map(SysRelation::getTargetId).collect(Collectors.toList());
}
public List<Long> getRelationTargetIdListByObjectIdListAndCategory(List<Long> objectIdList, SysRelationType category) {
return this.getRelationListByObjectIdListAndCategory(objectIdList, category).stream()
.map(SysRelation::getTargetId).collect(Collectors.toList());
}
public List<Long> getRelationObjectIdListByTargetIdAndCategory(Long targetId, SysRelationType category) {
return this.getRelationListByTargetIdAndCategory(targetId, category).stream()
.map(SysRelation::getObjectId).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,213 @@
package com.byhah.cloud.admin.module.sys.service;
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.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.sys.dto.ChangeModuleDto;
import com.byhah.cloud.admin.module.sys.dto.ResourceTreeDto;
import com.byhah.cloud.admin.module.sys.dto.SysResourceDto;
import com.byhah.cloud.admin.module.sys.dto.SysResourceSearchDto;
import com.byhah.cloud.orm.mapper.sys.ISysResourceMapper;
import com.byhah.cloud.basic.core.entity.system.SysRelation;
import com.byhah.cloud.basic.core.entity.system.SysResource;
import com.byhah.cloud.basic.core.enums.sys.SysMenuType;
import com.byhah.cloud.basic.core.enums.sys.SysResourceType;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.core.utils.Asserts;
import com.byhah.deploy.basic.util.web.PageUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import static com.byhah.cloud.basic.core.enums.sys.SysResourceType.*;
/**
* 菜单Service接口实现类
**/
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class SysResourceService extends ServiceImpl<ISysResourceMapper, SysResource> {
private final SysRelationService sysRelationService;
public Page<SysResource> page(SysResourceSearchDto dto) {
return lambdaQuery().eq(SysResource::getCategory, dto.getCategory()).like(StrUtil.isNotBlank(dto.getSearchKey()), SysResource::getTitle, dto.getSearchKey())
.eq(Objects.nonNull(dto.getModule()), SysResource::getModule, dto.getModule())
.eq(Objects.nonNull(dto.getParentId()), SysResource::getParentId, dto.getParentId())
.orderByAsc(SysResource::getSortCode)
.page(PageUtils.toPage());
}
private void fillParentSysResourceInfo(List<SysResource> resourceList) {
if (CollUtil.isNotEmpty(resourceList)) {
List<Long> parentIds = resourceList.stream().map(SysResource::getParentId).filter(x -> !Objects.equals(x, 0L)).distinct().collect(Collectors.toList());
if (CollUtil.isNotEmpty(parentIds)) {
List<SysResource> parents = lambdaQuery().ne(SysResource::getCategory, MODULE).in(SysResource::getId, parentIds).list();
if (CollUtil.isNotEmpty(parents)) {
fillParentSysResourceInfo(parents);
resourceList.addAll(parents);
}
}
}
}
@Transactional(rollbackFor = Exception.class)
public void add(SysResourceDto dto) {
checkParam(dto);
SysResource resource = BeanUtil.toBean(dto, SysResource.class);
Long count = lambdaQuery().eq(SysResource::getParentId, resource.getParentId()).eq(SysResource::getTitle, resource.getTitle()).count();
Asserts.isTrue(count == 0, "存在重复的菜单");
if (Objects.nonNull(dto.getParentId()) && dto.getParentId() != 0L) {
SysResource parent = getById(dto.getParentId());
Asserts.notNull(parent, "上级菜单不存在");
if (parent.getCategory() == MODULE) {
resource.setModule(parent.getId());
} else {
resource.setModule(parent.getModule());
}
}
resource.setCategory(SysResourceType.forValue(dto.getCategory()));
save(resource);
}
private void checkParam(SysResourceDto dto) {
if (dto.getCategory() != SPA.getType()) {
Asserts.notNull(dto.getParentId(), "parentId不能为空");
}
if (dto.getCategory() == MENU.getType()) {
Asserts.notNull(dto.getMenuType(), "菜单类型不能为空");
if (dto.getMenuType() == SysMenuType.MENU.getType()) {
Asserts.notNull(dto.getComponent(), "component不能为空");
} else if (dto.getMenuType() == SysMenuType.IFRAME.getType() || dto.getMenuType() == SysMenuType.LINK.getType()) {
dto.setName(RandomUtil.randomNumbers(10));
dto.setComponent(null);
} else {
dto.setName(null);
dto.setComponent(null);
}
} else if (dto.getCategory() == MODULE.getType()) {
Asserts.isTrue(StrUtil.isNotBlank(dto.getTitle()), "模块名不能为空");
Asserts.isTrue(StrUtil.isNotBlank(dto.getIcon()), "模块图标不能为空");
} else if (dto.getCategory() == BUTTON.getType()) {
Asserts.isTrue(StrUtil.isNotBlank(dto.getTitle()), "按钮名不能为空");
Asserts.isTrue(StrUtil.isNotBlank(dto.getCode()), "按钮编码不能为空");
}
}
@Transactional(rollbackFor = Exception.class)
public void edit(SysResourceDto dto) {
SysResource resource = queryEntity(dto.getId());
checkParam(dto);
BeanUtil.copyProperties(dto, resource);
boolean repeatTitle = count(new LambdaQueryWrapper<SysResource>().eq(SysResource::getParentId, resource.getParentId()).eq(SysResource::getCategory, MENU).eq(SysResource::getTitle, resource.getTitle()).ne(SysResource::getId, resource.getId())) > 0;
if (repeatTitle) {
throw new CommonException("存在重复的菜单,名称为:{}", resource.getTitle());
}
List<SysResource> originDataList = list(new LambdaQueryWrapper<SysResource>().eq(SysResource::getCategory, MENU));
boolean errorLevel = getChildListById(originDataList, resource.getId(), true).stream().map(SysResource::getId).toList().contains(resource.getParentId());
if (errorLevel) {
throw new CommonException("不可选择上级菜单:{}", getById(originDataList, resource.getParentId()).getName());
}
if (Objects.nonNull(dto.getParentId()) && dto.getParentId() != 0L) {
SysResource parentMenu = getById(dto.getParentId());
Asserts.notNull(parentMenu, "上级菜单不存在");
}
updateById(resource);
}
public void changeModule(ChangeModuleDto dto) {
SysResource resource = queryEntity(dto.getId());
if (!resource.getParentId().equals(0L)) {
throw new CommonException("非顶级菜单不可修改所属模块");
}
List<SysResource> resources = list(new LambdaQueryWrapper<SysResource>().eq(SysResource::getCategory, MENU));
List<SysResource> sysResourceChildList = getChildListById(resources, resource.getId(), true).stream().peek(x -> x.setModule(dto.getModule())).collect(Collectors.toList());
updateBatchById(sysResourceChildList);
}
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
List<Long> all = childs(ids, new ArrayList<>());
removeByIds(all);
sysRelationService.lambdaUpdate().in(SysRelation::getTargetId, all).remove();
}
}
private List<Long> childs(List<Long> parents, List<Long> all) {
all.addAll(parents);
List<Long> childs = lambdaQuery().in(SysResource::getParentId, parents).select(SysResource::getId).list().stream().map(SysResource::getId).collect(Collectors.toList());
if (CollUtil.isNotEmpty(childs)) {
childs(childs, all);
}
return all;
}
public SysResource detail(Long id) {
return queryEntity(id);
}
public SysResource queryEntity(Long id) {
SysResource SysResource = getById(id);
if (ObjectUtil.isEmpty(SysResource)) {
throw new CommonException("菜单不存在id值为{}", id);
}
return SysResource;
}
public List<Tree<Long>> menuTreeSelector(ResourceTreeDto dto) {
List<SysResource> resourceList = lambdaQuery().notIn(CollUtil.isNotEmpty(dto.getExcludeCategory()), SysResource::getCategory, dto.getExcludeCategory()).eq(StrUtil.isNotBlank(dto.getSearchKey()), SysResource::getTitle, dto.getSearchKey()).eq(Objects.nonNull(dto.getModule()), SysResource::getModule, dto.getModule()).list();
fillParentSysResourceInfo(resourceList);
List<TreeNode<Long>> treeNodeList = resourceList.stream().map(x -> new TreeNode<>(x.getId(), x.getParentId(), x.getTitle(), x.getSortCode()).setExtra(JSONUtil.parseObj(x))).collect(Collectors.toList());
Long root = Optional.ofNullable(dto.getModule()).orElse(0L);
return TreeUtil.build(treeNodeList, root);
}
/* ====以下为各种递归方法==== */
public List<SysResource> getChildListById(List<SysResource> originDataList, Long id, boolean includeSelf) {
List<SysResource> resultList = CollUtil.newArrayList();
execRecursionFindChild(originDataList, id, resultList);
if (includeSelf) {
SysResource self = getById(originDataList, id);
if (ObjectUtil.isNotEmpty(self)) {
resultList.add(self);
}
}
return resultList;
}
public void execRecursionFindChild(List<SysResource> originDataList, Long id, List<SysResource> resultList) {
originDataList.forEach(item -> {
if (item.getParentId().equals(id)) {
resultList.add(item);
execRecursionFindChild(originDataList, item.getId(), resultList);
}
});
}
public SysResource getById(List<SysResource> originDataList, Long id) {
for (SysResource resource : originDataList) {
if (resource.getId().equals(id)) {
return resource;
}
}
return null;
}
}

View File

@ -0,0 +1,133 @@
package com.byhah.cloud.admin.module.sys.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.cloud.admin.module.sys.dto.SysRoleDto;
import com.byhah.cloud.admin.module.sys.dto.SysRoleGrantResourceDto;
import com.byhah.cloud.admin.module.sys.dto.SysRoleGrantUserDto;
import com.byhah.cloud.orm.mapper.sys.ISysRoleMapper;
import com.byhah.cloud.basic.constant.SystemKey;
import com.byhah.cloud.basic.core.entity.system.SysRelation;
import com.byhah.cloud.basic.core.entity.system.SysResource;
import com.byhah.cloud.basic.core.entity.system.SysRole;
import com.byhah.cloud.basic.core.enums.sys.SysRelationType;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.deploy.basic.core.utils.Asserts;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 角色Service接口实现类
**/
@Service
@RequiredArgsConstructor
public class SysRoleService extends ServiceImpl<ISysRoleMapper, SysRole> {
private final SysRelationService sysRelationService;
private final SysResourceService sysMenuService;
@Transactional(rollbackFor = Exception.class)
public void add(SysRoleDto dto) {
Long count = lambdaQuery().eq(SysRole::getName, dto.getName()).count();
Asserts.isTrue(count == 0, "角色名称已存在");
count = lambdaQuery().eq(SysRole::getCode, dto.getCode()).count();
Asserts.isTrue(count == 0, "角色权限代码已存在");
SysRole sysRole = BeanUtil.toBean(dto, SysRole.class);
save(sysRole);
}
@Transactional(rollbackFor = Exception.class)
public void edit(SysRoleDto dto) {
SysRole dbRole = queryEntity(dto.getId());
boolean superRole = dbRole.getCode().equals(SystemKey.SYS_ROLE);
if (superRole) {
throw new CommonException("不可编辑超管角色");
}
Long count = lambdaQuery().eq(SysRole::getName, dto.getName()).ne(SysRole::getId, dbRole.getId()).count();
Asserts.isTrue(count == 0, "角色名称已存在");
count = lambdaQuery().eq(SysRole::getCode, dto.getCode()).ne(SysRole::getId, dbRole.getId()).count();
Asserts.isTrue(count == 0, "角色权限代码已存在");
BeanUtil.copyProperties(dto, dbRole);
updateById(dbRole);
}
@Transactional(rollbackFor = Exception.class)
public void delete(List<Long> ids) {
if (ObjectUtil.isNotEmpty(ids)) {
boolean containsSuperAdminRole = listByIds(ids).stream().map(SysRole::getCode).collect(Collectors.toSet()).contains(SystemKey.SYS_ROLE);
if (containsSuperAdminRole) {
throw new CommonException("不可删除系统内置超管角色");
}
// 级联删除角色与用户关系
sysRelationService.remove(new LambdaUpdateWrapper<SysRelation>().in(SysRelation::getTargetId, ids).eq(SysRelation::getCategory, SysRelationType.USER_HAS_ROLE));
// 级联删除角色与资源关系
sysRelationService.remove(new LambdaUpdateWrapper<SysRelation>().in(SysRelation::getObjectId, ids).eq(SysRelation::getCategory, SysRelationType.ROLE_HAS_RESOURCE));
// 执行删除
removeByIds(ids);
}
}
public SysRole detail(Long id) {
return queryEntity(id);
}
public List<SysResource> ownResource(Long id) {
List<Long> ids = sysRelationService.getRelationListByObjectIdAndCategory(id, SysRelationType.ROLE_HAS_RESOURCE).stream().map(SysRelation::getTargetId).collect(Collectors.toList());
return CollUtil.isNotEmpty(ids) ? sysMenuService.listByIds(ids) : Collections.emptyList();
}
public void grantResource(SysRoleGrantResourceDto dto) {
Long id = dto.getId();
SysRole sysRole = queryEntity(id);
List<Long> menuIdList = dto.getResourceIds();
if (!SystemKey.SYS_ROLE.equals(sysRole.getCode())) {
if (ObjectUtil.isNotEmpty(menuIdList)) {
Set<Long> sysModuleIdList = sysMenuService.listByIds(menuIdList).stream().map(SysResource::getModule).collect(Collectors.toSet());
boolean containsSystemModule = sysMenuService.listByIds(sysModuleIdList).stream().map(SysResource::getCode).collect(Collectors.toSet()).contains(SystemKey.SYS_MODULE);
if (containsSystemModule) {
throw new CommonException("非超管角色不可被授权系统模块菜单资源");
}
}
}
sysRelationService.saveRelationBatch(id, menuIdList, SysRelationType.ROLE_HAS_RESOURCE,true);
}
public List<Long> ownUser(Long id) {
return sysRelationService.getRelationObjectIdListByTargetIdAndCategory(id, SysRelationType.USER_HAS_ROLE);
}
public void grantUser(SysRoleGrantUserDto dto) {
Long id = dto.getId();
List<Long> grantInfoList = dto.getGrantInfoList();
sysRelationService.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getTargetId, id).eq(SysRelation::getCategory, SysRelationType.USER_HAS_ROLE));
sysRelationService.saveBatch(grantInfoList.stream().map(userId -> {
SysRelation sysRelation = new SysRelation();
sysRelation.setObjectId(userId);
sysRelation.setTargetId(id);
sysRelation.setCategory(SysRelationType.USER_HAS_ROLE);
return sysRelation;
}).collect(Collectors.toList()));
}
public SysRole queryEntity(Long id) {
SysRole sysRole = getById(id);
if (ObjectUtil.isEmpty(sysRole)) {
throw new CommonException("角色不存在id值为{}", id);
}
return sysRole;
}
}

View File

@ -0,0 +1,56 @@
package com.byhah.cloud.admin.module.sys.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.byhah.deploy.basic.core.exception.CommonException;
import com.byhah.cloud.admin.module.sys.dto.SysTenantDto;
import com.byhah.cloud.basic.core.entity.system.SysTenant;
import com.byhah.cloud.orm.mapper.sys.ISysTenantMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* sys_tenantService实现类
**/
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class SysTenantService extends ServiceImpl<ISysTenantMapper, SysTenant> {
private final SysUserService userService;
public void add(SysTenantDto dto) {
SysTenant tenant = BeanUtil.toBean(dto, SysTenant.class);
this.save(tenant);
// 保存用户
userService.add(dto.getName(), dto.getAccount(), dto.getPhone());
}
public void edit(SysTenantDto dto) {
SysTenant dbTenant = this.queryEntity(dto.getId());
BeanUtil.copyProperties(dto, dbTenant);
this.updateById(dbTenant);
if (!dbTenant.getAccount().equals(dto.getAccount())) {
userService.add(dto.getName(), dto.getAccount(), dto.getPhone());
}
}
public void delete(List<Long> ids) {
this.removeByIds(ids);
}
public SysTenant detail(Long id) {
return this.queryEntity(id);
}
public SysTenant queryEntity(Long id) {
SysTenant sysTenant = this.getById(id);
if (ObjectUtil.isEmpty(sysTenant)) {
throw new CommonException("sys_tenant不存在id值为{}", id);
}
return sysTenant;
}
}

Some files were not shown because too many files have changed in this diff Show More