1、结构化调整;
This commit is contained in:
149
msgpush-module-system/msgpush-module-system-boot/pom.xml
Normal file
149
msgpush-module-system/msgpush-module-system-boot/pom.xml
Normal file
@@ -0,0 +1,149 @@
|
||||
<?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.njcn</groupId>
|
||||
<artifactId>msgpush-module-system</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>msgpush-module-system-boot</artifactId>
|
||||
<description>系统模块功能服务模块</description>
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-env</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖服务 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-biz-ip</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-rpc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- websocket 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-mq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.anji-plus</groupId>
|
||||
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId> <!-- 文件客户端:解决 ftp 连接 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.mwiede</groupId>
|
||||
<artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId> <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
|
||||
<artifactId>s3</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- 打包 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.njcn.msgpush.module.system;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 项目的启动类
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SystemServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SystemServerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.msgpush.module.system.api.config;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.config.ConfigDO;
|
||||
import com.njcn.msgpush.module.system.service.config.ConfigService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class ConfigApiImpl implements ConfigApi {
|
||||
|
||||
@Resource
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public CommonResult<String> getConfigValueByKey(String key) {
|
||||
ConfigDO config = configService.getConfigByKey(key);
|
||||
return success(config != null ? config.getValue() : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.msgpush.module.system.api.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.api.dept.dto.DeptRespDTO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.DeptService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class DeptApiImpl implements DeptApi {
|
||||
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
|
||||
@Override
|
||||
public CommonResult<DeptRespDTO> getDept(Long id) {
|
||||
DeptDO dept = deptService.getDept(id);
|
||||
return success(BeanUtils.toBean(dept, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptRespDTO>> getDeptList(Collection<Long> ids) {
|
||||
List<DeptDO> depts = deptService.getDeptList(ids);
|
||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateDeptList(Collection<Long> ids) {
|
||||
deptService.validateDeptList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptRespDTO>> getChildDeptList(Long id) {
|
||||
List<DeptDO> depts = deptService.getChildDeptList(id);
|
||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.njcn.msgpush.module.system.api.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.api.dept.dto.PostRespDTO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.PostDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.PostService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class PostApiImpl implements PostApi {
|
||||
|
||||
@Resource
|
||||
private PostService postService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validPostList(Collection<Long> ids) {
|
||||
postService.validatePostList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<PostRespDTO>> getPostList(Collection<Long> ids) {
|
||||
List<PostDO> list = postService.getPostList(ids);
|
||||
return success(BeanUtils.toBean(list, PostRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.njcn.msgpush.module.system.api.dict;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.common.biz.system.dict.dto.DictDataRespDTO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dict.DictDataDO;
|
||||
import com.njcn.msgpush.module.system.service.dict.DictDataService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Primary // 由于 DictDataCommonApi 的存在,必须声明为 @Primary Bean
|
||||
@Hidden
|
||||
public class DictDataApiImpl implements DictDataApi {
|
||||
|
||||
@Resource
|
||||
private DictDataService dictDataService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateDictDataList(String dictType, Collection<String> values) {
|
||||
dictDataService.validateDictDataList(dictType, values);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DictDataRespDTO>> getDictDataList(String dictType) {
|
||||
List<DictDataDO> list = dictDataService.getDictDataListByDictType(dictType);
|
||||
return success(BeanUtils.toBean(list, DictDataRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.msgpush.module.system.api.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.module.system.service.logger.ApiAccessLogService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class ApiAccessLogApiImpl implements ApiAccessLogCommonApi {
|
||||
|
||||
@Resource
|
||||
private ApiAccessLogService apiAccessLogService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {
|
||||
apiAccessLogService.createApiAccessLog(createDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.msgpush.module.system.api.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiErrorLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.module.system.service.logger.ApiErrorLogService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class ApiErrorLogApiImpl implements ApiErrorLogCommonApi {
|
||||
|
||||
@Resource
|
||||
private ApiErrorLogService apiErrorLogService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) {
|
||||
apiErrorLogService.createApiErrorLog(createDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.njcn.msgpush.module.system.api.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.dto.OperateLogCreateReqDTO;
|
||||
import com.njcn.msgpush.module.system.api.logger.dto.OperateLogPageReqDTO;
|
||||
import com.njcn.msgpush.module.system.api.logger.dto.OperateLogRespDTO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.logger.OperateLogDO;
|
||||
import com.njcn.msgpush.module.system.service.logger.OperateLogService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Primary // 由于 OperateLogCommonApi 的存在,必须声明为 @Primary Bean
|
||||
@Hidden
|
||||
public class OperateLogApiImpl implements OperateLogApi {
|
||||
|
||||
@Resource
|
||||
private OperateLogService operateLogService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> createOperateLog(OperateLogCreateReqDTO createReqDTO) {
|
||||
operateLogService.createOperateLog(createReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<PageResult<OperateLogRespDTO>> getOperateLogPage(OperateLogPageReqDTO pageReqDTO) {
|
||||
PageResult<OperateLogDO> operateLogPage = operateLogService.getOperateLogPage(pageReqDTO);
|
||||
return success(BeanUtils.toBean(operateLogPage, OperateLogRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.msgpush.module.system.api.oauth2;
|
||||
|
||||
import com.njcn.msgpush.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
|
||||
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2TokenService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
@Hidden
|
||||
public class OAuth2TokenApiImpl implements OAuth2TokenCommonApi {
|
||||
|
||||
@Resource
|
||||
private OAuth2TokenService oauth2TokenService;
|
||||
|
||||
@Override
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
|
||||
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
|
||||
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<OAuth2AccessTokenCheckRespDTO> checkAccessToken(String accessToken) {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken);
|
||||
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> removeAccessToken(String accessToken) {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
|
||||
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> refreshAccessToken(String refreshToken, String clientId) {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
|
||||
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.msgpush.module.system.api.permission;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.module.system.service.permission.PermissionService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Primary // 由于 PermissionCommonApi 的存在,必须声明为 @Primary Bean
|
||||
@Hidden
|
||||
public class PermissionApiImpl implements PermissionApi {
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Set<Long>> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
|
||||
return success(permissionService.getUserRoleIdListByRoleId(roleIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> hasAnyPermissions(Long userId, String... permissions) {
|
||||
return success(permissionService.hasAnyPermissions(userId, permissions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> hasAnyRoles(Long userId, String... roles) {
|
||||
return success(permissionService.hasAnyRoles(userId, roles));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.njcn.msgpush.module.system.api.user;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.njcn.msgpush.module.system.service.user.AdminUserService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class AdminUserApiImpl implements AdminUserApi {
|
||||
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
|
||||
@Override
|
||||
public CommonResult<AdminUserRespDTO> getUser(Long id) {
|
||||
AdminUserDO user = userService.getUser(id);
|
||||
return success(BeanUtils.toBean(user, AdminUserRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<AdminUserRespDTO>> getUserList(Collection<Long> ids) {
|
||||
List<AdminUserDO> users = userService.getUserList(ids);
|
||||
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<AdminUserRespDTO>> getUserListByDeptIds(Collection<Long> deptIds) {
|
||||
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
|
||||
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<AdminUserRespDTO>> getUserListByPostIds(Collection<Long> postIds) {
|
||||
List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
|
||||
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateUserList(Collection<Long> ids) {
|
||||
userService.validateUserList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.msgpush.module.system.api.websocket;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.websocket.core.sender.WebSocketMessageSender;
|
||||
import com.njcn.msgpush.module.system.api.websocket.dto.WebSocketSendToUsersReqDTO;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
@Hidden
|
||||
public class WebSocketSenderApiImpl implements WebSocketSenderApi {
|
||||
|
||||
private static final Integer SYSTEM_USER_TYPE = UserTypeEnum.ADMIN.getValue();
|
||||
|
||||
@Resource
|
||||
private WebSocketMessageSender webSocketMessageSender;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> sendToUsers(WebSocketSendToUsersReqDTO message) {
|
||||
if (CollUtil.isNotEmpty(message.getUserIds())) {
|
||||
message.getUserIds().stream().distinct().forEach(userId ->
|
||||
webSocketMessageSender.send(SYSTEM_USER_TYPE, userId,
|
||||
message.getMessageType(), message.getMessageContent()));
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.encrypt.core.annotation.ApiEncrypt;
|
||||
import com.njcn.msgpush.framework.security.config.SecurityProperties;
|
||||
import com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserRouteRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserInfoRespVO;
|
||||
import com.njcn.msgpush.module.system.convert.auth.AuthConvert;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.njcn.msgpush.module.system.enums.logger.LoginLogTypeEnum;
|
||||
import com.njcn.msgpush.module.system.service.auth.AdminAuthService;
|
||||
import com.njcn.msgpush.module.system.service.permission.MenuService;
|
||||
import com.njcn.msgpush.module.system.service.permission.PermissionService;
|
||||
import com.njcn.msgpush.module.system.service.permission.RoleService;
|
||||
import com.njcn.msgpush.module.system.service.user.AdminUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 认证")
|
||||
@RestController
|
||||
@RequestMapping("/system/auth")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private AdminAuthService authService;
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
@Resource
|
||||
private RoleService roleService;
|
||||
@Resource
|
||||
private MenuService menuService;
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
@PostMapping("/login")
|
||||
@PermitAll
|
||||
@Operation(summary = "使用账号密码登录")
|
||||
@ApiEncrypt(response = false, requestFields = {"password"})
|
||||
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
|
||||
return success(authService.login(reqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
@PermitAll
|
||||
@Operation(summary = "登出系统")
|
||||
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||
String token = SecurityFrameworkUtils.obtainAuthorization(request,
|
||||
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/refresh-token")
|
||||
@PermitAll
|
||||
@Operation(summary = "刷新令牌")
|
||||
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
|
||||
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
return success(authService.refreshToken(refreshToken));
|
||||
}
|
||||
|
||||
@GetMapping("/get-user-info")
|
||||
@Operation(summary = "获取登录用户信息")
|
||||
public CommonResult<AuthUserInfoRespVO> getUserInfo() {
|
||||
// 1.1 获得用户信息
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 1.2 获得角色和按钮权限
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convertUserInfo(user, roles, menuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-user-routes")
|
||||
@Operation(summary = "获取登录用户路由信息")
|
||||
public CommonResult<AuthUserRouteRespVO> getUserRoutes() {
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convertUserRoutes(menuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-permission-info")
|
||||
@Operation(summary = "获取登录用户的权限信息")
|
||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
if (CollUtil.isEmpty(roles)) {
|
||||
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
|
||||
}
|
||||
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
@PermitAll
|
||||
@Operation(summary = "注册用户")
|
||||
@ApiEncrypt(response = false, requestFields = {"password"})
|
||||
public CommonResult<AuthLoginRespVO> register(@RequestBody @Valid AuthRegisterReqVO registerReqVO) {
|
||||
return success(authService.register(registerReqVO));
|
||||
}
|
||||
|
||||
private List<RoleDO> getCurrentUserRoles() {
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
||||
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()));
|
||||
return roles;
|
||||
}
|
||||
|
||||
private List<MenuDO> getCurrentUserMenus(List<RoleDO> roles) {
|
||||
if (CollUtil.isEmpty(roles)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
||||
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
||||
return menuService.filterDisableMenus(menuList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
@Schema(description = "管理后台 - 账号密码登录 Request VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthLoginReqVO extends CaptchaVerificationReqVO {
|
||||
|
||||
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpushyuanma")
|
||||
@NotEmpty(message = "登录账号不能为空")
|
||||
@Length(min = 4, max = 30, message = "账号长度为 4-30 位")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "账号格式为数字以及字母")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
|
||||
@NotEmpty(message = "密码不能为空")
|
||||
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 登录 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthLoginRespVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy")
|
||||
private String accessToken;
|
||||
|
||||
@Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice")
|
||||
private String refreshToken;
|
||||
|
||||
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime expiresTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthMenuRespVO {
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
|
||||
private String component;
|
||||
|
||||
@Schema(description = "组件名", example = "SystemUser")
|
||||
private String componentName;
|
||||
|
||||
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean visible;
|
||||
|
||||
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean keepAlive;
|
||||
|
||||
@Schema(description = "是否总是显示", example = "false")
|
||||
private Boolean alwaysShow;
|
||||
|
||||
/**
|
||||
* 子路由
|
||||
*/
|
||||
private List<AuthMenuRespVO> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthPermissionInfoRespVO {
|
||||
|
||||
@Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private UserVO user;
|
||||
|
||||
@Schema(description = "角色标识数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Set<String> roles;
|
||||
|
||||
@Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Set<String> permissions;
|
||||
|
||||
@Schema(description = "菜单树", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<MenuVO> menus;
|
||||
|
||||
@Schema(description = "用户信息 VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class UserVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "用户邮箱", example = "msgpush@iocoder.cn")
|
||||
private String email;
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class MenuVO {
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
|
||||
private String component;
|
||||
|
||||
@Schema(description = "组件名", example = "SystemUser")
|
||||
private String componentName;
|
||||
|
||||
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean visible;
|
||||
|
||||
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean keepAlive;
|
||||
|
||||
@Schema(description = "是否总是显示", example = "false")
|
||||
private Boolean alwaysShow;
|
||||
|
||||
/**
|
||||
* 子路由
|
||||
*/
|
||||
private List<MenuVO> children;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
@Schema(description = "管理后台 - 注册 Request VO")
|
||||
@Data
|
||||
public class AuthRegisterReqVO extends CaptchaVerificationReqVO {
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
|
||||
@NotBlank(message = "用户账号不能为空")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由数字、字母组成")
|
||||
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "awen")
|
||||
@NotBlank(message = "用户昵称不能为空")
|
||||
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "所属部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "所属部门不能为空")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "主岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "主岗位不能为空")
|
||||
private Long positionId;
|
||||
|
||||
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||
@NotEmpty(message = "密码不能为空")
|
||||
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由 Meta Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthRouteMetaRespVO {
|
||||
|
||||
@Schema(description = "菜单或页面标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String title;
|
||||
|
||||
@Schema(description = "国际化 key")
|
||||
private String i18nKey;
|
||||
|
||||
@Schema(description = "图标名")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "本地图标名")
|
||||
private String localIcon;
|
||||
|
||||
@Schema(description = "排序值")
|
||||
private Integer order;
|
||||
|
||||
@Schema(description = "是否缓存")
|
||||
private Boolean keepAlive;
|
||||
|
||||
@Schema(description = "是否在菜单中隐藏")
|
||||
private Boolean hideInMenu;
|
||||
|
||||
@Schema(description = "当前页面高亮的菜单路由名")
|
||||
private String activeMenu;
|
||||
|
||||
@Schema(description = "是否支持多标签页")
|
||||
private Boolean multiTab;
|
||||
|
||||
@Schema(description = "标签页固定位置")
|
||||
private Integer fixedIndexInTab;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由节点 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthRouteNodeRespVO {
|
||||
|
||||
@Schema(description = "路由节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "完整路由路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "/system/user")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "前端组件白名单 key", example = "view.system_user")
|
||||
private String component;
|
||||
|
||||
@Schema(description = "重定向路径")
|
||||
private String redirect;
|
||||
|
||||
@Schema(description = "路由 props")
|
||||
private Object props;
|
||||
|
||||
@Schema(description = "路由 meta", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private AuthRouteMetaRespVO meta;
|
||||
|
||||
@Schema(description = "子路由列表")
|
||||
private List<AuthRouteNodeRespVO> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthUserInfoRespVO {
|
||||
|
||||
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "角色编码列表", example = "[\"SUPER_ADMIN\"]")
|
||||
private List<String> roles;
|
||||
|
||||
@Schema(description = "按钮权限码列表", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "[\"system:user:add\", \"system:user:update\"]")
|
||||
private List<String> buttons;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthUserRouteRespVO {
|
||||
|
||||
@Schema(description = "用户可访问路由树", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<AuthRouteNodeRespVO> routes;
|
||||
|
||||
@Schema(description = "默认首页路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
|
||||
private String home;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 验证码 Request VO")
|
||||
@Data
|
||||
public class CaptchaVerificationReqVO {
|
||||
|
||||
// ========== 图片验证码相关 ==========
|
||||
@Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==")
|
||||
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
|
||||
private String captchaVerification;
|
||||
|
||||
/**
|
||||
* 开启验证码的 Group
|
||||
*/
|
||||
public interface CodeEnableGroup {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.captcha;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
|
||||
import com.anji.captcha.model.common.ResponseModel;
|
||||
import com.anji.captcha.model.vo.CaptchaVO;
|
||||
import com.anji.captcha.service.CaptchaService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "管理后台 - 验证码")
|
||||
@RestController("adminCaptchaController")
|
||||
@RequestMapping("/system/captcha")
|
||||
public class CaptchaController {
|
||||
|
||||
@Resource
|
||||
private CaptchaService captchaService;
|
||||
|
||||
@PostMapping({"/get"})
|
||||
@Operation(summary = "获得验证码")
|
||||
@PermitAll
|
||||
|
||||
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
|
||||
assert request.getRemoteHost() != null;
|
||||
data.setBrowserInfo(getRemoteId(request));
|
||||
return captchaService.get(data);
|
||||
}
|
||||
|
||||
@PostMapping("/check")
|
||||
@Operation(summary = "校验验证码")
|
||||
@PermitAll
|
||||
|
||||
public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
|
||||
data.setBrowserInfo(getRemoteId(request));
|
||||
return captchaService.check(data);
|
||||
}
|
||||
|
||||
public static String getRemoteId(HttpServletRequest request) {
|
||||
String ip = ServletUtils.getClientIP(request);
|
||||
String ua = request.getHeader("user-agent");
|
||||
if (StrUtil.isNotBlank(ip)) {
|
||||
return ip + ua;
|
||||
}
|
||||
return request.getRemoteAddr() + ua;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.config;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.config.vo.ConfigSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.convert.config.ConfigConvert;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.config.ConfigDO;
|
||||
import com.njcn.msgpush.module.system.enums.ErrorCodeConstants;
|
||||
import com.njcn.msgpush.module.system.service.config.ConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 参数配置")
|
||||
@RestController
|
||||
@RequestMapping("/system/config")
|
||||
@Validated
|
||||
public class ConfigController {
|
||||
|
||||
@Resource
|
||||
private ConfigService configService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:create')")
|
||||
public CommonResult<Long> createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) {
|
||||
return success(configService.createConfig(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:update')")
|
||||
public CommonResult<Boolean> updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) {
|
||||
configService.updateConfig(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除参数配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:delete')")
|
||||
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
|
||||
configService.deleteConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除参数配置")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:config:delete')")
|
||||
public CommonResult<Boolean> deleteConfigList(@RequestParam("ids") List<Long> ids) {
|
||||
configService.deleteConfigList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get")
|
||||
@Operation(summary = "获得参数配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:query')")
|
||||
public CommonResult<ConfigRespVO> getConfig(@RequestParam("id") Long id) {
|
||||
return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get-value-by-key")
|
||||
@Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端")
|
||||
@Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username")
|
||||
public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
|
||||
ConfigDO config = configService.getConfigByKey(key);
|
||||
if (config == null) {
|
||||
return success(null);
|
||||
}
|
||||
if (!config.getVisible()) {
|
||||
throw exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE);
|
||||
}
|
||||
return success(config.getValue());
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获取参数配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:query')")
|
||||
public CommonResult<PageResult<ConfigRespVO>> getConfigPage(@Valid ConfigPageReqVO pageReqVO) {
|
||||
PageResult<ConfigDO> page = configService.getConfigPage(pageReqVO);
|
||||
return success(ConfigConvert.INSTANCE.convertPage(page));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('system:config:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportConfig(ConfigPageReqVO exportReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<ConfigDO> list = configService.getConfigPage(exportReqVO).getList();
|
||||
// 输出
|
||||
ExcelUtils.write(response, "参数配置.xls", "数据", ConfigRespVO.class,
|
||||
ConfigConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.config.vo;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 参数配置分页 Request VO")
|
||||
@Data
|
||||
public class ConfigPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "数据源名称,模糊匹配", example = "名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "参数键名,模糊匹配", example = "yunai.db.username")
|
||||
private String key;
|
||||
|
||||
@Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.config.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 参数配置信息 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ConfigRespVO {
|
||||
|
||||
@Schema(description = "参数配置序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("参数配置序号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "参数分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz")
|
||||
@ExcelProperty("参数分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名")
|
||||
@ExcelProperty("参数名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username")
|
||||
@ExcelProperty("参数键名")
|
||||
private String key;
|
||||
|
||||
@Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("参数键值")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "参数类型", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.CONFIG_TYPE)
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@ExcelProperty(value = "是否可见", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.BOOLEAN_STRING)
|
||||
private Boolean visible;
|
||||
|
||||
@Schema(description = "备注", example = "备注一下很帅气!")
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.config.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 参数配置创建/修改 Request VO")
|
||||
@Data
|
||||
public class ConfigSaveReqVO {
|
||||
|
||||
@Schema(description = "参数配置序号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "参数分组", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz")
|
||||
@NotEmpty(message = "参数分组不能为空")
|
||||
@Size(max = 50, message = "参数名称不能超过 50 个字符")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名")
|
||||
@NotBlank(message = "参数名称不能为空")
|
||||
@Size(max = 100, message = "参数名称不能超过 100 个字符")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username")
|
||||
@NotBlank(message = "参数键名长度不能为空")
|
||||
@Size(max = 100, message = "参数键名长度不能超过 100 个字符")
|
||||
private String key;
|
||||
|
||||
@Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotBlank(message = "参数键值不能为空")
|
||||
@Size(max = 500, message = "参数键值长度不能超过 500 个字符")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "是否可见不能为空")
|
||||
private Boolean visible;
|
||||
|
||||
@Schema(description = "备注", example = "备注一下很帅气!")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.dept.DeptRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.DeptService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 部门")
|
||||
@RestController
|
||||
@RequestMapping("/system/dept")
|
||||
@Validated
|
||||
public class DeptController {
|
||||
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
|
||||
@PostMapping("create")
|
||||
@Operation(summary = "创建部门")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:create')")
|
||||
public CommonResult<Long> createDept(@Valid @RequestBody DeptSaveReqVO createReqVO) {
|
||||
Long deptId = deptService.createDept(createReqVO);
|
||||
return success(deptId);
|
||||
}
|
||||
|
||||
@PutMapping("update")
|
||||
@Operation(summary = "更新部门")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:update')")
|
||||
public CommonResult<Boolean> updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) {
|
||||
deptService.updateDept(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("delete")
|
||||
@Operation(summary = "删除部门")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
|
||||
public CommonResult<Boolean> deleteDept(@RequestParam("id") Long id) {
|
||||
deptService.deleteDept(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除部门")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
|
||||
public CommonResult<Boolean> deleteDeptList(@RequestParam("ids") List<Long> ids) {
|
||||
deptService.deleteDeptList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取部门列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
public CommonResult<List<DeptRespVO>> getDeptList(DeptListReqVO reqVO) {
|
||||
List<DeptDO> list = deptService.getDeptList(reqVO);
|
||||
return success(BeanUtils.toBean(list, DeptRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/list-all-simple", "/simple-list"})
|
||||
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
|
||||
public CommonResult<List<DeptSimpleRespVO>> getSimpleDeptList() {
|
||||
List<DeptDO> list = deptService.getDeptList(
|
||||
new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得部门信息")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
public CommonResult<DeptRespVO> getDept(@RequestParam("id") Long id) {
|
||||
DeptDO dept = deptService.getDept(id);
|
||||
return success(BeanUtils.toBean(dept, DeptRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader.OrgLeaderRelationRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader.OrgLeaderRelationSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
|
||||
import com.njcn.msgpush.module.system.convert.user.UserConvert;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.OrgLeaderRelationDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.DeptService;
|
||||
import com.njcn.msgpush.module.system.service.dept.OrgLeaderRelationService;
|
||||
import com.njcn.msgpush.module.system.service.user.AdminUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - 组织负责人关系")
|
||||
@RestController
|
||||
@RequestMapping("/system/org-leader")
|
||||
@Validated
|
||||
public class OrgLeaderRelationController {
|
||||
|
||||
@Resource
|
||||
private OrgLeaderRelationService orgLeaderRelationService;
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
@Resource
|
||||
private AdminUserService adminUserService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建组织负责人关系")
|
||||
@PreAuthorize("@ss.hasPermission('system:org-leader:create')")
|
||||
public CommonResult<Long> createOrgLeaderRelation(@Valid @RequestBody OrgLeaderRelationSaveReqVO createReqVO) {
|
||||
return success(orgLeaderRelationService.createOrgLeaderRelation(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改组织负责人关系")
|
||||
@PreAuthorize("@ss.hasPermission('system:org-leader:update')")
|
||||
public CommonResult<Boolean> updateOrgLeaderRelation(@Valid @RequestBody OrgLeaderRelationSaveReqVO updateReqVO) {
|
||||
orgLeaderRelationService.updateOrgLeaderRelation(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除组织负责人关系")
|
||||
@Parameter(name = "id", description = "负责人关系编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:org-leader:delete')")
|
||||
public CommonResult<Boolean> deleteOrgLeaderRelation(@RequestParam("id") Long id) {
|
||||
orgLeaderRelationService.deleteOrgLeaderRelation(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-dept")
|
||||
@Operation(summary = "查询组织下的负责人关系列表")
|
||||
@Parameter(name = "deptId", description = "组织节点 ID", required = true, example = "100")
|
||||
@PreAuthorize("@ss.hasPermission('system:org-leader:query')")
|
||||
public CommonResult<List<OrgLeaderRelationRespVO>> getOrgLeaderRelationListByDept(@RequestParam("deptId") Long deptId) {
|
||||
List<OrgLeaderRelationDO> relations = orgLeaderRelationService.getOrgLeaderRelationListByDeptId(deptId);
|
||||
List<OrgLeaderRelationRespVO> respList = BeanUtils.toBean(relations, OrgLeaderRelationRespVO.class);
|
||||
Map<Long, AdminUserDO> userMap = adminUserService.getUserMap(convertList(relations, OrgLeaderRelationDO::getUserId));
|
||||
respList.forEach(respVO -> {
|
||||
AdminUserDO user = userMap.get(respVO.getUserId());
|
||||
if (user != null) {
|
||||
respVO.setUserNickname(user.getNickname());
|
||||
}
|
||||
});
|
||||
return success(respList);
|
||||
}
|
||||
|
||||
@GetMapping("/candidate-users")
|
||||
@Operation(summary = "查询组织负责人候选用户列表")
|
||||
@Parameter(name = "deptId", description = "组织节点 ID", required = true, example = "100")
|
||||
@PreAuthorize("@ss.hasPermission('system:org-leader:query')")
|
||||
public CommonResult<List<UserSimpleRespVO>> getCandidateUsers(@RequestParam("deptId") Long deptId) {
|
||||
List<AdminUserDO> users = orgLeaderRelationService.getCandidateUsersByDeptId(deptId);
|
||||
Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(users, AdminUserDO::getDeptId));
|
||||
return success(UserConvert.INSTANCE.convertSimpleList(users, deptMap));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.post.PostPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.post.PostRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dept.vo.post.PostSimpleRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.PostDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.PostService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 岗位")
|
||||
@RestController
|
||||
@RequestMapping("/system/post")
|
||||
@Validated
|
||||
public class PostController {
|
||||
|
||||
@Resource
|
||||
private PostService postService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建岗位")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:create')")
|
||||
public CommonResult<Long> createPost(@Valid @RequestBody PostSaveReqVO createReqVO) {
|
||||
Long postId = postService.createPost(createReqVO);
|
||||
return success(postId);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改岗位")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:update')")
|
||||
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
|
||||
postService.updatePost(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除岗位")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:delete')")
|
||||
public CommonResult<Boolean> deletePost(@RequestParam("id") Long id) {
|
||||
postService.deletePost(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("delete-list")
|
||||
@Operation(summary = "批量删除岗位")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:delete')")
|
||||
public CommonResult<Boolean> deletePostList(@RequestParam("ids") List<Long> ids) {
|
||||
postService.deletePostList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get")
|
||||
@Operation(summary = "获得岗位信息")
|
||||
@Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:query')")
|
||||
public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
|
||||
PostDO post = postService.getPost(id);
|
||||
return success(BeanUtils.toBean(post, PostRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/list-all-simple", "simple-list"})
|
||||
@Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
|
||||
public CommonResult<List<PostSimpleRespVO>> getSimplePostList() {
|
||||
// 获得岗位列表,只要开启状态的
|
||||
List<PostDO> list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
|
||||
// 排序后,返回给前端
|
||||
list.sort(Comparator.comparing(PostDO::getSort));
|
||||
return success(BeanUtils.toBean(list, PostSimpleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得岗位分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:query')")
|
||||
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
|
||||
PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, PostRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "岗位管理")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException {
|
||||
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<PostDO> list = postService.getPostPage(reqVO).getList();
|
||||
// 输出
|
||||
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class,
|
||||
BeanUtils.toBean(list, PostRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.dept;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 部门列表 Request VO")
|
||||
@Data
|
||||
public class DeptListReqVO {
|
||||
|
||||
@Schema(description = "部门名称,模糊匹配", example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "组织节点类型", example = "dept")
|
||||
private String orgType;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.dept;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 部门信息 Response VO")
|
||||
@Data
|
||||
public class DeptRespVO {
|
||||
|
||||
@Schema(description = "部门编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发中心")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父部门 ID", example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "组织节点类型", example = "dept")
|
||||
private String orgType;
|
||||
|
||||
@Schema(description = "组织物化路径", example = "/100/101/103/")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "组织层级", example = "3")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "组织编码", example = "RD_CENTER")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.dept;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 部门创建/修改 Request VO")
|
||||
@Data
|
||||
public class DeptSaveReqVO {
|
||||
|
||||
@Schema(description = "部门编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发中心")
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
@Size(max = 30, message = "部门名称长度不能超过 30 个字符")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父部门 ID", example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "组织节点类型", example = "dept")
|
||||
@Size(max = 20, message = "组织节点类型长度不能超过 20 个字符")
|
||||
private String orgType;
|
||||
|
||||
@Schema(description = "组织编码", example = "RD_CENTER")
|
||||
@Size(max = 64, message = "组织编码长度不能超过 64 个字符")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.dept;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 部门精简信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeptSimpleRespVO {
|
||||
|
||||
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "组织节点类型", example = "dept")
|
||||
private String orgType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 组织负责人关系 Response VO")
|
||||
@Data
|
||||
public class OrgLeaderRelationRespVO {
|
||||
|
||||
@Schema(description = "负责人关系编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "组织节点 ID", example = "100")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "负责人用户 ID", example = "1")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "负责人用户昵称", example = "管理员")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "生效开始时间")
|
||||
private LocalDateTime effectiveFrom;
|
||||
|
||||
@Schema(description = "生效结束时间")
|
||||
private LocalDateTime effectiveUntil;
|
||||
|
||||
@Schema(description = "备注", example = "部门负责人")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.orgleader;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 组织负责人关系创建/修改 Request VO")
|
||||
@Data
|
||||
public class OrgLeaderRelationSaveReqVO {
|
||||
|
||||
@Schema(description = "负责人关系编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "组织节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "组织节点不能为空")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "负责人用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "负责人用户不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "生效开始时间")
|
||||
private LocalDateTime effectiveFrom;
|
||||
|
||||
@Schema(description = "生效结束时间")
|
||||
private LocalDateTime effectiveUntil;
|
||||
|
||||
@Schema(description = "备注", example = "部门负责人")
|
||||
@Size(max = 500, message = "备注长度不能超过 500 个字符")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - 岗位分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PostPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "岗位编码,模糊匹配", example = "msgpush")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "岗位名称,模糊匹配", example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "岗位类型", example = "technical")
|
||||
private String postType;
|
||||
|
||||
@Schema(description = "岗位级别", example = "8")
|
||||
private Integer levelRank;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 岗位信息 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class PostRespVO {
|
||||
|
||||
@Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("岗位序号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "后端开发工程师")
|
||||
@ExcelProperty("岗位名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "backend")
|
||||
@ExcelProperty("岗位编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "岗位类型", example = "technical")
|
||||
@ExcelProperty("岗位类型")
|
||||
private String postType;
|
||||
|
||||
@Schema(description = "岗位级别", example = "8")
|
||||
@ExcelProperty("岗位级别")
|
||||
private Integer levelRank;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty("岗位排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "状态", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "技术序列岗位")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 岗位创建/修改 Request VO")
|
||||
@Data
|
||||
public class PostSaveReqVO {
|
||||
|
||||
@Schema(description = "岗位编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "后端开发工程师")
|
||||
@NotBlank(message = "岗位名称不能为空")
|
||||
@Size(max = 50, message = "岗位名称长度不能超过 50 个字符")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "backend")
|
||||
@NotBlank(message = "岗位编码不能为空")
|
||||
@Size(max = 64, message = "岗位编码长度不能超过 64 个字符")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "岗位类型", example = "technical")
|
||||
@Size(max = 20, message = "岗位类型长度不能超过 20 个字符")
|
||||
private String postType;
|
||||
|
||||
@Schema(description = "岗位级别", example = "8")
|
||||
@Min(value = 0, message = "岗位级别不能小于 0")
|
||||
private Integer levelRank;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "技术序列岗位")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dept.vo.post;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 岗位信息的精简 Response VO")
|
||||
@Data
|
||||
public class PostSimpleRespVO {
|
||||
|
||||
@Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("岗位序号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
|
||||
@ExcelProperty("岗位名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "岗位编码", example = "backend")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "岗位类型", example = "technical")
|
||||
private String postType;
|
||||
|
||||
@Schema(description = "岗位级别", example = "8")
|
||||
private Integer levelRank;
|
||||
|
||||
@Schema(description = "岗位排序", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.data.DictDataRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dict.DictDataDO;
|
||||
import com.njcn.msgpush.module.system.service.dict.DictDataService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 字典数据")
|
||||
@RestController
|
||||
@RequestMapping("/system/dict-data")
|
||||
@Validated
|
||||
public class DictDataController {
|
||||
|
||||
@Resource
|
||||
private DictDataService dictDataService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增字典数据")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:create')")
|
||||
public CommonResult<Long> createDictData(@Valid @RequestBody DictDataSaveReqVO createReqVO) {
|
||||
Long dictDataId = dictDataService.createDictData(createReqVO);
|
||||
return success(dictDataId);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改字典数据")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:update')")
|
||||
public CommonResult<Boolean> updateDictData(@Valid @RequestBody DictDataSaveReqVO updateReqVO) {
|
||||
dictDataService.updateDictData(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除字典数据")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
|
||||
public CommonResult<Boolean> deleteDictData(@RequestParam("id") Long id) {
|
||||
dictDataService.deleteDictData(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除字典数据")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
|
||||
public CommonResult<Boolean> deleteDictDataList(@RequestParam("ids") List<Long> ids) {
|
||||
dictDataService.deleteDictDataList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/list-all-simple", "simple-list"})
|
||||
@Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地")
|
||||
// 无需添加权限认证,因为前端全局都需要
|
||||
public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() {
|
||||
List<DictDataDO> list = dictDataService.getDictDataList(
|
||||
CommonStatusEnum.ENABLE.getStatus(), null);
|
||||
return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得字典类型的分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:query')")
|
||||
public CommonResult<PageResult<DictDataRespVO>> getDictTypePage(@Valid DictDataPageReqVO pageReqVO) {
|
||||
PageResult<DictDataDO> pageResult = dictDataService.getDictDataPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, DictDataRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get")
|
||||
@Operation(summary = "/查询字典数据详细")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:query')")
|
||||
public CommonResult<DictDataRespVO> getDictData(@RequestParam("id") Long id) {
|
||||
DictDataDO dictData = dictDataService.getDictData(id);
|
||||
return success(BeanUtils.toBean(dictData, DictDataRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出字典数据")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void export(HttpServletResponse response, @Valid DictDataPageReqVO exportReqVO) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<DictDataDO> list = dictDataService.getDictDataPage(exportReqVO).getList();
|
||||
// 输出
|
||||
ExcelUtils.write(response, "字典数据.xls", "数据", DictDataRespVO.class,
|
||||
BeanUtils.toBean(list, DictDataRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.type.DictTypePageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.type.DictTypeRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dict.DictTypeDO;
|
||||
import com.njcn.msgpush.module.system.service.dict.DictTypeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 字典类型")
|
||||
@RestController
|
||||
@RequestMapping("/system/dict-type")
|
||||
@Validated
|
||||
public class DictTypeController {
|
||||
|
||||
@Resource
|
||||
private DictTypeService dictTypeService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建字典类型")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:create')")
|
||||
public CommonResult<Long> createDictType(@Valid @RequestBody DictTypeSaveReqVO createReqVO) {
|
||||
Long dictTypeId = dictTypeService.createDictType(createReqVO);
|
||||
return success(dictTypeId);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改字典类型")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:update')")
|
||||
public CommonResult<Boolean> updateDictType(@Valid @RequestBody DictTypeSaveReqVO updateReqVO) {
|
||||
dictTypeService.updateDictType(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除字典类型")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
|
||||
public CommonResult<Boolean> deleteDictType(Long id) {
|
||||
dictTypeService.deleteDictType(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除字典类型")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
|
||||
public CommonResult<Boolean> deleteDictTypeList(@RequestParam("ids") List<Long> ids) {
|
||||
dictTypeService.deleteDictTypeList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得字典类型的分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:query')")
|
||||
public CommonResult<PageResult<DictTypeRespVO>> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
PageResult<DictTypeDO> pageResult = dictTypeService.getDictTypePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "/查询字典类型详细")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@GetMapping(value = "/get")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:query')")
|
||||
public CommonResult<DictTypeRespVO> getDictType(@RequestParam("id") Long id) {
|
||||
DictTypeDO dictType = dictTypeService.getDictType(id);
|
||||
return success(BeanUtils.toBean(dictType, DictTypeRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/list-all-simple", "simple-list"})
|
||||
@Operation(summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
|
||||
// 无需添加权限认证,因为前端全局都需要
|
||||
public CommonResult<List<DictTypeSimpleRespVO>> getSimpleDictTypeList() {
|
||||
List<DictTypeDO> list = dictTypeService.getDictTypeList();
|
||||
return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "导出数据类型")
|
||||
@GetMapping("/export-excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:dict:query')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void export(HttpServletResponse response, @Valid DictTypePageReqVO exportReqVO) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<DictTypeDO> list = dictTypeService.getDictTypePage(exportReqVO).getList();
|
||||
// 导出
|
||||
ExcelUtils.write(response, "字典类型.xls", "数据", DictTypeRespVO.class,
|
||||
BeanUtils.toBean(list, DictTypeRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.data;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - 字典类型分页列表 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DictDataPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "字典标签", example = "灿能")
|
||||
@Size(max = 100, message = "字典标签长度不能超过100个字符")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "字典类型,模糊匹配", example = "sys_common_sex")
|
||||
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
|
||||
private String dictType;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.data;
|
||||
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 字典数据信息 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class DictDataRespVO {
|
||||
|
||||
@Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("字典编码")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("字典排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
@ExcelProperty("字典标签")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
|
||||
@ExcelProperty("字典键值")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
@ExcelProperty("字典类型")
|
||||
private String dictType;
|
||||
|
||||
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "状态", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default")
|
||||
private String colorType;
|
||||
|
||||
@Schema(description = "css 样式", example = "btn-visible")
|
||||
private String cssClass;
|
||||
|
||||
@Schema(description = "备注", example = "我是一个角色")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.data;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 字典数据创建/修改 Request VO")
|
||||
@Data
|
||||
public class DictDataSaveReqVO {
|
||||
|
||||
@Schema(description = "字典数据编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
@NotBlank(message = "字典标签不能为空")
|
||||
@Size(max = 100, message = "字典标签长度不能超过100个字符")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
|
||||
@NotBlank(message = "字典键值不能为空")
|
||||
@Size(max = 100, message = "字典键值长度不能超过100个字符")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
@NotBlank(message = "字典类型不能为空")
|
||||
@Size(max = 100, message = "字典类型长度不能超过100个字符")
|
||||
private String dictType;
|
||||
|
||||
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default")
|
||||
private String colorType;
|
||||
|
||||
@Schema(description = "css 样式", example = "btn-visible")
|
||||
private String cssClass;
|
||||
|
||||
@Schema(description = "备注", example = "我是一个角色")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 数据字典精简 Response VO")
|
||||
@Data
|
||||
public class DictDataSimpleRespVO {
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "gender")
|
||||
private String dictType;
|
||||
|
||||
@Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "男")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default")
|
||||
private String colorType;
|
||||
|
||||
@Schema(description = "css 样式", example = "btn-visible")
|
||||
private String cssClass;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.type;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 字典类型分页列表 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DictTypePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "字典类型名称,模糊匹配", example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型,模糊匹配", example = "sys_common_sex")
|
||||
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "字典类型编码,兼容前端 code 查询参数", example = "sys_common_sex")
|
||||
@Size(max = 100, message = "字典类型编码长度不能超过100个字符")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
public String getTypeKeyword() {
|
||||
return StringUtils.hasText(code) ? code : type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.type;
|
||||
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 字典类型信息 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class DictTypeRespVO {
|
||||
|
||||
@Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("字典主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别")
|
||||
@ExcelProperty("字典名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
@ExcelProperty("字典类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "状态", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "快乐的备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.type;
|
||||
|
||||
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.Size;
|
||||
|
||||
@Schema(description = "管理后台 - 字典类型创建/修改 Request VO")
|
||||
@Data
|
||||
public class DictTypeSaveReqVO {
|
||||
|
||||
@Schema(description = "字典类型编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别")
|
||||
@NotBlank(message = "字典名称不能为空")
|
||||
@Size(max = 100, message = "字典类型名称长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
@NotNull(message = "字典类型不能为空")
|
||||
@Size(max = 100, message = "字典类型类型长度不能超过 100 个字符")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "快乐的备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.dict.vo.type;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 字典类型精简信息 Response VO")
|
||||
@Data
|
||||
public class DictTypeSimpleRespVO {
|
||||
|
||||
@Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "字典类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
private String type;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.file.vo.config.FileConfigSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.file.FileConfigDO;
|
||||
import com.njcn.msgpush.module.system.service.file.FileConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 文件配置")
|
||||
@RestController
|
||||
@RequestMapping("/system/file-config")
|
||||
@Validated
|
||||
public class FileConfigController {
|
||||
|
||||
@Resource
|
||||
private FileConfigService fileConfigService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建文件配置")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:create')")
|
||||
public CommonResult<Long> createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) {
|
||||
return success(fileConfigService.createFileConfig(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新文件配置")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
|
||||
public CommonResult<Boolean> updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) {
|
||||
fileConfigService.updateFileConfig(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-master")
|
||||
@Operation(summary = "更新文件配置为 Master")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
|
||||
public CommonResult<Boolean> updateFileConfigMaster(@RequestParam("id") Long id) {
|
||||
fileConfigService.updateFileConfigMaster(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除文件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
|
||||
public CommonResult<Boolean> deleteFileConfig(@RequestParam("id") Long id) {
|
||||
fileConfigService.deleteFileConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除文件配置")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
|
||||
public CommonResult<Boolean> deleteFileConfigList(@RequestParam("ids") List<Long> ids) {
|
||||
fileConfigService.deleteFileConfigList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得文件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
|
||||
public CommonResult<FileConfigRespVO> getFileConfig(@RequestParam("id") Long id) {
|
||||
FileConfigDO config = fileConfigService.getFileConfig(id);
|
||||
return success(BeanUtils.toBean(config, FileConfigRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得文件配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
|
||||
public CommonResult<PageResult<FileConfigRespVO>> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) {
|
||||
PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
@Operation(summary = "测试文件配置是否正确")
|
||||
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
|
||||
public CommonResult<String> testFileConfig(@RequestParam("id") Long id) throws Exception {
|
||||
String url = fileConfigService.testFileConfig(id);
|
||||
return success(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.file.vo.file.*;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.file.FileDO;
|
||||
import com.njcn.msgpush.module.system.service.file.FileService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.module.system.framework.file.core.utils.FileTypeUtils.writeAttachment;
|
||||
|
||||
@Tag(name = "管理后台 - 文件存储")
|
||||
@RestController
|
||||
@RequestMapping("/system/file")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class FileController {
|
||||
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
|
||||
@PostMapping("/upload")
|
||||
@Operation(summary = "上传文件", description = "模式一:后端上传文件")
|
||||
@Parameter(name = "file", description = "文件附件", required = true,
|
||||
schema = @Schema(type = "string", format = "binary"))
|
||||
public CommonResult<String> uploadFile(@Valid FileUploadReqVO uploadReqVO) throws Exception {
|
||||
MultipartFile file = uploadReqVO.getFile();
|
||||
byte[] content = IoUtil.readBytes(file.getInputStream());
|
||||
return success(fileService.createFile(content, file.getOriginalFilename(),
|
||||
uploadReqVO.getDirectory(), file.getContentType()));
|
||||
}
|
||||
|
||||
@GetMapping("/presigned-url")
|
||||
@Operation(summary = "获取文件预签名地址(上传)", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器")
|
||||
@Parameters({
|
||||
@Parameter(name = "name", description = "文件名称", required = true),
|
||||
@Parameter(name = "directory", description = "文件目录")
|
||||
})
|
||||
public CommonResult<FilePresignedUrlRespVO> getFilePresignedUrl(
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value = "directory", required = false) String directory) {
|
||||
return success(fileService.presignPutUrl(name, directory));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件")
|
||||
public CommonResult<Long> createFile(@Valid @RequestBody FileCreateReqVO createReqVO) {
|
||||
return success(fileService.createFile(createReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得文件")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:file:query')")
|
||||
public CommonResult<FileRespVO> getFile(@RequestParam("id") Long id) {
|
||||
return success(BeanUtils.toBean(fileService.getFile(id), FileRespVO.class));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除文件")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:file:delete')")
|
||||
public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) throws Exception {
|
||||
fileService.deleteFile(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除文件")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:file:delete')")
|
||||
public CommonResult<Boolean> deleteFileList(@RequestParam("ids") List<Long> ids) throws Exception {
|
||||
fileService.deleteFileList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/{configId}/get/**")
|
||||
@PermitAll
|
||||
|
||||
@Operation(summary = "下载文件")
|
||||
@Parameter(name = "configId", description = "配置编号", required = true)
|
||||
public void getFileContent(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("configId") Long configId) throws Exception {
|
||||
// 获取请求的路径
|
||||
String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false);
|
||||
if (StrUtil.isEmpty(path)) {
|
||||
throw new IllegalArgumentException("结尾的 path 路径必须传递");
|
||||
}
|
||||
// 解码,解决中文路径的问题
|
||||
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
|
||||
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
|
||||
path = URLUtil.decode(path, StandardCharsets.UTF_8, false);
|
||||
|
||||
// 读取内容
|
||||
byte[] content = fileService.getFileContent(configId, path);
|
||||
if (content == null) {
|
||||
log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
writeAttachment(response, path, content);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得文件分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:file:query')")
|
||||
public CommonResult<PageResult<FileRespVO>> getFilePage(@Valid FilePageReqVO pageVO) {
|
||||
PageResult<FileDO> pageResult = fileService.getFilePage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, FileRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 文件配置分页 Request VO")
|
||||
@Data
|
||||
public class FileConfigPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "配置名", example = "S3 - 阿里云")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "存储器", example = "1")
|
||||
private Integer storage;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
|
||||
|
||||
import com.njcn.msgpush.module.system.framework.file.core.client.FileClientConfig;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 文件配置 Response VO")
|
||||
@Data
|
||||
public class FileConfigRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer storage;
|
||||
|
||||
@Schema(description = "是否为主配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean master;
|
||||
|
||||
@Schema(description = "存储配置", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private FileClientConfig config;
|
||||
|
||||
@Schema(description = "备注", example = "我是备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 文件配置创建/修改 Request VO")
|
||||
@Data
|
||||
public class FileConfigSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云")
|
||||
@NotNull(message = "配置名不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "存储器不能为空")
|
||||
private Integer storage;
|
||||
|
||||
@Schema(description = "存储配置,配置是动态参数,所以使用 Map 接收", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "存储配置不能为空")
|
||||
private Map<String, Object> config;
|
||||
|
||||
@Schema(description = "备注", example = "我是备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 文件创建 Request VO")
|
||||
@Data
|
||||
public class FileCreateReqVO {
|
||||
|
||||
@NotNull(message = "文件配置编号不能为空")
|
||||
@Schema(description = "文件配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
|
||||
private Long configId;
|
||||
|
||||
@NotNull(message = "文件路径不能为空")
|
||||
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush.jpg")
|
||||
private String path;
|
||||
|
||||
@NotNull(message = "原文件名不能为空")
|
||||
@Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush.jpg")
|
||||
private String name;
|
||||
|
||||
@NotNull(message = "文件 URL不能为空")
|
||||
@Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/msgpush.jpg")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "文件 MIME 类型", example = "application/octet-stream")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long size;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 文件分页 Request VO")
|
||||
@Data
|
||||
public class FilePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "文件路径,模糊匹配", example = "msgpush")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "文件类型,模糊匹配", example = "jpg")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "管理后台 - 文件预签名地址 Response VO")
|
||||
@Data
|
||||
public class FilePresignedUrlRespVO {
|
||||
|
||||
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "文件上传 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://s3.cn-south-1.qiniucs.com/ruoyi-vue-pro/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS%2F20240217%2Fcn-south-1%2Fs3%2Faws4_request&X-Amz-Date=20240217T123222Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=a29f33770ab79bf523ccd4034d0752ac545f3c2a3b17baa1eb4e280cfdccfda5")
|
||||
private String uploadUrl;
|
||||
|
||||
/**
|
||||
* 为什么要返回 url 字段?
|
||||
*
|
||||
* 前端上传完文件后,需要使用该 URL 进行访问
|
||||
*/
|
||||
@Schema(description = "文件访问 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://test.msgpush.iocoder.cn/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 为什么要返回 path 字段?
|
||||
*
|
||||
* 前端上传完文件后,需要调用 createFile 记录下 path 路径
|
||||
*/
|
||||
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx.png")
|
||||
private String path;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 文件 Response VO,不返回 content 字段,太大")
|
||||
@Data
|
||||
public class FileRespVO {
|
||||
|
||||
@Schema(description = "文件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush.jpg")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush.jpg")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/msgpush.jpg")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "文件MIME类型", example = "application/octet-stream")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.file.vo.file;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Schema(description = "管理后台 - 上传文件 Request VO")
|
||||
@Data
|
||||
public class FileUploadReqVO {
|
||||
|
||||
@Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "文件附件不能为空")
|
||||
private MultipartFile file;
|
||||
|
||||
@Schema(description = "文件目录", example = "XXX/YYY")
|
||||
private String directory;
|
||||
|
||||
@AssertTrue(message = "文件目录不正确")
|
||||
@JsonIgnore
|
||||
public boolean isDirectoryValid() {
|
||||
return isDirectoryValid(directory);
|
||||
}
|
||||
|
||||
public static boolean isDirectoryValid(String directory) {
|
||||
// 1. 不能包含 .. 防止目录穿越
|
||||
// 2. 不能以 / 或 \ 开头,防止上传到根目录
|
||||
return !StrUtil.contains(directory, "..")
|
||||
&& !StrUtil.startWithAny(directory, "/", "\\");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.ip;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.ip.core.Area;
|
||||
import com.njcn.msgpush.framework.ip.core.utils.AreaUtils;
|
||||
import com.njcn.msgpush.framework.ip.core.utils.IPUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.ip.vo.AreaNodeRespVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 地区")
|
||||
@RestController
|
||||
@RequestMapping("/system/area")
|
||||
@Validated
|
||||
public class AreaController {
|
||||
|
||||
@GetMapping("/tree")
|
||||
@Operation(summary = "获得地区树")
|
||||
public CommonResult<List<AreaNodeRespVO>> getAreaTree() {
|
||||
Area area = AreaUtils.getArea(Area.ID_CHINA);
|
||||
Assert.notNull(area, "获取不到中国");
|
||||
return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-by-ip")
|
||||
@Operation(summary = "获得 IP 对应的地区名")
|
||||
@Parameter(name = "ip", description = "IP", required = true)
|
||||
public CommonResult<String> getAreaByIp(@RequestParam("ip") String ip) {
|
||||
// 获得城市
|
||||
Area area = IPUtils.getArea(ip);
|
||||
if (area == null) {
|
||||
return success("未知");
|
||||
}
|
||||
// 格式化返回
|
||||
return success(AreaUtils.format(area.getId()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.ip.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 地区节点 Response VO")
|
||||
@Data
|
||||
public class AreaNodeRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000")
|
||||
private Integer id;
|
||||
|
||||
@Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 子节点
|
||||
*/
|
||||
private List<AreaNodeRespVO> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.logger.ApiAccessLogDO;
|
||||
import com.njcn.msgpush.module.system.service.logger.ApiAccessLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - API 访问日志")
|
||||
@RestController
|
||||
@RequestMapping("/system/api-access-log")
|
||||
@Validated
|
||||
public class ApiAccessLogController {
|
||||
|
||||
@Resource
|
||||
private ApiAccessLogService apiAccessLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 API 访问日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
|
||||
public CommonResult<ApiAccessLogRespVO> getApiAccessLog(@RequestParam("id") Long id) {
|
||||
ApiAccessLogDO apiAccessLog = apiAccessLogService.getApiAccessLog(id);
|
||||
return success(BeanUtils.toBean(apiAccessLog, ApiAccessLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得API 访问日志分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
|
||||
public CommonResult<PageResult<ApiAccessLogRespVO>> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) {
|
||||
PageResult<ApiAccessLogDO> pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出API 访问日志 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-access-log:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<ApiAccessLogDO> list = apiAccessLogService.getApiAccessLogPage(exportReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "API 访问日志.xls", "数据", ApiAccessLogRespVO.class,
|
||||
BeanUtils.toBean(list, ApiAccessLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.logger.ApiErrorLogDO;
|
||||
import com.njcn.msgpush.module.system.service.logger.ApiErrorLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - API 错误日志")
|
||||
@RestController
|
||||
@RequestMapping("/system/api-error-log")
|
||||
@Validated
|
||||
public class ApiErrorLogController {
|
||||
|
||||
@Resource
|
||||
private ApiErrorLogService apiErrorLogService;
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "更新 API 错误日志的状态")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024"),
|
||||
@Parameter(name = "processStatus", description = "处理状态", required = true, example = "1")
|
||||
})
|
||||
@PreAuthorize("@ss.hasPermission('system:api-error-log:update-status')")
|
||||
public CommonResult<Boolean> updateApiErrorLogProcess(@RequestParam("id") Long id,
|
||||
@RequestParam("processStatus") Integer processStatus) {
|
||||
apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 API 错误日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
|
||||
public CommonResult<ApiErrorLogRespVO> getApiErrorLog(@RequestParam("id") Long id) {
|
||||
ApiErrorLogDO apiErrorLog = apiErrorLogService.getApiErrorLog(id);
|
||||
return success(BeanUtils.toBean(apiErrorLog, ApiErrorLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 API 错误日志分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
|
||||
public CommonResult<PageResult<ApiErrorLogRespVO>> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) {
|
||||
PageResult<ApiErrorLogDO> pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出 API 错误日志 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:api-error-log:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<ApiErrorLogDO> list = apiErrorLogService.getApiErrorLogPage(exportReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "API 错误日志.xls", "数据", ApiErrorLogRespVO.class,
|
||||
BeanUtils.toBean(list, ApiErrorLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.loginlog.LoginLogRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.logger.LoginLogDO;
|
||||
import com.njcn.msgpush.module.system.service.logger.LoginLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 登录日志")
|
||||
@RestController
|
||||
@RequestMapping("/system/login-log")
|
||||
@Validated
|
||||
public class LoginLogController {
|
||||
|
||||
@Resource
|
||||
private LoginLogService loginLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得登录日志")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
public CommonResult<LoginLogRespVO> getLoginLog(Long id) {
|
||||
LoginLogDO loginLog = loginLogService.getLoginLog(id);
|
||||
return success(BeanUtils.toBean(loginLog, LoginLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得登录日志分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
public CommonResult<PageResult<LoginLogRespVO>> getLoginLogPage(@Valid LoginLogPageReqVO pageReqVO) {
|
||||
PageResult<LoginLogDO> pageResult = loginLogService.getLoginLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, LoginLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出登录日志 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportLoginLog(HttpServletResponse response, @Valid LoginLogPageReqVO exportReqVO) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<LoginLogDO> list = loginLogService.getLoginLogPage(exportReqVO).getList();
|
||||
// 输出
|
||||
ExcelUtils.write(response, "登录日志.xls", "数据列表", LoginLogRespVO.class,
|
||||
BeanUtils.toBean(list, LoginLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.framework.excel.core.util.ExcelUtils;
|
||||
import com.njcn.msgpush.framework.translate.core.TranslateUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.logger.OperateLogDO;
|
||||
import com.njcn.msgpush.module.system.service.logger.OperateLogService;
|
||||
import com.fhs.core.trans.anno.TransMethodResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 操作日志")
|
||||
@RestController
|
||||
@RequestMapping("/system/operate-log")
|
||||
@Validated
|
||||
public class OperateLogController {
|
||||
|
||||
@Resource
|
||||
private OperateLogService operateLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "查看操作日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
|
||||
public CommonResult<OperateLogRespVO> getOperateLog(@RequestParam("id") Long id) {
|
||||
OperateLogDO operateLog = operateLogService.getOperateLog(id);
|
||||
return success(BeanUtils.toBean(operateLog, OperateLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "查看操作日志分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
|
||||
@TransMethodResult
|
||||
public CommonResult<PageResult<OperateLogRespVO>> pageOperateLog(@Valid OperateLogPageReqVO pageReqVO) {
|
||||
PageResult<OperateLogDO> pageResult = operateLogService.getOperateLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, OperateLogRespVO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "导出操作日志")
|
||||
@GetMapping("/export-excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
|
||||
@TransMethodResult
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<OperateLogDO> list = operateLogService.getOperateLogPage(exportReqVO).getList();
|
||||
ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogRespVO.class,
|
||||
TranslateUtils.translate(BeanUtils.toBean(list, OperateLogRespVO.class)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - API 访问日志分页 Request VO")
|
||||
@Data
|
||||
public class ApiAccessLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "666")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", example = "2")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "应用名", example = "dashboard")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy")
|
||||
private String requestUrl;
|
||||
|
||||
@Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] beginTime;
|
||||
|
||||
@Schema(description = "执行时长,大于等于,单位:毫秒", example = "100")
|
||||
private Integer duration;
|
||||
|
||||
@Schema(description = "结果码", example = "0")
|
||||
private Integer resultCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apiaccesslog;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - API 访问日志 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApiAccessLogRespVO {
|
||||
|
||||
@Schema(description = "日志主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("日志主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002")
|
||||
@ExcelProperty("链路追踪编号")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
@ExcelProperty("用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty(value = "用户类型", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.USER_TYPE)
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard")
|
||||
@ExcelProperty("应用名")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
|
||||
@ExcelProperty("请求方法名")
|
||||
private String requestMethod;
|
||||
|
||||
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
|
||||
@ExcelProperty("请求地址")
|
||||
private String requestUrl;
|
||||
|
||||
@Schema(description = "请求参数")
|
||||
@ExcelProperty("请求参数")
|
||||
private String requestParams;
|
||||
|
||||
@Schema(description = "响应结果")
|
||||
@ExcelProperty("响应结果")
|
||||
private String responseBody;
|
||||
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
@ExcelProperty("用户 IP")
|
||||
private String userIp;
|
||||
|
||||
@Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
|
||||
@ExcelProperty("浏览器 UA")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "操作模块", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品模块")
|
||||
@ExcelProperty("操作模块")
|
||||
private String operateModule;
|
||||
|
||||
@Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建商品")
|
||||
@ExcelProperty("操作名")
|
||||
private String operateName;
|
||||
|
||||
@Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "操作分类", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.OPERATE_TYPE)
|
||||
private Integer operateType;
|
||||
|
||||
@Schema(description = "开始请求时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("开始请求时间")
|
||||
private LocalDateTime beginTime;
|
||||
|
||||
@Schema(description = "结束请求时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("结束请求时间")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Schema(description = "执行时长", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@ExcelProperty("执行时长")
|
||||
private Integer duration;
|
||||
|
||||
@Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@ExcelProperty("结果码")
|
||||
private Integer resultCode;
|
||||
|
||||
@Schema(description = "结果提示", example = "灿能,牛逼!")
|
||||
@ExcelProperty("结果提示")
|
||||
private String resultMsg;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - API 错误日志分页 Request VO")
|
||||
@Data
|
||||
public class ApiErrorLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "666")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", example = "1")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "应用名", example = "dashboard")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求地址", example = "/xx/yy")
|
||||
private String requestUrl;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "异常发生时间")
|
||||
private LocalDateTime[] exceptionTime;
|
||||
|
||||
@Schema(description = "处理状态", example = "0")
|
||||
private Integer processStatus;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.apierrorlog;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - API 错误日志 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApiErrorLogRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("编号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002")
|
||||
@ExcelProperty("链路追踪编号")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
@ExcelProperty("用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "用户类型", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.USER_TYPE)
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard")
|
||||
@ExcelProperty("应用名")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
|
||||
@ExcelProperty("请求方法名")
|
||||
private String requestMethod;
|
||||
|
||||
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xx/yy")
|
||||
@ExcelProperty("请求地址")
|
||||
private String requestUrl;
|
||||
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("请求参数")
|
||||
private String requestParams;
|
||||
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
@ExcelProperty("用户 IP")
|
||||
private String userIp;
|
||||
|
||||
@Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
|
||||
@ExcelProperty("浏览器 UA")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "异常发生时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常发生时间")
|
||||
private LocalDateTime exceptionTime;
|
||||
|
||||
@Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常名")
|
||||
private String exceptionName;
|
||||
|
||||
@Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常导致的消息")
|
||||
private String exceptionMessage;
|
||||
|
||||
@Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常导致的根消息")
|
||||
private String exceptionRootCauseMessage;
|
||||
|
||||
@Schema(description = "异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常的栈轨迹")
|
||||
private String exceptionStackTrace;
|
||||
|
||||
@Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常发生的类全名")
|
||||
private String exceptionClassName;
|
||||
|
||||
@Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常发生的类文件")
|
||||
private String exceptionFileName;
|
||||
|
||||
@Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常发生的方法名")
|
||||
private String exceptionMethodName;
|
||||
|
||||
@Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("异常发生的方法所在行")
|
||||
private Integer exceptionLineNumber;
|
||||
|
||||
@Schema(description = "处理状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@ExcelProperty(value = "处理状态", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.API_ERROR_LOG_PROCESS_STATUS)
|
||||
private Integer processStatus;
|
||||
|
||||
@Schema(description = "处理时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("处理时间")
|
||||
private LocalDateTime processTime;
|
||||
|
||||
@Schema(description = "处理用户编号", example = "233")
|
||||
@ExcelProperty("处理用户编号")
|
||||
private Integer processUserId;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.loginlog;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 登录日志分页列表 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LoginLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户 IP,模拟匹配", example = "127.0.0.1")
|
||||
private String userIp;
|
||||
|
||||
@Schema(description = "用户账号,模拟匹配", example = "灿能")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "操作状态", example = "true")
|
||||
private Boolean status;
|
||||
|
||||
@Schema(description = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.loginlog;
|
||||
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.framework.excel.core.convert.DictConvert;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 登录日志 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class LoginLogRespVO {
|
||||
|
||||
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("日志主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "日志类型,参见 LoginLogTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "日志类型", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.LOGIN_TYPE)
|
||||
private Integer logType;
|
||||
|
||||
@Schema(description = "用户编号", example = "666")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "msgpush")
|
||||
@ExcelProperty("用户账号")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "登录结果", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.LOGIN_RESULT)
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
@ExcelProperty("登录 IP")
|
||||
private String userIp;
|
||||
|
||||
@Schema(description = "浏览器 UserAgent", example = "Mozilla/5.0")
|
||||
@ExcelProperty("浏览器 UA")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "登录时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("登录时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.operatelog;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 操作日志分页列表 Request VO")
|
||||
@Data
|
||||
public class OperateLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "灿能")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "操作模块业务编号", example = "1")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "操作模块,模拟匹配", example = "订单")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "操作名,模拟匹配", example = "创建订单")
|
||||
private String subType;
|
||||
|
||||
@Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息")
|
||||
private String action;
|
||||
|
||||
@Schema(description = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.logger.vo.operatelog;
|
||||
|
||||
import com.njcn.msgpush.framework.excel.core.annotations.DictFormat;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.njcn.msgpush.module.system.enums.DictTypeConstants;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 操作日志 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class OperateLogRespVO implements VO {
|
||||
|
||||
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@ExcelProperty("日志编号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@Trans(type = TransType.SIMPLE, target = AdminUserDO.class, fields = "nickname", ref = "userName")
|
||||
private Long userId;
|
||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "awen")
|
||||
@ExcelProperty("操作人")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1", implementation = Integer.class)
|
||||
@ExcelProperty("用户类型")
|
||||
@DictFormat(DictTypeConstants.USER_TYPE)
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单")
|
||||
@ExcelProperty("操作模块类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单")
|
||||
@ExcelProperty("操作名")
|
||||
private String subType;
|
||||
|
||||
@Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty("操作模块业务编号")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从灿能改成源码。")
|
||||
private String action;
|
||||
|
||||
@Schema(description = "拓展字段", example = "{'orderId': 1}")
|
||||
private String extra;
|
||||
|
||||
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
|
||||
@NotEmpty(message = "请求方法名不能为空")
|
||||
private String requestMethod;
|
||||
|
||||
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
|
||||
private String requestUrl;
|
||||
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
private String userIp;
|
||||
|
||||
@Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notice;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notice.vo.NoticePageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notice.vo.NoticeRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notice.vo.NoticeSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.notice.NoticeDO;
|
||||
import com.njcn.msgpush.module.system.service.notice.NoticeService;
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.websocket.core.sender.WebSocketMessageSender;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 通知公告")
|
||||
@RestController
|
||||
@RequestMapping("/system/notice")
|
||||
@Validated
|
||||
public class NoticeController {
|
||||
|
||||
@Resource
|
||||
private NoticeService noticeService;
|
||||
|
||||
@Resource
|
||||
private WebSocketMessageSender webSocketMessageSender;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建通知公告")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:create')")
|
||||
public CommonResult<Long> createNotice(@Valid @RequestBody NoticeSaveReqVO createReqVO) {
|
||||
Long noticeId = noticeService.createNotice(createReqVO);
|
||||
return success(noticeId);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改通知公告")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:update')")
|
||||
public CommonResult<Boolean> updateNotice(@Valid @RequestBody NoticeSaveReqVO updateReqVO) {
|
||||
noticeService.updateNotice(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除通知公告")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:delete')")
|
||||
public CommonResult<Boolean> deleteNotice(@RequestParam("id") Long id) {
|
||||
noticeService.deleteNotice(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除通知公告")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:delete')")
|
||||
public CommonResult<Boolean> deleteNoticeList(@RequestParam("ids") List<Long> ids) {
|
||||
noticeService.deleteNoticeList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获取通知公告列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:query')")
|
||||
public CommonResult<PageResult<NoticeRespVO>> getNoticePage(@Validated NoticePageReqVO pageReqVO) {
|
||||
PageResult<NoticeDO> pageResult = noticeService.getNoticePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, NoticeRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得通知公告")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:query')")
|
||||
public CommonResult<NoticeRespVO> getNotice(@RequestParam("id") Long id) {
|
||||
NoticeDO notice = noticeService.getNotice(id);
|
||||
return success(BeanUtils.toBean(notice, NoticeRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/push")
|
||||
@Operation(summary = "推送通知公告", description = "只发送给 websocket 连接在线的用户")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:notice:update')")
|
||||
public CommonResult<Boolean> push(@RequestParam("id") Long id) {
|
||||
NoticeDO notice = noticeService.getNotice(id);
|
||||
Assert.notNull(notice, "公告不能为空");
|
||||
// 通过 websocket 推送给在线的用户
|
||||
webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), "notice-push", notice);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notice.vo;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - 通知公告分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NoticePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "通知公告名称,模糊匹配", example = "灿能")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notice.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 通知公告信息 Response VO")
|
||||
@Data
|
||||
public class NoticeRespVO {
|
||||
|
||||
@Schema(description = "通知公告序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notice.vo;
|
||||
|
||||
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.Size;
|
||||
|
||||
@Schema(description = "管理后台 - 通知公告创建/修改 Request VO")
|
||||
@Data
|
||||
public class NoticeSaveReqVO {
|
||||
|
||||
@Schema(description = "岗位公告编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
|
||||
@NotBlank(message = "公告标题不能为空")
|
||||
@Size(max = 50, message = "公告标题不能超过50个字符")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
|
||||
@NotNull(message = "公告类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.notify.NotifyMessageDO;
|
||||
import com.njcn.msgpush.module.system.service.notify.NotifyMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 我的站内信")
|
||||
@RestController
|
||||
@RequestMapping("/system/notify-message")
|
||||
@Validated
|
||||
public class NotifyMessageController {
|
||||
|
||||
@Resource
|
||||
private NotifyMessageService notifyMessageService;
|
||||
|
||||
// ========== 管理所有的站内信 ==========
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得站内信")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-message:query')")
|
||||
public CommonResult<NotifyMessageRespVO> getNotifyMessage(@RequestParam("id") Long id) {
|
||||
NotifyMessageDO message = notifyMessageService.getNotifyMessage(id);
|
||||
return success(BeanUtils.toBean(message, NotifyMessageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得站内信分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-message:query')")
|
||||
public CommonResult<PageResult<NotifyMessageRespVO>> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) {
|
||||
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
|
||||
}
|
||||
|
||||
// ========== 查看自己的站内信 ==========
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获得我的站内信分页")
|
||||
public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
|
||||
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO,
|
||||
getLoginUserId(), UserTypeEnum.ADMIN.getValue());
|
||||
return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/update-read")
|
||||
@Operation(summary = "标记站内信为已读")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
|
||||
public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
|
||||
notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@PutMapping("/update-all-read")
|
||||
@Operation(summary = "标记所有站内信为已读")
|
||||
public CommonResult<Boolean> updateAllNotifyMessageRead() {
|
||||
notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/get-unread-list")
|
||||
@Operation(summary = "获取当前用户的最新站内信列表,默认 10 条")
|
||||
@Parameter(name = "size", description = "10")
|
||||
public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
|
||||
@RequestParam(name = "size", defaultValue = "10") Integer size) {
|
||||
List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(
|
||||
getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
|
||||
return success(BeanUtils.toBean(list, NotifyMessageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-unread-count")
|
||||
@Operation(summary = "获得当前用户的未读站内信数量")
|
||||
@ApiAccessLog(enable = false) // 由于前端会不断轮询该接口,记录日志没有意义
|
||||
public CommonResult<Long> getUnreadNotifyMessageCount() {
|
||||
return success(notifyMessageService.getUnreadNotifyMessageCount(
|
||||
getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.notify.vo.template.NotifyTemplateSendReqVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.notify.NotifyTemplateDO;
|
||||
import com.njcn.msgpush.module.system.service.notify.NotifySendService;
|
||||
import com.njcn.msgpush.module.system.service.notify.NotifyTemplateService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 站内信模版")
|
||||
@RestController
|
||||
@RequestMapping("/system/notify-template")
|
||||
@Validated
|
||||
public class NotifyTemplateController {
|
||||
|
||||
@Resource
|
||||
private NotifyTemplateService notifyTemplateService;
|
||||
|
||||
@Resource
|
||||
private NotifySendService notifySendService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建站内信模版")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:create')")
|
||||
public CommonResult<Long> createNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO createReqVO) {
|
||||
return success(notifyTemplateService.createNotifyTemplate(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新站内信模版")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:update')")
|
||||
public CommonResult<Boolean> updateNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO updateReqVO) {
|
||||
notifyTemplateService.updateNotifyTemplate(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除站内信模版")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:delete')")
|
||||
public CommonResult<Boolean> deleteNotifyTemplate(@RequestParam("id") Long id) {
|
||||
notifyTemplateService.deleteNotifyTemplate(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除站内信模版")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:delete')")
|
||||
public CommonResult<Boolean> deleteNotifyTemplateList(@RequestParam("ids") List<Long> ids) {
|
||||
notifyTemplateService.deleteNotifyTemplateList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得站内信模版")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:query')")
|
||||
public CommonResult<NotifyTemplateRespVO> getNotifyTemplate(@RequestParam("id") Long id) {
|
||||
NotifyTemplateDO template = notifyTemplateService.getNotifyTemplate(id);
|
||||
return success(BeanUtils.toBean(template, NotifyTemplateRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得站内信模版分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:query')")
|
||||
public CommonResult<PageResult<NotifyTemplateRespVO>> getNotifyTemplatePage(@Valid NotifyTemplatePageReqVO pageVO) {
|
||||
PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, NotifyTemplateRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/send-notify")
|
||||
@Operation(summary = "发送站内信")
|
||||
@PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
|
||||
public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
|
||||
if (UserTypeEnum.MEMBER.getValue().equals(sendReqVO.getUserType())) {
|
||||
return success(notifySendService.sendSingleNotifyToMember(sendReqVO.getUserId(),
|
||||
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
|
||||
} else {
|
||||
return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(),
|
||||
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.message;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class NotifyMessageMyPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "是否已读", example = "true")
|
||||
private Boolean readStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.message;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class NotifyMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "25025")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", example = "1")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "模板编码", example = "test_01")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "模版类型", example = "2")
|
||||
private Integer templateType;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信 Response VO")
|
||||
@Data
|
||||
public class NotifyMessageRespVO {
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25025")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Byte userType;
|
||||
|
||||
@Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13013")
|
||||
private Long templateId;
|
||||
|
||||
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "模版发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "awen")
|
||||
private String templateNickname;
|
||||
|
||||
@Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容")
|
||||
private String templateContent;
|
||||
|
||||
@Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer templateType;
|
||||
|
||||
@Schema(description = "模版参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Map<String, Object> templateParams;
|
||||
|
||||
@Schema(description = "是否已读", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean readStatus;
|
||||
|
||||
@Schema(description = "阅读时间")
|
||||
private LocalDateTime readTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.template;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信模版分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class NotifyTemplatePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "模版编码", example = "test_01")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "模版名称", example = "我是名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.template;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信模版 Response VO")
|
||||
@Data
|
||||
public class NotifyTemplateRespVO {
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "参数数组", example = "name,code")
|
||||
private List<String> params;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "我是备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.template;
|
||||
|
||||
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.msgpush.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信模版创建/修改 Request VO")
|
||||
@Data
|
||||
public class NotifyTemplateSaveReqVO {
|
||||
|
||||
@Schema(description = "ID", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版")
|
||||
@NotEmpty(message = "模版名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST")
|
||||
@NotNull(message = "模版编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "模版类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||
@NotEmpty(message = "发送人名称不能为空")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容")
|
||||
@NotEmpty(message = "模版内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "我是备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.notify.vo.template;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 站内信模板的发送 Request VO")
|
||||
@Data
|
||||
public class NotifyTemplateSendReqVO {
|
||||
|
||||
@Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "01")
|
||||
@NotNull(message = "用户id不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "01")
|
||||
@NotEmpty(message = "模板编码不能为空")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "模板参数")
|
||||
private Map<String, Object> templateParams;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2ClientService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - OAuth2 客户端")
|
||||
@RestController
|
||||
@RequestMapping("/system/oauth2-client")
|
||||
@Validated
|
||||
public class OAuth2ClientController {
|
||||
|
||||
@Resource
|
||||
private OAuth2ClientService oAuth2ClientService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 OAuth2 客户端")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:create')")
|
||||
public CommonResult<Long> createOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO createReqVO) {
|
||||
return success(oAuth2ClientService.createOAuth2Client(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新 OAuth2 客户端")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:update')")
|
||||
public CommonResult<Boolean> updateOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO updateReqVO) {
|
||||
oAuth2ClientService.updateOAuth2Client(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除 OAuth2 客户端")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')")
|
||||
public CommonResult<Boolean> deleteOAuth2Client(@RequestParam("id") Long id) {
|
||||
oAuth2ClientService.deleteOAuth2Client(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@Operation(summary = "批量删除 OAuth2 客户端")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')")
|
||||
public CommonResult<Boolean> deleteOAuth2ClientList(@RequestParam("ids") List<Long> ids) {
|
||||
oAuth2ClientService.deleteOAuth2ClientList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 OAuth2 客户端")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
|
||||
public CommonResult<OAuth2ClientRespVO> getOAuth2Client(@RequestParam("id") Long id) {
|
||||
OAuth2ClientDO client = oAuth2ClientService.getOAuth2Client(id);
|
||||
return success(BeanUtils.toBean(client, OAuth2ClientRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 OAuth2 客户端分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
|
||||
public CommonResult<PageResult<OAuth2ClientRespVO>> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) {
|
||||
PageResult<OAuth2ClientDO> pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO);
|
||||
return success(BeanUtils.toBean(pageResult, OAuth2ClientRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.http.HttpUtils;
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
|
||||
import com.njcn.msgpush.module.system.convert.oauth2.OAuth2OpenConvert;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
||||
import com.njcn.msgpush.module.system.enums.oauth2.OAuth2GrantTypeEnum;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2ApproveService;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2ClientService;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2GrantService;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2TokenService;
|
||||
import com.njcn.msgpush.module.system.util.oauth2.OAuth2Utils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
|
||||
import static com.njcn.msgpush.framework.common.exception.util.ServiceExceptionUtil.exception0;
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* 提供给外部应用调用为主
|
||||
*
|
||||
* 一般来说,管理后台的 /system-api/* 是不直接提供给外部应用使用,主要是外部应用能够访问的数据与接口是有限的,而管理后台的 RBAC 无法很好的控制。
|
||||
* 参考大量的开放平台,都是独立的一套 OpenAPI,对应到【本系统】就是在 Controller 下新建 open 包,实现 /open-api/* 接口,然后通过 scope 进行控制。
|
||||
* 另外,一个公司如果有多个管理后台,它们 client_id 产生的 access token 相互之间是无法互通的,即无法访问它们系统的 API 接口,直到两个 client_id 产生信任授权。
|
||||
*
|
||||
* 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。
|
||||
* scope 的使用示例,可见 {@link OAuth2UserController} 类
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@Tag(name = "管理后台 - OAuth2.0 授权")
|
||||
@RestController
|
||||
@RequestMapping("/system/oauth2")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class OAuth2OpenController {
|
||||
|
||||
@Resource
|
||||
private OAuth2GrantService oauth2GrantService;
|
||||
@Resource
|
||||
private OAuth2ClientService oauth2ClientService;
|
||||
@Resource
|
||||
private OAuth2ApproveService oauth2ApproveService;
|
||||
@Resource
|
||||
private OAuth2TokenService oauth2TokenService;
|
||||
|
||||
/**
|
||||
* 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法
|
||||
*
|
||||
* 授权码 authorization_code 模式时:code + redirectUri + state 参数
|
||||
* 密码 password 模式时:username + password + scope 参数
|
||||
* 刷新 refresh_token 模式时:refreshToken 参数
|
||||
* 客户端 client_credentials 模式:scope 参数
|
||||
* 简化 implicit 模式时:不支持
|
||||
*
|
||||
* 注意,默认需要传递 client_id + client_secret 参数
|
||||
*/
|
||||
@PostMapping("/token")
|
||||
@PermitAll
|
||||
@Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
|
||||
@Parameters({
|
||||
@Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"),
|
||||
@Parameter(name = "code", description = "授权范围", example = "userinfo.read"),
|
||||
@Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.iocoder.cn"),
|
||||
@Parameter(name = "state", description = "状态", example = "1"),
|
||||
@Parameter(name = "username", example = "tudou"),
|
||||
@Parameter(name = "password", example = "cai"), // 多个使用空格分隔
|
||||
@Parameter(name = "scope", example = "user_info"),
|
||||
@Parameter(name = "refresh_token", example = "123424233"),
|
||||
})
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
|
||||
@RequestParam("grant_type") String grantType,
|
||||
@RequestParam(value = "code", required = false) String code, // 授权码模式
|
||||
@RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式
|
||||
@RequestParam(value = "state", required = false) String state, // 授权码模式
|
||||
@RequestParam(value = "username", required = false) String username, // 密码模式
|
||||
@RequestParam(value = "password", required = false) String password, // 密码模式
|
||||
@RequestParam(value = "scope", required = false) String scope, // 密码模式
|
||||
@RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式
|
||||
List<String> scopes = OAuth2Utils.buildScopes(scope);
|
||||
// 1.1 校验授权类型
|
||||
OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType);
|
||||
if (grantTypeEnum == null) {
|
||||
throw exception0(BAD_REQUEST.getCode(), StrUtil.format("未知授权类型({})", grantType));
|
||||
}
|
||||
if (grantTypeEnum == OAuth2GrantTypeEnum.IMPLICIT) {
|
||||
throw exception0(BAD_REQUEST.getCode(), "Token 接口不支持 implicit 授权模式");
|
||||
}
|
||||
|
||||
// 1.2 校验客户端
|
||||
String[] clientIdAndSecret = obtainBasicAuthorization(request);
|
||||
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
|
||||
grantType, scopes, redirectUri);
|
||||
|
||||
// 2. 根据授权模式,获取访问令牌
|
||||
OAuth2AccessTokenDO accessTokenDO;
|
||||
switch (grantTypeEnum) {
|
||||
case AUTHORIZATION_CODE:
|
||||
accessTokenDO = oauth2GrantService.grantAuthorizationCodeForAccessToken(client.getClientId(), code, redirectUri, state);
|
||||
break;
|
||||
case PASSWORD:
|
||||
accessTokenDO = oauth2GrantService.grantPassword(username, password, client.getClientId(), scopes);
|
||||
break;
|
||||
case CLIENT_CREDENTIALS:
|
||||
accessTokenDO = oauth2GrantService.grantClientCredentials(client.getClientId(), scopes);
|
||||
break;
|
||||
case REFRESH_TOKEN:
|
||||
accessTokenDO = oauth2GrantService.grantRefreshToken(refreshToken, client.getClientId());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("未知授权类型:" + grantType);
|
||||
}
|
||||
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
|
||||
return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO));
|
||||
}
|
||||
|
||||
@DeleteMapping("/token")
|
||||
@PermitAll
|
||||
@Operation(summary = "删除访问令牌")
|
||||
@Parameter(name = "token", required = true, description = "访问令牌", example = "biu")
|
||||
public CommonResult<Boolean> revokeToken(HttpServletRequest request,
|
||||
@RequestParam("token") String token) {
|
||||
// 校验客户端
|
||||
String[] clientIdAndSecret = obtainBasicAuthorization(request);
|
||||
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
|
||||
null, null, null);
|
||||
|
||||
// 删除访问令牌
|
||||
return success(oauth2GrantService.revokeToken(client.getClientId(), token));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法
|
||||
*/
|
||||
@PostMapping("/check-token")
|
||||
@PermitAll
|
||||
@Operation(summary = "校验访问令牌")
|
||||
@Parameter(name = "token", required = true, description = "访问令牌", example = "biu")
|
||||
public CommonResult<OAuth2OpenCheckTokenRespVO> checkToken(HttpServletRequest request,
|
||||
@RequestParam("token") String token) {
|
||||
// 校验客户端
|
||||
String[] clientIdAndSecret = obtainBasicAuthorization(request);
|
||||
oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
|
||||
null, null, null);
|
||||
|
||||
// 校验令牌
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token);
|
||||
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
|
||||
return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 authorize 方法
|
||||
*/
|
||||
@GetMapping("/authorize")
|
||||
@Operation(summary = "获得授权信息", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
|
||||
@Parameter(name = "clientId", required = true, description = "客户端编号", example = "tudou")
|
||||
public CommonResult<OAuth2OpenAuthorizeInfoRespVO> authorize(@RequestParam("clientId") String clientId) {
|
||||
// 0. 校验用户已经登录。通过 Spring Security 实现
|
||||
|
||||
// 1. 获得 Client 客户端的信息
|
||||
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId);
|
||||
// 2. 获得用户已经授权的信息
|
||||
List<OAuth2ApproveDO> approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId);
|
||||
// 拼接返回
|
||||
return success(OAuth2OpenConvert.INSTANCE.convert(client, approves));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 approveOrDeny 方法
|
||||
*
|
||||
* 场景一:【自动授权 autoApprove = true】
|
||||
* 刚进入 sso.vue 界面,调用该接口,用户历史已经给该应用做过对应的授权,或者 OAuth2Client 支持该 scope 的自动授权
|
||||
* 场景二:【手动授权 autoApprove = false】
|
||||
* 在 sso.vue 界面,用户选择好 scope 授权范围,调用该接口,进行授权。此时,approved 为 true 或者 false
|
||||
*
|
||||
* 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理
|
||||
*/
|
||||
@PostMapping("/authorize")
|
||||
@Operation(summary = "申请授权", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【提交】调用")
|
||||
@Parameters({
|
||||
@Parameter(name = "response_type", required = true, description = "响应类型", example = "code"),
|
||||
@Parameter(name = "client_id", required = true, description = "客户端编号", example = "tudou"),
|
||||
@Parameter(name = "scope", description = "授权范围", example = "userinfo.read"), // 使用 Map<String, Boolean> 格式,Spring MVC 暂时不支持这么接收参数
|
||||
@Parameter(name = "redirect_uri", required = true, description = "重定向 URI", example = "https://www.iocoder.cn"),
|
||||
@Parameter(name = "auto_approve", required = true, description = "用户是否接受", example = "true"),
|
||||
@Parameter(name = "state", example = "1")
|
||||
})
|
||||
public CommonResult<String> approveOrDeny(@RequestParam("response_type") String responseType,
|
||||
@RequestParam("client_id") String clientId,
|
||||
@RequestParam(value = "scope", required = false) String scope,
|
||||
@RequestParam("redirect_uri") String redirectUri,
|
||||
@RequestParam(value = "auto_approve") Boolean autoApprove,
|
||||
@RequestParam(value = "state", required = false) String state) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Boolean> scopes = JsonUtils.parseObject(scope, Map.class);
|
||||
scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap());
|
||||
// 0. 校验用户已经登录。通过 Spring Security 实现
|
||||
|
||||
// 1.1 校验 responseType 是否满足 code 或者 token 值
|
||||
OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType);
|
||||
// 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内
|
||||
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null,
|
||||
grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri);
|
||||
|
||||
// 2.1 假设 approved 为 null,说明是场景一
|
||||
if (Boolean.TRUE.equals(autoApprove)) {
|
||||
// 如果无法自动授权通过,则返回空 url,前端不进行跳转
|
||||
if (!oauth2ApproveService.checkForPreApproval(getLoginUserId(), getUserType(), clientId, scopes.keySet())) {
|
||||
return success(null);
|
||||
}
|
||||
} else { // 2.2 假设 approved 非 null,说明是场景二
|
||||
// 如果计算后不通过,则跳转一个错误链接
|
||||
if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) {
|
||||
return success(OAuth2Utils.buildUnsuccessfulRedirect(redirectUri, responseType, state,
|
||||
"access_denied", "User denied access"));
|
||||
}
|
||||
}
|
||||
|
||||
// 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向
|
||||
List<String> approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
|
||||
if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) {
|
||||
return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
|
||||
}
|
||||
// 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向
|
||||
return success(getImplicitGrantRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
|
||||
}
|
||||
|
||||
private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) {
|
||||
if (StrUtil.equals(responseType, "code")) {
|
||||
return OAuth2GrantTypeEnum.AUTHORIZATION_CODE;
|
||||
}
|
||||
if (StrUtil.equalsAny(responseType, "token")) {
|
||||
return OAuth2GrantTypeEnum.IMPLICIT;
|
||||
}
|
||||
throw exception0(BAD_REQUEST.getCode(), "response_type 参数值只允许 code 和 token");
|
||||
}
|
||||
|
||||
private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client,
|
||||
List<String> scopes, String redirectUri, String state) {
|
||||
// 1. 创建 access token 访问令牌
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes);
|
||||
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
|
||||
// 2. 拼接重定向的 URL
|
||||
// noinspection unchecked
|
||||
return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(),
|
||||
scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class));
|
||||
}
|
||||
|
||||
private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client,
|
||||
List<String> scopes, String redirectUri, String state) {
|
||||
// 1. 创建 code 授权码
|
||||
String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId, getUserType(), client.getClientId(), scopes,
|
||||
redirectUri, state);
|
||||
// 2. 拼接重定向的 URL
|
||||
return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state);
|
||||
}
|
||||
|
||||
private Integer getUserType() {
|
||||
return UserTypeEnum.ADMIN.getValue();
|
||||
}
|
||||
|
||||
private String[] obtainBasicAuthorization(HttpServletRequest request) {
|
||||
String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request);
|
||||
if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) {
|
||||
throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递");
|
||||
}
|
||||
return clientIdAndSecret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.pojo.PageResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.njcn.msgpush.module.system.enums.logger.LoginLogTypeEnum;
|
||||
import com.njcn.msgpush.module.system.service.auth.AdminAuthService;
|
||||
import com.njcn.msgpush.module.system.service.oauth2.OAuth2TokenService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - OAuth2.0 令牌")
|
||||
@RestController
|
||||
@RequestMapping("/system/oauth2-token")
|
||||
public class OAuth2TokenController {
|
||||
|
||||
@Resource
|
||||
private OAuth2TokenService oauth2TokenService;
|
||||
@Resource
|
||||
private AdminAuthService authService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得访问令牌分页", description = "只返回有效期内的")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-token:page')")
|
||||
public CommonResult<PageResult<OAuth2AccessTokenRespVO>> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) {
|
||||
PageResult<OAuth2AccessTokenDO> pageResult = oauth2TokenService.getAccessTokenPage(reqVO);
|
||||
return success(BeanUtils.toBean(pageResult, OAuth2AccessTokenRespVO.class));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除访问令牌")
|
||||
@Parameter(name = "accessToken", description = "访问令牌", required = true, example = "tudou")
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')")
|
||||
public CommonResult<Boolean> deleteAccessToken(@RequestParam("accessToken") String accessToken) {
|
||||
authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除访问令牌")
|
||||
@Parameter(name = "accessTokens", description = "访问令牌数组", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')")
|
||||
public CommonResult<Boolean> deleteAccessTokenList(@RequestParam("accessTokens") List<String> accessTokens) {
|
||||
accessTokens.forEach(accessToken ->
|
||||
authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO;
|
||||
import com.njcn.msgpush.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.dept.PostDO;
|
||||
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.njcn.msgpush.module.system.service.dept.DeptService;
|
||||
import com.njcn.msgpush.module.system.service.dept.PostService;
|
||||
import com.njcn.msgpush.module.system.service.user.AdminUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
|
||||
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* 提供给外部应用调用为主
|
||||
*
|
||||
* 1. 在 getUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.read')") 注解,声明需要满足 scope = user.read
|
||||
* 2. 在 updateUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.write')") 注解,声明需要满足 scope = user.write
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@Tag(name = "管理后台 - OAuth2.0 用户")
|
||||
@RestController
|
||||
@RequestMapping("/system/oauth2/user")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class OAuth2UserController {
|
||||
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
@Resource
|
||||
private PostService postService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得用户基本信息")
|
||||
@PreAuthorize("@ss.hasScope('user.read')")
|
||||
public CommonResult<OAuth2UserInfoRespVO> getUserInfo() {
|
||||
// 获得用户基本信息
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
OAuth2UserInfoRespVO resp = BeanUtils.toBean(user, OAuth2UserInfoRespVO.class);
|
||||
// 获得部门信息
|
||||
if (user.getDeptId() != null) {
|
||||
DeptDO dept = deptService.getDept(user.getDeptId());
|
||||
resp.setDept(BeanUtils.toBean(dept, OAuth2UserInfoRespVO.Dept.class));
|
||||
}
|
||||
// 获得主岗位信息
|
||||
if (user.getPositionId() != null) {
|
||||
PostDO position = postService.getPost(user.getPositionId());
|
||||
resp.setPosition(BeanUtils.toBean(position, OAuth2UserInfoRespVO.Post.class));
|
||||
}
|
||||
return success(resp);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新用户基本信息")
|
||||
@PreAuthorize("@ss.hasScope('user.write')")
|
||||
public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) {
|
||||
// 这里将 OAuth2UserUpdateReqVO 转成 UserProfileUpdateReqVO,实现接口复用
|
||||
userService.updateUserProfile(getLoginUserId(), BeanUtils.toBean(reqVO, UserProfileUpdateReqVO.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - OAuth2 客户端分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class OAuth2ClientPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "应用名,模糊匹配", example = "土豆")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - OAuth2 客户端 Response VO")
|
||||
@Data
|
||||
public class OAuth2ClientRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou")
|
||||
private String clientId;
|
||||
|
||||
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan")
|
||||
private String secret;
|
||||
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
private String logo;
|
||||
|
||||
@Schema(description = "应用描述", example = "我是一个应用")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640")
|
||||
private Integer accessTokenValiditySeconds;
|
||||
|
||||
@Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000")
|
||||
private Integer refreshTokenValiditySeconds;
|
||||
|
||||
@Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
|
||||
private List<String> redirectUris;
|
||||
|
||||
@Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password")
|
||||
private List<String> authorizedGrantTypes;
|
||||
|
||||
@Schema(description = "授权范围", example = "user_info")
|
||||
private List<String> scopes;
|
||||
|
||||
@Schema(description = "自动通过的授权范围", example = "user_info")
|
||||
private List<String> autoApproveScopes;
|
||||
|
||||
@Schema(description = "权限", example = "system:user:query")
|
||||
private List<String> authorities;
|
||||
|
||||
@Schema(description = "资源", example = "1024")
|
||||
private List<String> resourceIds;
|
||||
|
||||
@Schema(description = "附加信息", example = "{yunai: true}")
|
||||
private String additionalInformation;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.client;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - OAuth2 客户端创建/修改 Request VO")
|
||||
@Data
|
||||
public class OAuth2ClientSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou")
|
||||
@NotNull(message = "客户端编号不能为空")
|
||||
private String clientId;
|
||||
|
||||
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan")
|
||||
@NotNull(message = "客户端密钥不能为空")
|
||||
private String secret;
|
||||
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||
@NotNull(message = "应用名不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
@NotNull(message = "应用图标不能为空")
|
||||
@URL(message = "应用图标的地址不正确")
|
||||
private String logo;
|
||||
|
||||
@Schema(description = "应用描述", example = "我是一个应用")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640")
|
||||
@NotNull(message = "访问令牌的有效期不能为空")
|
||||
private Integer accessTokenValiditySeconds;
|
||||
|
||||
@Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000")
|
||||
@NotNull(message = "刷新令牌的有效期不能为空")
|
||||
private Integer refreshTokenValiditySeconds;
|
||||
|
||||
@Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
|
||||
@NotNull(message = "可重定向的 URI 地址不能为空")
|
||||
private List<@NotEmpty(message = "重定向的 URI 不能为空") @URL(message = "重定向的 URI 格式不正确") String> redirectUris;
|
||||
|
||||
@Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password")
|
||||
@NotNull(message = "授权类型不能为空")
|
||||
private List<String> authorizedGrantTypes;
|
||||
|
||||
@Schema(description = "授权范围", example = "user_info")
|
||||
private List<String> scopes;
|
||||
|
||||
@Schema(description = "自动通过的授权范围", example = "user_info")
|
||||
private List<String> autoApproveScopes;
|
||||
|
||||
@Schema(description = "权限", example = "system:user:query")
|
||||
private List<String> authorities;
|
||||
|
||||
@Schema(description = "资源", example = "1024")
|
||||
private List<String> resourceIds;
|
||||
|
||||
@Schema(description = "附加信息", example = "{yunai: true}")
|
||||
private String additionalInformation;
|
||||
|
||||
@AssertTrue(message = "附加信息必须是 JSON 格式")
|
||||
public boolean isAdditionalInformationJson() {
|
||||
return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 【开放接口】访问令牌 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2OpenAccessTokenRespVO {
|
||||
|
||||
@Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou")
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
@Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice")
|
||||
@JsonProperty("refresh_token")
|
||||
private String refreshToken;
|
||||
|
||||
@Schema(description = "令牌类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bearer")
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
|
||||
@Schema(description = "过期时间,单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "42430")
|
||||
@JsonProperty("expires_in")
|
||||
private Long expiresIn;
|
||||
|
||||
@Schema(description = "授权范围,如果多个授权范围,使用空格分隔", example = "user_info")
|
||||
private String scope;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open;
|
||||
|
||||
import com.njcn.msgpush.framework.common.core.KeyValue;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 授权页的信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2OpenAuthorizeInfoRespVO {
|
||||
|
||||
/**
|
||||
* 客户端
|
||||
*/
|
||||
private Client client;
|
||||
|
||||
@Schema(description = "scope 的选中信息,使用 List 保证有序性,Key 是 scope,Value 为是否选中", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<KeyValue<String, Boolean>> scopes;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Client {
|
||||
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
private String logo;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.open;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "Admin API - open check token response")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2OpenCheckTokenRespVO {
|
||||
|
||||
@Schema(description = "User id", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
@JsonProperty("user_id")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "User type", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@JsonProperty("user_type")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "Client id", requiredMode = Schema.RequiredMode.REQUIRED, example = "car")
|
||||
@JsonProperty("client_id")
|
||||
private String clientId;
|
||||
|
||||
@Schema(description = "Scopes", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_info")
|
||||
private List<String> scopes;
|
||||
|
||||
@Schema(description = "Access token", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou")
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
@Schema(description = "Expire timestamp in seconds", requiredMode = Schema.RequiredMode.REQUIRED, example = "1593092157")
|
||||
private Long exp;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.njcn.msgpush.module.system.controller.admin.oauth2.vo.token;
|
||||
|
||||
import com.njcn.msgpush.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - 访问令牌分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class OAuth2AccessTokenPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private String clientId;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user