This commit is contained in:
2025-10-17 10:11:04 +08:00
commit 9618d5cfa1
2012 changed files with 163764 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
<?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">
<parent>
<groupId>com.jeelowcode</groupId>
<artifactId>jeelowcode-service</artifactId>
<version>${jeelowcode.version}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeelowcode-service-system-biz</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
system 模块下,我们放通用业务,支撑上层的核心业务。
例如说:用户、部门、权限、数据字典等等
</description>
<dependencies>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>jeelowcode-service-system-api</artifactId>
<version>${jeelowcode.version}</version>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>jeelowcode-service-infra-api</artifactId>
<version>${jeelowcode.version}</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-biz-operatelog</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-biz-dict</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-biz-data-permission</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-biz-ip</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-redis</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-mq</artifactId>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>tool-spring-boot-starter-captcha</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId> <!-- 微信登录(公众号) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId> <!-- 微信登录(小程序) -->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId> <!-- 短信(阿里云) -->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId> <!-- 短信(阿里云) -->
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
</dependency>
<!-- 低代码 -->
<dependency>
<groupId>com.jeelowcode</groupId>
<artifactId>jeelowcode-module-api</artifactId>
</dependency>
<dependency>
<groupId>com.github.stuxuhai</groupId>
<artifactId>jpinyin</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,58 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.AdminUserRespDTO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.service.IDeptService;
import com.jeelowcode.service.system.service.IAdminUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertSet;
/**
* Admin 用户 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiAdminUserApiImpl implements IApiAdminUserApi {
@Resource
private IAdminUserService userService;
@Resource
private IDeptService deptService;
@Override
public AdminUserRespDTO getUser(Long id) {
AdminUserDO user = userService.getUser(id);
return BeanUtils.toBean(user, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserList(Collection<Long> ids) {
List<AdminUserDO> users = userService.getUserList(ids);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserListByDeptIds(Collection<Long> deptIds) {
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds) {
List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public void validateUserList(Collection<Long> ids) {
userService.validateUserList(ids);
}
}

View File

@@ -0,0 +1,47 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.DeptRespDTO;
import com.jeelowcode.service.system.entity.DeptDO;
import com.jeelowcode.service.system.service.IDeptService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* 部门 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiDeptApiImpl implements IApiDeptApi {
@Resource
private IDeptService deptService;
@Override
public DeptRespDTO getDept(Long id) {
DeptDO dept = deptService.getDept(id);
return BeanUtils.toBean(dept, DeptRespDTO.class);
}
@Override
public List<DeptRespDTO> getDeptList(Collection<Long> ids) {
List<DeptDO> depts = deptService.getDeptList(ids);
return BeanUtils.toBean(depts, DeptRespDTO.class);
}
@Override
public void validateDeptList(Collection<Long> ids) {
deptService.validateDeptList(ids);
}
@Override
public List<DeptRespDTO> getChildDeptList(Long id) {
List<DeptDO> childDeptList = deptService.getChildDeptList(id);
return BeanUtils.toBean(childDeptList, DeptRespDTO.class);
}
}

View File

@@ -0,0 +1,40 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.DictDataRespDTO;
import com.jeelowcode.service.system.entity.DictDataDO;
import com.jeelowcode.service.system.service.IDictDataService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 字典数据 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiDictDataApiImpl implements IApiDictDataApi {
@Resource
private IDictDataService dictDataService;
@Override
public void validateDictDataList(String dictType, Collection<String> values) {
dictDataService.validateDictDataList(dictType, values);
}
@Override
public DictDataRespDTO getDictData(String dictType, String value) {
DictDataDO dictData = dictDataService.getDictData(dictType, value);
return BeanUtils.toBean(dictData, DictDataRespDTO.class);
}
@Override
public DictDataRespDTO parseDictData(String dictType, String label) {
DictDataDO dictData = dictDataService.parseDictData(dictType, label);
return BeanUtils.toBean(dictData, DictDataRespDTO.class);
}
}

View File

@@ -0,0 +1,33 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.ErrorCodeAutoGenerateReqDTO;
import com.jeelowcode.service.system.dto.ErrorCodeRespDTO;
import com.jeelowcode.service.system.service.IErrorCodeService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
/**
* 错误码 Api 实现类
*
* @author 芋道源码
*/
@Service
public class ApiErrorCodeApiImpl implements IApiErrorCodeApi {
@Resource
private IErrorCodeService errorCodeService;
@Override
public void autoGenerateErrorCodeList(List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs) {
errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs);
}
@Override
public List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, LocalDateTime minUpdateTime) {
return errorCodeService.getErrorCodeList(applicationName, minUpdateTime);
}
}

View File

@@ -0,0 +1,27 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.LoginLogCreateReqDTO;
import com.jeelowcode.service.system.service.ILoginLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 登录日志的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiLoginLogApiImpl implements IApiLoginLogApi {
@Resource
private ILoginLogService loginLogService;
@Override
public void createLoginLog(LoginLogCreateReqDTO reqDTO) {
loginLogService.createLoginLog(reqDTO);
}
}

View File

@@ -0,0 +1,20 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.MailSendSingleToUserReqDTO;
import com.jeelowcode.service.system.service.IMailSendService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 邮件发送 API 实现类
*
* @author wangjingyi
*/
@Service
@Validated
public class ApiMailSendApiImpl implements IApiMailSendApi {
}

View File

@@ -0,0 +1,27 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.NotifySendSingleToUserReqDTO;
import com.jeelowcode.service.system.service.INotifySendService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 站内信发送 API 实现类
*
* @author xrcoder
*/
@Service
public class ApiNotifyMessageSendApiImpl implements IApiNotifyMessageSendApi {
@Resource
private INotifySendService notifySendService;
@Override
public void sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) {
notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@@ -0,0 +1,49 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.OAuth2AccessTokenCheckRespDTO;
import com.jeelowcode.service.system.dto.OAuth2AccessTokenCreateReqDTO;
import com.jeelowcode.service.system.dto.OAuth2AccessTokenRespDTO;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import com.jeelowcode.service.system.service.IOAuth2TokenService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* OAuth2.0 Token API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiOAuth2TokenApiImpl implements IApiOAuth2TokenApi {
@Resource
private IOAuth2TokenService oauth2TokenService;
@Override
public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(),reqDTO.getLoginDeptId(),reqDTO.getLoginRoleId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
@Override
public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class);
}
@Override
public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
@Override
public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
}

View File

@@ -0,0 +1,61 @@
package com.jeelowcode.service.system.api;
import cn.hutool.core.collection.CollUtil;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.service.system.dto.OperateLogCreateReqDTO;
import com.jeelowcode.service.system.dto.OperateLogV2CreateReqDTO;
import com.jeelowcode.service.system.dto.OperateLogV2PageReqDTO;
import com.jeelowcode.service.system.dto.OperateLogV2RespDTO;
import com.jeelowcode.service.system.config.convert.logger.OperateLogConvert;
import com.jeelowcode.service.system.entity.OperateLogV2DO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.service.IAdminUserService;
import com.jeelowcode.service.system.service.IOperateLogService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertSet;
/**
* 操作日志 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiOperateLogApiImpl implements IApiOperateLogApi {
@Resource
private IOperateLogService operateLogService;
@Resource
private IAdminUserService adminUserService;
@Override
public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
operateLogService.createOperateLog(createReqDTO);
}
@Override
@Async
public void createOperateLogV2(OperateLogV2CreateReqDTO createReqDTO) {
operateLogService.createOperateLogV2(createReqDTO);
}
@Override
public PageResult<OperateLogV2RespDTO> getOperateLogPage(OperateLogV2PageReqDTO pageReqVO) {
PageResult<OperateLogV2DO> operateLogPage = operateLogService.getOperateLogPage(pageReqVO);
if (CollUtil.isEmpty(operateLogPage.getList())) {
return PageResult.empty();
}
// 获取用户
List<AdminUserDO> userList = adminUserService.getUserList(
convertSet(operateLogPage.getList(), OperateLogV2DO::getUserId));
return OperateLogConvert.INSTANCE.convertPage(operateLogPage, userList);
}
}

View File

@@ -0,0 +1,42 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.DeptDataPermissionRespDTO;
import com.jeelowcode.service.system.service.IPermissionService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Set;
/**
* 权限 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiPermissionApiImpl implements IApiPermissionApi {
@Resource
private IPermissionService permissionService;
@Override
public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
return permissionService.getUserRoleIdListByRoleId(roleIds);
}
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
return permissionService.hasAnyPermissions(userId, permissions);
}
@Override
public boolean hasAnyRoles(Long userId, String... roles) {
return permissionService.hasAnyRoles(userId, roles);
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
return permissionService.getDeptDataPermission(userId);
}
}

View File

@@ -0,0 +1,35 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.PostRespDTO;
import com.jeelowcode.service.system.entity.PostDO;
import com.jeelowcode.service.system.service.IPostService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* 岗位 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiPostApiImpl implements IApiPostApi {
@Resource
private IPostService postService;
@Override
public void validPostList(Collection<Long> ids) {
postService.validatePostList(ids);
}
@Override
public List<PostRespDTO> getPostList(Collection<Long> ids) {
List<PostDO> list = postService.getPostList(ids);
return BeanUtils.toBean(list, PostRespDTO.class);
}
}

View File

@@ -0,0 +1,24 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.service.IRoleService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 角色 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiRoleApiImpl implements IApiRoleApi {
@Resource
private IRoleService roleService;
@Override
public void validRoleList(Collection<Long> ids) {
roleService.validateRoleList(ids);
}
}

View File

@@ -0,0 +1,29 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.service.ISensitiveWordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 敏感词 API 实现类
*
* @author 永不言败
*/
@Service
public class ApiSensitiveWordApiImpl implements IApiSensitiveWordApi {
@Resource
private ISensitiveWordService sensitiveWordService;
@Override
public List<String> validateText(String text, List<String> tags) {
return sensitiveWordService.validateText(text, tags);
}
@Override
public boolean isTextValid(String text, List<String> tags) {
return sensitiveWordService.isTextValid(text, tags);
}
}

View File

@@ -0,0 +1,39 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.SmsCodeValidateReqDTO;
import com.jeelowcode.service.system.dto.SmsCodeSendReqDTO;
import com.jeelowcode.service.system.dto.SmsCodeUseReqDTO;
import com.jeelowcode.service.system.service.ISmsCodeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信验证码 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiSmsCodeApiImpl implements IApiSmsCodeApi {
@Resource
private ISmsCodeService smsCodeService;
@Override
public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
smsCodeService.sendSmsCode(reqDTO);
}
@Override
public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
smsCodeService.useSmsCode(reqDTO);
}
@Override
public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
smsCodeService.validateSmsCode(reqDTO);
}
}

View File

@@ -0,0 +1,29 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.SmsSendSingleToUserReqDTO;
import com.jeelowcode.service.system.service.ISmsSendService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信发送 API 接口
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiSmsSendApiImpl implements IApiSmsSendApi {
@Resource
private ISmsSendService smsSendService;
@Override
public Long sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) {
return smsSendService.sendSingleSmsToAdmin(reqDTO.getMobile(), reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@@ -0,0 +1,43 @@
package com.jeelowcode.service.system.api;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.SocialWxJsapiSignatureRespDTO;
import com.jeelowcode.service.system.dto.SocialWxPhoneNumberInfoRespDTO;
import com.jeelowcode.service.system.service.ISocialClientService;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 社交应用的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiSocialClientApiImpl implements IApiSocialClientApi {
@Resource
private ISocialClientService socialClientService;
@Override
public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
return socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
}
@Override
public SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url) {
WxJsapiSignature signature = socialClientService.createWxMpJsapiSignature(userType, url);
return BeanUtils.toBean(signature, SocialWxJsapiSignatureRespDTO.class);
}
@Override
public SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
return BeanUtils.toBean(info, SocialWxPhoneNumberInfoRespDTO.class);
}
}

View File

@@ -0,0 +1,45 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.dto.SocialUserBindReqDTO;
import com.jeelowcode.service.system.dto.SocialUserRespDTO;
import com.jeelowcode.service.system.dto.SocialUserUnbindReqDTO;
import com.jeelowcode.service.system.service.ISocialUserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 社交用户的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiSocialUserApiImpl implements IApiSocialUserApi {
@Resource
private ISocialUserService socialUserService;
@Override
public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
return socialUserService.bindSocialUser(reqDTO);
}
@Override
public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) {
socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(),
reqDTO.getSocialType(), reqDTO.getOpenid());
}
@Override
public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) {
return socialUserService.getSocialUserByUserId(userType, userId, socialType);
}
@Override
public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) {
return socialUserService.getSocialUserByCode(userType, socialType, code, state);
}
}

View File

@@ -0,0 +1,30 @@
package com.jeelowcode.service.system.api;
import com.jeelowcode.service.system.service.ITenantService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 多租户的 API 实现类
*
* @author 芋道源码
*/
@Service
public class ApiTenantApiImpl implements IApiTenantApi {
@Resource
private ITenantService tenantService;
@Override
public List<Long> getTenantIdList() {
return tenantService.getTenantIdList();
}
@Override
public void validateTenant(Long id) {
tenantService.validTenant(id);
}
}

View File

@@ -0,0 +1,100 @@
package com.jeelowcode.service.system.config.convert.auth;
import cn.hutool.core.collection.CollUtil;
import com.jeelowcode.service.system.controller.vo.auth.*;
import com.jeelowcode.service.system.dto.SmsCodeSendReqDTO;
import com.jeelowcode.service.system.dto.SmsCodeUseReqDTO;
import com.jeelowcode.service.system.dto.SocialUserBindReqDTO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.entity.MenuDO;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import com.jeelowcode.service.system.entity.RoleDO;
import com.jeelowcode.service.system.enums.MenuTypeEnum;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.slf4j.LoggerFactory;
import java.util.*;
import static com.jeelowcode.service.system.entity.MenuDO.ID_ROOT;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertSet;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.filterList;
@Mapper
public interface AuthConvert {
AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class);
AuthLoginRespVO convert(OAuth2AccessTokenDO bean);
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList, Set<String> allPermissions) {
Set<String> myPermissions = convertSet(menuList, MenuDO::getPermission);
Map<String,Boolean> permissionMap=new HashMap<>();
for(String allPermission:allPermissions){
Boolean hasRole=false;
if(myPermissions.contains(allPermission)){
hasRole=true;
}
permissionMap.put(allPermission,hasRole);
}
return AuthPermissionInfoRespVO.builder()
.user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class))
.roles(convertSet(roleList, RoleDO::getCode))
// 权限标识信息
.permissions(permissionMap)
// 菜单树
.menus(buildMenuTree(menuList))
.build();
}
AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu);
/**
* 将菜单列表,构建成菜单树
*
* @param menuList 菜单列表
* @return 菜单树
*/
default List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList) {
if (CollUtil.isEmpty(menuList)) {
return Collections.emptyList();
}
// 移除按钮
menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType()));
// 排序,保证菜单的有序性
menuList.sort(Comparator.comparing(MenuDO::getSort));
// 构建菜单树
// 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu)));
// 处理父子关系
treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> {
// 获得父节点
AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
if (parentNode == null) {
LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
childNode.getId(), childNode.getParentId());
return;
}
// 将自己添加到父节点中
if (parentNode.getChildren() == null) {
parentNode.setChildren(new ArrayList<>());
}
parentNode.getChildren().add(childNode);
});
// 获得到所有的根节点
return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId()));
}
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO);
SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO);
SmsCodeUseReqDTO convert(AuthSmsLoginReqVO reqVO, Integer scene, String usedIp);
}

View File

@@ -0,0 +1,49 @@
package com.jeelowcode.service.system.config.convert.logger;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.collection.CollectionUtils;
import com.jeelowcode.tool.framework.common.util.collection.MapUtils;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.dto.OperateLogV2RespDTO;
import com.jeelowcode.service.system.controller.vo.logger.operatelog.OperateLogRespVO;
import com.jeelowcode.service.system.entity.OperateLogDO;
import com.jeelowcode.service.system.entity.OperateLogV2DO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertMap;
import static com.jeelowcode.tool.framework.common.util.collection.MapUtils.findAndThen;
@Mapper
public interface OperateLogConvert {
OperateLogConvert INSTANCE = Mappers.getMapper(OperateLogConvert.class);
default List<OperateLogRespVO> convertList(List<OperateLogDO> list, Map<Long, AdminUserDO> userMap) {
return CollectionUtils.convertList(list, log -> {
OperateLogRespVO logVO = BeanUtils.toBean(log, OperateLogRespVO.class);
MapUtils.findAndThen(userMap, log.getUserId(), user -> logVO.setUserNickname(user.getNickname()));
return logVO;
});
}
default PageResult<OperateLogV2RespDTO> convertPage(PageResult<OperateLogV2DO> operateLogPage, List<AdminUserDO> userList) {
return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList));
}
OperateLogV2RespDTO convert(OperateLogV2DO operateLogV2DO);
default List<OperateLogV2RespDTO> setUserInfo(List<OperateLogV2DO> logList, List<AdminUserDO> userList) {
Map<Long, AdminUserDO> userMap = convertMap(userList, AdminUserDO::getId);
return CollectionUtils.convertList(logList, item -> {
OperateLogV2RespDTO respDTO = convert(item);
findAndThen(userMap, item.getUserId(), user -> respDTO.setUserName(user.getNickname()));
return respDTO;
});
}
}

View File

@@ -0,0 +1,21 @@
package com.jeelowcode.service.system.config.convert.mail;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import com.jeelowcode.service.system.entity.MailAccountDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface MailAccountConvert {
MailAccountConvert INSTANCE = Mappers.getMapper(MailAccountConvert.class);
default MailAccount convert(MailAccountDO account, String nickname) {
String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
return new MailAccount().setFrom(from).setAuth(true)
.setUser(account.getUsername()).setPass(account.getPassword())
.setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable());
}
}

View File

@@ -0,0 +1,56 @@
package com.jeelowcode.service.system.config.convert.oauth2;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.util.collection.CollectionUtils;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenAccessTokenRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenAuthorizeInfoRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenCheckTokenRespVO;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import com.jeelowcode.service.system.entity.OAuth2ApproveDO;
import com.jeelowcode.service.system.entity.OAuth2ClientDO;
import com.jeelowcode.service.system.util.OAuth2Utils;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Mapper
public interface OAuth2OpenConvert {
OAuth2OpenConvert INSTANCE = Mappers.getMapper(OAuth2OpenConvert.class);
default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) {
OAuth2OpenAccessTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenAccessTokenRespVO.class);
respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase());
respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime()));
respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes()));
return respVO;
}
default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) {
OAuth2OpenCheckTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenCheckTokenRespVO.class);
respVO.setExp(LocalDateTimeUtil.toEpochMilli(bean.getExpiresTime()) / 1000L);
respVO.setUserType(UserTypeEnum.ADMIN.getValue());
return respVO;
}
default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List<OAuth2ApproveDO> approves) {
// 构建 scopes
List<KeyValue<String, Boolean>> scopes = new ArrayList<>(client.getScopes().size());
Map<String, OAuth2ApproveDO> approveMap = CollectionUtils.convertMap(approves, OAuth2ApproveDO::getScope);
client.getScopes().forEach(scope -> {
OAuth2ApproveDO approve = approveMap.get(scope);
scopes.add(new KeyValue<>(scope, approve != null ? approve.getApproved() : false));
});
// 拼接返回
return new OAuth2OpenAuthorizeInfoRespVO(
new OAuth2OpenAuthorizeInfoRespVO.Client(client.getName(), client.getLogo()), scopes);
}
}

View File

@@ -0,0 +1,6 @@
/**
* 提供 POJO 类的实体转换
*
* 目前使用 MapStruct 框架
*/
package com.jeelowcode.service.system.config.convert;

View File

@@ -0,0 +1,17 @@
package com.jeelowcode.service.system.config.convert.social;
import com.jeelowcode.service.system.dto.SocialUserBindReqDTO;
import com.jeelowcode.service.system.controller.vo.socail.user.SocialUserBindReqVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface SocialUserConvert {
SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class);
@Mapping(source = "reqVO.type", target = "socialType")
SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO);
}

View File

@@ -0,0 +1,26 @@
package com.jeelowcode.service.system.config.convert.tenant;
import com.jeelowcode.service.system.controller.vo.tenant.tenant.TenantSaveReqVO;
import com.jeelowcode.service.system.controller.vo.user.user.UserSaveReqVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 租户 Convert
*
* @author 芋道源码
*/
@Mapper
public interface TenantConvert {
TenantConvert INSTANCE = Mappers.getMapper(TenantConvert.class);
default UserSaveReqVO convert02(TenantSaveReqVO bean) {
UserSaveReqVO reqVO = new UserSaveReqVO();
reqVO.setUsername(bean.getUsername());
reqVO.setPassword(bean.getPassword());
reqVO.setNickname(bean.getContactName()).setMobile(bean.getContactMobile());
return reqVO;
}
}

View File

@@ -0,0 +1,43 @@
package com.jeelowcode.service.system.config.convert.user;
import com.jeelowcode.tool.framework.common.util.collection.CollectionUtils;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.user.profile.UserProfileRespVO;
import com.jeelowcode.service.system.controller.vo.user.user.UserRespVO;
import com.jeelowcode.service.system.controller.vo.user.user.UserSimpleRespVO;
import com.jeelowcode.service.system.entity.SocialUserDO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
default List<UserRespVO> convertList(List<AdminUserDO> list) {
return CollectionUtils.convertList(list, user -> convert(user));
}
default UserRespVO convert(AdminUserDO user) {
UserRespVO userVO = BeanUtils.toBean(user, UserRespVO.class);
return userVO;
}
default List<UserSimpleRespVO> convertSimpleList(List<AdminUserDO> list) {
return CollectionUtils.convertList(list, user -> {
UserSimpleRespVO userVO = BeanUtils.toBean(user, UserSimpleRespVO.class);
return userVO;
});
}
default UserProfileRespVO convert(List<SocialUserDO> socialUsers,
AdminUserDO user) {
UserProfileRespVO userVO = BeanUtils.toBean(user, UserProfileRespVO.class);
userVO.setSocialUsers(BeanUtils.toBean(socialUsers, UserProfileRespVO.SocialUser.class));
return userVO;
}
}

View File

@@ -0,0 +1,31 @@
package com.jeelowcode.service.system.config.framework.datapermission.config;
import com.jeelowcode.tool.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* system 模块的数据权限 Configuration
*
* @author 芋道源码
*/
@Configuration(proxyBeanMethods = false)
public class DataPermissionConfiguration {
@Bean
public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
return rule -> {
/*
暂时不做系统表
rule.addDeptColumn(AdminUserDO.class);
rule.addDeptColumn(DeptDO.class, "id");
// user
rule.addUserColumn(AdminUserDO.class, "id");*/
// dept
//rule.addJeeLowCodeColumn("test_form_dictionary");
};
}
}

View File

@@ -0,0 +1,4 @@
/**
* system 模块的数据权限配置
*/
package com.jeelowcode.service.system.config.framework.datapermission;

View File

@@ -0,0 +1,51 @@
package com.jeelowcode.service.system.config.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.service.system.api.IApiAdminUserApi;
import com.jeelowcode.service.system.dto.AdminUserRespDTO;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 管理员名字的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class AdminUserParseFunction implements IParseFunction {
public static final String NAME = "getAdminUserById";
@Resource
private IApiAdminUserApi apiAdminUserApi;
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
// 获取用户信息
AdminUserRespDTO user = apiAdminUserApi.getUser(Long.parseLong(value.toString()));
if (user == null) {
log.warn("[apply][获取用户{{}}为空", value);
return "";
}
// 返回格式 芋道源码(13888888888)
String nickname = user.getNickname();
if (StrUtil.isEmpty(user.getMobile())) {
return nickname;
}
return StrUtil.format("{}({})", nickname, user.getMobile());
}
}

View File

@@ -0,0 +1,38 @@
package com.jeelowcode.service.system.config.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.tool.framework.ip.core.utils.AreaUtils;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 地名的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class AreaParseFunction implements IParseFunction {
public static final String NAME = "getArea";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return AreaUtils.format(Integer.parseInt(value.toString()));
}
}

View File

@@ -0,0 +1,39 @@
package com.jeelowcode.service.system.config.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.tool.framework.dict.core.util.DictFrameworkUtils;
import com.jeelowcode.service.infra.enums.DictTypeConstants;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 是否类型的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Component
@Slf4j
public class BooleanParseFunction implements IParseFunction {
public static final String NAME = "getBoolean";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString());
}
}

View File

@@ -0,0 +1,46 @@
package com.jeelowcode.service.system.config.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.service.system.api.IApiDeptApi;
import com.jeelowcode.service.system.dto.DeptRespDTO;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 管理员名字的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class DeptParseFunction implements IParseFunction {
public static final String NAME = "getDeptById";
@Resource
private IApiDeptApi apiDeptApi;
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
// 获取部门信息
DeptRespDTO dept = apiDeptApi.getDept(Long.parseLong(value.toString()));
if (dept == null) {
log.warn("[apply][获取部门{{}}为空", value);
return "";
}
return dept.getName();
}
}

View File

@@ -0,0 +1,39 @@
package com.jeelowcode.service.system.config.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.tool.framework.dict.core.util.DictFrameworkUtils;
import com.jeelowcode.service.system.constant.DictTypeConstants;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 行业的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Component
@Slf4j
public class SexParseFunction implements IParseFunction {
public static final String NAME = "getSex";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString());
}
}

View File

@@ -0,0 +1 @@
package com.jeelowcode.service.system.config.framework.operatelog;

View File

@@ -0,0 +1,6 @@
/**
* 属于 system 模块的 framework 封装
*
* @author 芋道源码
*/
package com.jeelowcode.service.system.config.framework;

View File

@@ -0,0 +1,41 @@
package com.jeelowcode.service.system.config.framework.sms.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
import java.time.Duration;
@ConfigurationProperties(prefix = "jeelowcode.sms-code")
@Validated
@Data
public class SmsCodeProperties {
/**
* 过期时间
*/
@NotNull(message = "过期时间不能为空")
private Duration expireTimes;
/**
* 短信发送频率
*/
@NotNull(message = "短信发送频率不能为空")
private Duration sendFrequency;
/**
* 每日发送最大数量
*/
@NotNull(message = "每日发送最大数量不能为空")
private Integer sendMaximumQuantityPerDay;
/**
* 验证码最小值
*/
@NotNull(message = "验证码最小值不能为空")
private Integer beginCode;
/**
* 验证码最大值
*/
@NotNull(message = "验证码最大值不能为空")
private Integer endCode;
}

View File

@@ -0,0 +1,23 @@
package com.jeelowcode.service.system.config.framework.sms.config;
import com.jeelowcode.service.system.config.framework.sms.core.client.SmsClientFactory;
import com.jeelowcode.service.system.config.framework.sms.core.client.impl.SmsClientFactoryImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 短信配置类,包括短信客户端、短信验证码两部分
*
* @author 芋道源码
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SmsCodeProperties.class)
public class SmsConfiguration {
@Bean
public SmsClientFactory smsClientFactory() {
return new SmsClientFactoryImpl();
}
}

View File

@@ -0,0 +1,54 @@
package com.jeelowcode.service.system.config.framework.sms.core.client;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsReceiveRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsSendRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsTemplateRespDTO;
import java.util.List;
/**
* 短信客户端,用于对接各短信平台的 SDK实现短信发送等功能
*
* @author zzf
* @since 2021/1/25 14:14
*/
public interface SmsClient {
/**
* 获得渠道编号
*
* @return 渠道编号
*/
Long getId();
/**
* 发送消息
*
* @param logId 日志编号
* @param mobile 手机号
* @param apiTemplateId 短信 API 的模板编号
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
* @return 短信发送结果
*/
SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId,
List<KeyValue<String, Object>> templateParams) throws Throwable;
/**
* 解析接收短信的接收结果
*
* @param text 结果
* @return 结果内容
* @throws Throwable 当解析 text 发生异常时,则会抛出异常
*/
List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
/**
* 查询指定的短信模板
*
* @param apiTemplateId 短信 API 的模板编号
* @return 短信模板
*/
SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable;
}

View File

@@ -0,0 +1,36 @@
package com.jeelowcode.service.system.config.framework.sms.core.client;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
/**
* 短信客户端的工厂接口
*
* @author zzf
* @since 2021/1/28 14:01
*/
public interface SmsClientFactory {
/**
* 获得短信 Client
*
* @param channelId 渠道编号
* @return 短信 Client
*/
SmsClient getSmsClient(Long channelId);
/**
* 获得短信 Client
*
* @param channelCode 渠道编码
* @return 短信 Client
*/
SmsClient getSmsClient(String channelCode);
/**
* 创建短信 Client
*
* @param properties 配置对象
*/
void createOrUpdateSmsClient(SmsChannelProperties properties);
}

View File

@@ -0,0 +1,48 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 消息接收 Response DTO
*
* @author 芋道源码
*/
@Data
public class SmsReceiveRespDTO {
/**
* 是否接收成功
*/
private Boolean success;
/**
* API 接收结果的编码
*/
private String errorCode;
/**
* API 接收结果的说明
*/
private String errorMsg;
/**
* 手机号
*/
private String mobile;
/**
* 用户接收时间
*/
private LocalDateTime receiveTime;
/**
* 短信 API 发送返回的序号
*/
private String serialNo;
/**
* 短信日志编号
*
* 对应 SysSmsLogDO 的编号
*/
private Long logId;
}

View File

@@ -0,0 +1,43 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.dto;
import lombok.Data;
/**
* 短信发送 Response DTO
*
* @author 芋道源码
*/
@Data
public class SmsSendRespDTO {
/**
* 是否成功
*/
private Boolean success;
/**
* API 请求编号
*/
private String apiRequestId;
// ==================== 成功时字段 ====================
/**
* 短信 API 发送返回的序号
*/
private String serialNo;
// ==================== 失败时字段 ====================
/**
* API 返回错误码
*
* 由于第三方的错误码可能是字符串,所以使用 String 类型
*/
private String apiCode;
/**
* API 返回提示
*/
private String apiMsg;
}

View File

@@ -0,0 +1,33 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.dto;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import lombok.Data;
/**
* 短信模板 Response DTO
*
* @author 芋道源码
*/
@Data
public class SmsTemplateRespDTO {
/**
* 模板编号
*/
private String id;
/**
* 短信内容
*/
private String content;
/**
* 审核状态
*
* 枚举 {@link SmsTemplateAuditStatusEnum}
*/
private Integer auditStatus;
/**
* 审核未通过的理由
*/
private String auditReason;
}

View File

@@ -0,0 +1,54 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.impl;
import com.jeelowcode.service.system.config.framework.sms.core.client.SmsClient;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
/**
* 短信客户端的抽象类,提供模板方法,减少子类的冗余代码
*
* @author zzf
* @since 2021/2/1 9:28
*/
@Slf4j
public abstract class AbstractSmsClient implements SmsClient {
/**
* 短信渠道配置
*/
protected volatile SmsChannelProperties properties;
public AbstractSmsClient(SmsChannelProperties properties) {
this.properties = properties;
}
/**
* 初始化
*/
public final void init() {
doInit();
log.debug("[init][配置({}) 初始化完成]", properties);
}
/**
* 自定义初始化
*/
protected abstract void doInit();
public final void refresh(SmsChannelProperties properties) {
// 判断是否更新
if (properties.equals(this.properties)) {
return;
}
log.info("[refresh][配置({})发生变化,重新初始化]", properties);
this.properties = properties;
// 初始化
this.init();
}
@Override
public Long getId() {
return properties.getId();
}
}

View File

@@ -0,0 +1,182 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.impl;
import cn.hutool.core.lang.Assert;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.tool.framework.common.util.collection.MapUtils;
import com.jeelowcode.tool.framework.common.util.json.JsonUtils;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsReceiveRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsSendRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsTemplateRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList;
import static com.jeelowcode.tool.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static com.jeelowcode.tool.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
* 阿里短信客户端的实现类
*
* @author zzf
* @since 2021/1/25 14:17
*/
@Slf4j
public class AliyunSmsClient extends AbstractSmsClient {
/**
* 调用成功 code
*/
public static final String API_CODE_SUCCESS = "OK";
/**
* REGION, 使用杭州
*/
private static final String ENDPOINT = "cn-hangzhou";
/**
* 阿里云客户端
*/
private volatile IAcsClient client;
public AliyunSmsClient(SmsChannelProperties properties) {
super(properties);
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
@Override
protected void doInit() {
IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
client = new DefaultAcsClient(profile);
}
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
List<KeyValue<String, Object>> templateParams) throws Throwable {
// 构建请求
SendSmsRequest request = new SendSmsRequest();
request.setPhoneNumbers(mobile);
request.setSignName(properties.getSignature());
request.setTemplateCode(apiTemplateId);
request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
request.setOutId(String.valueOf(sendLogId));
// 执行请求
SendSmsResponse response = client.getAcsResponse(request);
return new SmsSendRespDTO().setSuccess(Objects.equals(response.getCode(), API_CODE_SUCCESS)).setSerialNo(response.getBizId())
.setApiRequestId(response.getRequestId()).setApiCode(response.getCode()).setApiMsg(response.getMessage());
}
@Override
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(status.getSuccess())
.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg())
.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime())
.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())));
}
@Override
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
// 构建请求
QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
request.setTemplateCode(apiTemplateId);
// 执行请求
QuerySmsTemplateResponse response = client.getAcsResponse(request);
if (response.getTemplateStatus() == null) {
return null;
}
return new SmsTemplateRespDTO().setId(response.getTemplateCode()).setContent(response.getTemplateContent())
.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
}
@VisibleForTesting
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
switch (templateStatus) {
case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
}
}
/**
* 短信接收状态
*
* 参见 <a href="https://help.aliyun.com/document_detail/101867.html">文档</a>
*
* @author 芋道源码
*/
@Data
public static class SmsReceiveStatus {
/**
* 手机号
*/
@JsonProperty("phone_number")
private String phoneNumber;
/**
* 发送时间
*/
@JsonProperty("send_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime sendTime;
/**
* 状态报告时间
*/
@JsonProperty("report_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime reportTime;
/**
* 是否接收成功
*/
private Boolean success;
/**
* 状态报告说明
*/
@JsonProperty("err_msg")
private String errMsg;
/**
* 状态报告编码
*/
@JsonProperty("err_code")
private String errCode;
/**
* 发送序列号
*/
@JsonProperty("biz_id")
private String bizId;
/**
* 用户序列号
*
* 这里我们传递的是 SysSmsLogDO 的日志编号
*/
@JsonProperty("out_id")
private String outId;
/**
* 短信长度,例如说 1、2、3
*
* 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送
*/
@JsonProperty("sms_size")
private Integer smsSize;
}
}

View File

@@ -0,0 +1,95 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.impl;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.http.HttpUtil;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.tool.framework.common.util.collection.MapUtils;
import com.jeelowcode.tool.framework.common.util.json.JsonUtils;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsReceiveRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsSendRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsTemplateRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 基于钉钉 WebHook 实现的调试的短信客户端实现类
*
* 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。
*
* @author 芋道源码
*/
public class DebugDingTalkSmsClient extends AbstractSmsClient {
public DebugDingTalkSmsClient(SmsChannelProperties properties) {
super(properties);
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
@Override
protected void doInit() {
}
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
// 构建请求
String url = buildUrl("robot/send");
Map<String, Object> params = new HashMap<>();
params.put("msgtype", "text");
String content = String.format("【模拟短信】\n手机号%s\n短信日志编号%d\n模板参数%s",
mobile, sendLogId, MapUtils.convertMap(templateParams));
params.put("text", MapUtil.builder().put("content", content).build());
// 执行请求
String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
// 解析结果
Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
String errorCode = MapUtil.getStr(responseObj, "errcode");
return new SmsSendRespDTO().setSuccess(Objects.equals(errorCode, "0")).setSerialNo(StrUtil.uuid())
.setApiCode(errorCode).setApiMsg(MapUtil.getStr(responseObj, "errorMsg"));
}
/**
* 构建请求地址
*
* 参见 <a href="https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71">文档</a>
*
* @param path 请求路径
* @return 请求地址
*/
@SuppressWarnings("SameParameterValue")
private String buildUrl(String path) {
// 生成 timestamp
long timestamp = System.currentTimeMillis();
// 生成 sign
String secret = properties.getApiSecret();
String stringToSign = timestamp + "\n" + secret;
byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign);
String sign = Base64.encode(signData);
// 构建最终 URL
return String.format("https://oapi.dingtalk.com/%s?access_token=%s&timestamp=%d&sign=%s",
path, properties.getApiKey(), timestamp, sign);
}
@Override
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
}
@Override
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
}
}

View File

@@ -0,0 +1,87 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.impl;
import com.jeelowcode.service.system.config.framework.sms.core.client.SmsClient;
import com.jeelowcode.service.system.config.framework.sms.core.client.SmsClientFactory;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsChannelEnum;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 短信客户端工厂接口
*
* @author zzf
*/
@Validated
@Slf4j
public class SmsClientFactoryImpl implements SmsClientFactory {
/**
* 短信客户端 Map
* key渠道编号使用 {@link SmsChannelProperties#getId()}
*/
private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();
/**
* 短信客户端 Map
* key渠道编码使用 {@link SmsChannelProperties#getCode()} ()}
*
* 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。
* 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients}
*/
private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();
public SmsClientFactoryImpl() {
// 初始化 channelCodeClients 集合
Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
// 创建一个空的 SmsChannelProperties 对象
SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode())
.setApiKey("default default").setApiSecret("default");
// 创建 Sms 客户端
AbstractSmsClient smsClient = createSmsClient(properties);
channelCodeClients.put(channel.getCode(), smsClient);
});
}
@Override
public SmsClient getSmsClient(Long channelId) {
return channelIdClients.get(channelId);
}
@Override
public SmsClient getSmsClient(String channelCode) {
return channelCodeClients.get(channelCode);
}
@Override
public void createOrUpdateSmsClient(SmsChannelProperties properties) {
AbstractSmsClient client = channelIdClients.get(properties.getId());
if (client == null) {
client = this.createSmsClient(properties);
client.init();
channelIdClients.put(client.getId(), client);
} else {
client.refresh(properties);
}
}
private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
// 创建客户端
switch (channelEnum) {
case ALIYUN: return new AliyunSmsClient(properties);
case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
case TENCENT: return new TencentSmsClient(properties);
}
// 创建失败,错误日志 + 抛出异常
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
}
}

View File

@@ -0,0 +1,218 @@
package com.jeelowcode.service.system.config.framework.sms.core.client.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.tool.framework.common.util.collection.ArrayUtils;
import com.jeelowcode.tool.framework.common.util.json.JsonUtils;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsReceiveRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsSendRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.client.dto.SmsTemplateRespDTO;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import com.jeelowcode.service.system.config.framework.sms.core.property.SmsChannelProperties;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.*;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList;
import static com.jeelowcode.tool.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static com.jeelowcode.tool.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
* 腾讯云短信功能实现
*
* 参见 <a href="https://cloud.tencent.com/document/product/382/52077">文档</a>
*
* @author shiwp
*/
public class TencentSmsClient extends AbstractSmsClient {
/**
* 调用成功 code
*/
public static final String API_CODE_SUCCESS = "Ok";
/**
* REGION使用南京
*/
private static final String ENDPOINT = "ap-nanjing";
/**
* 是否国际/港澳台短信:
*
* 0表示国内短信。
* 1表示国际/港澳台短信。
*/
private static final long INTERNATIONAL_CHINA = 0L;
private SmsClient client;
public TencentSmsClient(SmsChannelProperties properties) {
super(properties);
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
validateSdkAppId(properties);
}
@Override
protected void doInit() {
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretIdsecretKey
Credential credential = new Credential(getApiKey(), properties.getApiSecret());
client = new SmsClient(credential, ENDPOINT);
}
/**
* 参数校验腾讯云的 SDK AppId
*
* 原因是:腾讯云发放短信的时候,需要额外的参数 sdkAppId
*
* 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
*
* @param properties 配置
*/
private static void validateSdkAppId(SmsChannelProperties properties) {
String combineKey = properties.getApiKey();
Assert.notEmpty(combineKey, "apiKey 不能为空");
String[] keys = combineKey.trim().split(" ");
Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]");
}
private String getSdkAppId() {
return StrUtil.subAfter(properties.getApiKey(), " ", true);
}
private String getApiKey() {
return StrUtil.subBefore(properties.getApiKey(), " ", true);
}
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
// 构建请求
SendSmsRequest request = new SendSmsRequest();
request.setSmsSdkAppId(getSdkAppId());
request.setPhoneNumberSet(new String[]{mobile});
request.setSignName(properties.getSignature());
request.setTemplateId(apiTemplateId);
request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId)));
// 执行请求
SendSmsResponse response = client.SendSms(request);
SendStatus status = response.getSendStatusSet()[0];
return new SmsSendRespDTO().setSuccess(Objects.equals(status.getCode(), API_CODE_SUCCESS)).setSerialNo(status.getSerialNo())
.setApiRequestId(response.getRequestId()).setApiCode(status.getCode()).setApiMsg(status.getMessage());
}
@Override
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return convertList(callback, status -> new SmsReceiveRespDTO()
.setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()))
.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription())
.setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime())
.setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId()));
}
@Override
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
// 构建请求
DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
request.setInternational(INTERNATIONAL_CHINA);
// 执行请求
DescribeSmsTemplateListResponse response = client.DescribeSmsTemplateList(request);
DescribeTemplateListStatus status = response.getDescribeTemplateStatusSet()[0];
if (status == null || status.getStatusCode() == null) {
return null;
}
return new SmsTemplateRespDTO().setId(status.getTemplateId().toString()).setContent(status.getTemplateContent())
.setAuditStatus(convertSmsTemplateAuditStatus(status.getStatusCode().intValue())).setAuditReason(status.getReviewReply());
}
@VisibleForTesting
Integer convertSmsTemplateAuditStatus(int templateStatus) {
switch (templateStatus) {
case 1: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
case 0: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
case -1: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
}
}
@Data
private static class SmsReceiveStatus {
/**
* 短信接受成功 code
*/
public static final String SUCCESS_CODE = "SUCCESS";
/**
* 用户实际接收到短信的时间
*/
@JsonProperty("user_receive_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime receiveTime;
/**
* 国家(或地区)码
*/
@JsonProperty("nationcode")
private String nationCode;
/**
* 手机号码
*/
private String mobile;
/**
* 实际是否收到短信接收状态SUCCESS成功、FAIL失败
*/
@JsonProperty("report_status")
private String status;
/**
* 用户接收短信状态码错误信息
*/
@JsonProperty("errmsg")
private String errCode;
/**
* 用户接收短信状态描述
*/
@JsonProperty("description")
private String description;
/**
* 本次发送标识 ID与发送接口返回的SerialNo对应
*/
@JsonProperty("sid")
private String serialNo;
/**
* 用户的 session 内容(与发送接口的请求参数 SessionContext 一致)
*/
@JsonProperty("ext")
private SessionContext sessionContext;
}
@VisibleForTesting
@Data
static class SessionContext {
/**
* 发送短信记录id
*/
private Long logId;
}
}

View File

@@ -0,0 +1,36 @@
package com.jeelowcode.service.system.config.framework.sms.core.enums;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 短信渠道枚举
*
* @author zzf
* @since 2021/1/25 10:56
*/
@Getter
@AllArgsConstructor
public enum SmsChannelEnum {
DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
ALIYUN("ALIYUN", "阿里云"),
TENCENT("TENCENT", "腾讯云"),
// HUA_WEI("HUA_WEI", "华为云"),
;
/**
* 编码
*/
private final String code;
/**
* 名字
*/
private final String name;
public static SmsChannelEnum getByCode(String code) {
return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
}
}

View File

@@ -0,0 +1,21 @@
package com.jeelowcode.service.system.config.framework.sms.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 短信模板的审核状态枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum SmsTemplateAuditStatusEnum {
CHECKING(1),
SUCCESS(2),
FAIL(3);
private final Integer status;
}

View File

@@ -0,0 +1,52 @@
package com.jeelowcode.service.system.config.framework.sms.core.property;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsChannelEnum;
import lombok.Data;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 短信渠道配置类
*
* @author zzf
* @since 2021/1/25 17:01
*/
@Data
@Validated
public class SmsChannelProperties {
/**
* 渠道编号
*/
@NotNull(message = "短信渠道 ID 不能为空")
private Long id;
/**
* 短信签名
*/
@NotEmpty(message = "短信签名不能为空")
private String signature;
/**
* 渠道编码
*
* 枚举 {@link SmsChannelEnum}
*/
@NotEmpty(message = "渠道编码不能为空")
private String code;
/**
* 短信 API 的账号
*/
@NotEmpty(message = "短信 API 的账号不能为空")
private String apiKey;
/**
* 短信 API 的密钥
*/
@NotEmpty(message = "短信 API 的密钥不能为空")
private String apiSecret;
/**
* 短信发送回调 URL
*/
private String callbackUrl;
}

View File

@@ -0,0 +1,24 @@
package com.jeelowcode.service.system.config.framework.web.config;
import com.jeelowcode.tool.framework.swagger.config.SwaggerAutoConfiguration;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* system 模块的 web 组件的 Configuration
*
* @author 芋道源码
*/
@Configuration(proxyBeanMethods = false)
public class SystemWebConfiguration {
/**
* system 模块的 API 分组
*/
@Bean
public GroupedOpenApi systemGroupedOpenApi() {
return SwaggerAutoConfiguration.buildGroupedOpenApi("system");
}
}

View File

@@ -0,0 +1,4 @@
/**
* system 模块的 web 配置
*/
package com.jeelowcode.service.system.config.framework.web;

View File

@@ -0,0 +1,21 @@
package com.jeelowcode.service.system.config.handler;
import com.jeelowcode.service.system.entity.TenantDO;
/**
* 租户信息处理
* 目的:尽量减少租户逻辑耦合到系统中
*
* @author 芋道源码
*/
public interface TenantInfoHandler {
/**
* 基于传入的租户信息,进行相关逻辑的执行
* 例如说,创建用户时,超过最大账户配额
*
* @param tenant 租户信息
*/
void handle(TenantDO tenant);
}

View File

@@ -0,0 +1,21 @@
package com.jeelowcode.service.system.config.handler;
import java.util.Set;
/**
* 租户菜单处理
* 目的:尽量减少租户逻辑耦合到系统中
*
* @author 芋道源码
*/
public interface TenantMenuHandler {
/**
* 基于传入的租户菜单【全】列表,进行相关逻辑的执行
* 例如说,返回可分配菜单的时候,可以移除多余的
*
* @param menuIds 菜单列表
*/
void handle(Set<Long> menuIds);
}

View File

@@ -0,0 +1,27 @@
package com.jeelowcode.service.system.config.job;
import com.jeelowcode.tool.framework.quartz.core.handler.JobHandler;
import com.jeelowcode.tool.framework.tenant.core.context.TenantContextHolder;
import com.jeelowcode.tool.framework.tenant.core.job.TenantJob;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.mapper.AdminUserMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
public class DemoJob implements JobHandler {
@Resource
private AdminUserMapper adminUserMapper;
@Override
@TenantJob // 标记多租户
public String execute(String param) {
System.out.println("当前租户:" + TenantContextHolder.getTenantId());
List<AdminUserDO> users = adminUserMapper.selectList();
return "用户数量:" + users.size();
}
}

View File

@@ -0,0 +1 @@
package com.jeelowcode.service.system.config.job;

View File

@@ -0,0 +1,31 @@
package com.jeelowcode.service.system.config.mq.consumer.mail;
import com.jeelowcode.service.system.config.mq.message.mail.MailSendMessage;
import com.jeelowcode.service.system.service.IMailSendService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 针对 {@link MailSendMessage} 的消费者
*
* @author 芋道源码
*/
@Component
@Slf4j
public class MailSendConsumer {
@Resource
private IMailSendService mailSendService;
@EventListener
@Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
public void onMessage(MailSendMessage message) {
log.info("[onMessage][消息内容({})]", message);
mailSendService.doSendMail(message);
}
}

View File

@@ -0,0 +1,31 @@
package com.jeelowcode.service.system.config.mq.consumer.sms;
import com.jeelowcode.service.system.config.mq.message.sms.SmsSendMessage;
import com.jeelowcode.service.system.service.ISmsSendService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 针对 {@link SmsSendMessage} 的消费者
*
* @author zzf
*/
@Component
@Slf4j
public class SmsSendConsumer {
@Resource
private ISmsSendService smsSendService;
@EventListener
@Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
public void onMessage(SmsSendMessage message) {
log.info("[onMessage][消息内容({})]", message);
smsSendService.doSendSms(message);
}
}

View File

@@ -0,0 +1,47 @@
package com.jeelowcode.service.system.config.mq.message.mail;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 邮箱发送消息
*
* @author 芋道源码
*/
@Data
public class MailSendMessage {
/**
* 邮件日志编号
*/
@NotNull(message = "邮件日志编号不能为空")
private Long logId;
/**
* 接收邮件地址
*/
@NotNull(message = "接收邮件地址不能为空")
private String mail;
/**
* 邮件账号编号
*/
@NotNull(message = "邮件账号编号不能为空")
private Long accountId;
/**
* 邮件发件人
*/
private String nickname;
/**
* 邮件标题
*/
@NotEmpty(message = "邮件标题不能为空")
private String title;
/**
* 邮件内容
*/
@NotEmpty(message = "邮件内容不能为空")
private String content;
}

View File

@@ -0,0 +1,42 @@
package com.jeelowcode.service.system.config.mq.message.sms;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 短信发送消息
*
* @author 芋道源码
*/
@Data
public class SmsSendMessage {
/**
* 短信日志编号
*/
@NotNull(message = "短信日志编号不能为空")
private Long logId;
/**
* 手机号
*/
@NotNull(message = "手机号不能为空")
private String mobile;
/**
* 短信渠道编号
*/
@NotNull(message = "短信渠道编号不能为空")
private Long channelId;
/**
* 短信 API 的模板编号
*/
@NotNull(message = "短信 API 的模板编号不能为空")
private String apiTemplateId;
/**
* 短信模板参数
*/
private List<KeyValue<String, Object>> templateParams;
}

View File

@@ -0,0 +1,41 @@
package com.jeelowcode.service.system.config.mq.producer.mail;
import com.jeelowcode.service.system.config.mq.message.mail.MailSendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Mail 邮件相关消息的 Producer
*
* @author wangjingyi
* @since 2021/4/19 13:33
*/
@Slf4j
@Component
public class MailProducer {
@Resource
private ApplicationContext applicationContext;
/**
* 发送 {@link MailSendMessage} 消息
*
* @param sendLogId 发送日志编码
* @param mail 接收邮件地址
* @param accountId 邮件账号编号
* @param nickname 邮件发件人
* @param title 邮件标题
* @param content 邮件内容
*/
public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
String nickname, String title, String content) {
MailSendMessage message = new MailSendMessage()
.setLogId(sendLogId).setMail(mail).setAccountId(accountId)
.setNickname(nickname).setTitle(title).setContent(content);
applicationContext.publishEvent(message);
}
}

View File

@@ -0,0 +1,41 @@
package com.jeelowcode.service.system.config.mq.producer.sms;
import com.jeelowcode.tool.framework.common.core.KeyValue;
import com.jeelowcode.service.system.config.mq.message.sms.SmsSendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* Sms 短信相关消息的 Producer
*
* @author zzf
* @since 2021/3/9 16:35
*/
@Slf4j
@Component
public class SmsProducer {
@Resource
private ApplicationContext applicationContext;
/**
* 发送 {@link SmsSendMessage} 消息
*
* @param logId 短信日志编号
* @param mobile 手机号
* @param channelId 渠道编号
* @param apiTemplateId 短信模板编号
* @param templateParams 短信模板参数
*/
public void sendSmsSendMessage(Long logId, String mobile,
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile);
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
applicationContext.publishEvent(message);
}
}

View File

@@ -0,0 +1,101 @@
package com.jeelowcode.service.system.config.redis;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
/**
* System Redis Key 枚举类
*
* @author 芋道源码
*/
public interface RedisKeyConstants {
/**
* 指定部门的所有子部门编号数组的缓存
* <p>
* KEY 格式dept_children_ids:{id}
* VALUE 数据类型String 子部门编号集合
*/
String DEPT_CHILDREN_ID_LIST = "dept_children_ids";
/**
* 角色的缓存
* <p>
* KEY 格式role:{id}
* VALUE 数据类型String 角色信息
*/
String ROLE = "role";
/**
* 用户拥有的角色编号的缓存
* <p>
* KEY 格式user_role_ids:{userId}
* VALUE 数据类型String 角色编号集合
*/
String USER_ROLE_ID_LIST = "user_role_ids";
/**
* 拥有指定菜单的角色编号的缓存
* <p>
* KEY 格式user_role_ids:{menuId}
* VALUE 数据类型String 角色编号集合
*/
String MENU_ROLE_ID_LIST = "menu_role_ids";
/**
* 拥有权限对应的菜单编号数组的缓存
* <p>
* KEY 格式permission_menu_ids:{permission}
* VALUE 数据类型String 菜单编号数组
*/
String PERMISSION_MENU_ID_LIST = "permission_menu_ids";
/**
* OAuth2 客户端的缓存
* <p>
* KEY 格式user:{id}
* VALUE 数据类型String 客户端信息
*/
String OAUTH_CLIENT = "oauth_client";
/**
* 访问令牌的缓存
* <p>
* KEY 格式oauth2_access_token:{token}
* VALUE 数据类型String 访问令牌信息 {@link OAuth2AccessTokenDO}
* <p>
* 由于动态过期时间,使用 RedisTemplate 操作
*/
String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s";
/**
* 站内信模版的缓存
* <p>
* KEY 格式notify_template:{code}
* VALUE 数据格式String 模版信息
*/
String NOTIFY_TEMPLATE = "notify_template";
/**
* 邮件账号的缓存
* <p>
* KEY 格式sms_template:{id}
* VALUE 数据格式String 账号信息
*/
String MAIL_ACCOUNT = "mail_account";
/**
* 邮件模版的缓存
* <p>
* KEY 格式mail_template:{code}
* VALUE 数据格式String 模版信息
*/
String MAIL_TEMPLATE = "mail_template";
/**
* 短信模版的缓存
* <p>
* KEY 格式sms_template:{id}
* VALUE 数据格式String 模版信息
*/
String SMS_TEMPLATE = "sms_template";
}

View File

@@ -0,0 +1,59 @@
package com.jeelowcode.service.system.config.redis.oauth2;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.jeelowcode.tool.framework.common.util.collection.CollectionUtils;
import com.jeelowcode.tool.framework.common.util.json.JsonUtils;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.jeelowcode.service.system.config.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
/**
* {@link OAuth2AccessTokenDO} 的 RedisDAO
*
* @author 芋道源码
*/
@Repository
public class OAuth2AccessTokenRedisDAO {
@Resource
private StringRedisTemplate stringRedisTemplate;
public OAuth2AccessTokenDO get(String accessToken) {
String redisKey = formatKey(accessToken);
return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class);
}
public void set(OAuth2AccessTokenDO accessTokenDO) {
String redisKey = formatKey(accessTokenDO.getAccessToken());
// 清理多余字段,避免缓存
accessTokenDO.setUpdater(null).setUpdateTime(null).setCreateTime(null).setCreator(null).setDeleted(null);
long time = LocalDateTimeUtil.between(LocalDateTime.now(), accessTokenDO.getExpiresTime(), ChronoUnit.SECONDS);
if (time > 0) {
stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(accessTokenDO), time, TimeUnit.SECONDS);
}
}
public void delete(String accessToken) {
String redisKey = formatKey(accessToken);
stringRedisTemplate.delete(redisKey);
}
public void deleteList(Collection<String> accessTokens) {
List<String> redisKeys = CollectionUtils.convertList(accessTokens, OAuth2AccessTokenRedisDAO::formatKey);
stringRedisTemplate.delete(redisKeys);
}
private static String formatKey(String accessToken) {
return String.format(OAUTH2_ACCESS_TOKEN, accessToken);
}
}

View File

@@ -0,0 +1,119 @@
package com.jeelowcode.service.system.config.social;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.jeelowcode.service.system.util.SshUtils;
import com.xingyuv.jushauth.cache.AuthStateCache;
import com.xingyuv.jushauth.config.AuthConfig;
import com.xingyuv.jushauth.config.AuthSource;
import com.xingyuv.jushauth.exception.AuthException;
import com.xingyuv.jushauth.model.AuthCallback;
import com.xingyuv.jushauth.model.AuthToken;
import com.xingyuv.jushauth.model.AuthUser;
import com.xingyuv.jushauth.request.AuthDefaultRequest;
import lombok.extern.slf4j.Slf4j;
/**
* Description: 中国星网认证
* Author: JeeLow
* Date: 2021/11/23 16:05
*/
@Slf4j
public class ChinaSatelliteAuthRequest extends AuthDefaultRequest {
/**
* 构造函数
*
* @param config 配置
* @param source 源
*/
public ChinaSatelliteAuthRequest(AuthConfig config, AuthSource source) {
super(config, ChinaSatelliteAuthSource.CHINA_SATELLITE_NET);
}
/**
* 构造函数
*
* @param config 配置
* @param authStateCache 缓存
*/
public ChinaSatelliteAuthRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, ChinaSatelliteAuthSource.CHINA_SATELLITE_NET, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
// 1.首先使用授权码获取token
String responseStr = doPostAuthorizationCode(authCallback.getCode());
JSONObject responseObj = JSONObject.parseObject(responseStr);
// 2.检查响应结果是否包含错误信息
this.checkResponse(responseObj);
// 3.解析响应结果获取token信息
return AuthToken.builder()
.accessToken(responseObj.getString("access_token"))
.refreshToken(responseObj.getString("refresh_token"))
.expireIn(responseObj.getInteger("expires_in"))
.tokenType(responseObj.getString("token_type"))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
// 1.使用token获取用户信息
String responseStr = doGetUserInfo(authToken);
JSONObject responseObj = JSONObject.parseObject(responseStr);
// 2.检查响应结果是否包含错误信息
this.checkResponse(responseObj);
// 3.解析响应结果,获取用户信息
JSONObject result = responseObj.getJSONObject("result");
Assert.notNull(result, () -> new AuthException("响应结果 result 不能为空"));
return AuthUser.builder()
.uuid(result.getString("id"))
.nickname(result.getString("displayName"))
.rawUserInfo(result)
.token(authToken)
.build();
}
/**
* 检查响应结果是否包含错误信息
*
* @param response 响应结果
*/
private void checkResponse(JSONObject response) {
if (response.containsKey("error")) {
throw new AuthException(response.getString("error"));
}
}
@Override
protected String doPostAuthorizationCode(String code) {
try {
return HttpRequest.post(this.accessTokenUrl(code))
.setSSLSocketFactory(SshUtils.createTrustAllSSLFactory())
.execute().body();
} catch (Exception e) {
log.error("[getAccessToken][code({}) 获取token失败]", code, e);
throw new AuthException("获取token失败");
}
}
@Override
protected String doGetUserInfo(AuthToken authToken) {
try {
return HttpRequest.get(this.userInfoUrl(authToken))
.header("Authorization", authToken.getAccessToken())
.setSSLSocketFactory(SshUtils.createTrustAllSSLFactory())
.execute().body();
} catch (Exception e) {
log.error("[getUserInfo][accessToken({}) 获取用户信息失败]", authToken.getAccessToken(), e);
throw new AuthException("获取用户信息失败");
}
}
}

View File

@@ -0,0 +1,54 @@
package com.jeelowcode.service.system.config.social;
import cn.hutool.extra.spring.SpringUtil;
import com.xingyuv.jushauth.config.AuthSource;
import com.xingyuv.jushauth.request.AuthDefaultRequest;
/**
* 中国星网办公网认证源
* <p>
* author: shelly chan
* date: 2025/09/19
*/
public enum ChinaSatelliteAuthSource implements AuthSource {
/**
* 获取认证授权地址
*/
CHINA_SATELLITE_NET {
@Override
public String authorize() {
String profile = SpringUtil.getActiveProfile();
if ("test".equals(profile)) {
return "https://sso-sy.chinasatnet.com.cn/authn-api/v5/oauth/authorize";
}
// 默认返回生产环境地址
return "https://sso-new.chinasatnet.com.cn/authn-api/v5/oauth/authorize";
}
@Override
public String accessToken() {
String profile = SpringUtil.getActiveProfile();
if ("test".equals(profile)) {
return "https://sso-sy.chinasatnet.com.cn/authn-api/v5/oauth/token";
}
return "https://sso-new.chinasatnet.com.cn/authn-api/v5/oauth/token";
}
@Override
public String userInfo() {
String profile = SpringUtil.getActiveProfile();
if ("test".equals(profile)) {
return "https://sso-sy.chinasatnet.com.cn/authn-api/v5/oauth/user-info";
}
return "https://sso-new.chinasatnet.com.cn/authn-api/v5/oauth/user-info";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return ChinaSatelliteAuthRequest.class;
}
};
}

View File

@@ -0,0 +1,87 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.ip.core.Area;
import com.jeelowcode.tool.framework.ip.core.utils.AreaUtils;
import com.jeelowcode.tool.framework.ip.core.utils.IPUtils;
import com.jeelowcode.service.system.controller.vo.ip.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.*;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 地区")
@RestController
@RequestMapping("/system/area")
@Validated
public class AreaController {
@GetMapping("/tree")
@Operation(tags = "地区管理",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(tags = "地区管理",summary = "获得 IP 对应的地区名")
@Parameter(name = "ip", description = "IP", required = true)
public CommonResult<String> getAreaByIp(
@Valid
@Pattern(regexp = "^(?:(\\\\d{1,2}|1\\\\d{2}|2[0-4]\\\\d|25[0-5])\\\\.){3}(\\\\d{1,2}|1\\\\d{2}|2[0-4]\\\\d|25[0-5])$", message = "ip格式不正确")
@RequestParam("ip")
String ip) {
// 获得城市
Area area = IPUtils.getArea(ip);
if (area == null) {
return success("未知");
}
// 格式化返回
return success(AreaUtils.format(area.getId()));
}
//------------------ jeelowcode --------------------
@GetMapping("/tree-by-id")
@Operation(tags = "地区管理",summary = "获得地区树")
public CommonResult<List<AreaNodeRespVO>> getAreaTreeById(Integer pid) {
Area area = AreaUtils.getArea(pid);
Assert.notNull(area, "获取不到中国");
List<AreaNodeRespVO> resultList=new ArrayList<>();
List<Area> children = area.getChildren();
for(Area areaTmp:children){
AreaNodeRespVO areaVo=new AreaNodeRespVO();
areaVo.setId(areaTmp.getId());
areaVo.setName(areaTmp.getName());
areaVo.setLeaf(CollectionUtil.isEmpty(areaTmp.getChildren()));
resultList.add(areaVo);
}
return success(resultList);
}
@PostMapping("/view-parent-list")
@Operation(tags = "地区管理",summary = "获取所有父级")
public CommonResult<Map<Integer,List<AreaNodeRespVO>>> viewParentList(@RequestBody List<Integer> idList) {
Map<Integer,List<AreaNodeRespVO>> resultMap=new HashMap<>();
for(Integer id:idList){
List<Area> areaList = AreaUtils.getAllParentList(id);
resultMap.put(id,BeanUtils.toBean(areaList, AreaNodeRespVO.class));
}
return success(resultMap);
}
}

View File

@@ -0,0 +1,294 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.service.system.config.convert.auth.AuthConvert;
import com.jeelowcode.service.system.constant.ErrorCodeConstants;
import com.jeelowcode.service.system.controller.vo.auth.*;
import com.jeelowcode.service.system.controller.vo.user.user.UserRespVO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.entity.MenuDO;
import com.jeelowcode.service.system.entity.RoleDO;
import com.jeelowcode.service.system.entity.UserRoleDO;
import com.jeelowcode.service.system.enums.LoginLogTypeEnum;
import com.jeelowcode.service.system.service.*;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.collection.CollectionUtils;
import com.jeelowcode.tool.framework.common.util.string.StrUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.tool.framework.security.config.SecurityProperties;
import com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils;
import com.jeelowcode.tool.framework.tenant.core.context.TenantContextHolder;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertSet;
import static com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils.*;
@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {
@Resource
private IAdminAuthService authService;
@Resource
private IAdminUserService userService;
@Resource
private IRoleService roleService;
@Resource
private IMenuService menuService;
@Resource
private IPermissionService permissionService;
@Resource
private ISocialClientService socialClientService;
@Resource
private SecurityProperties securityProperties;
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/login")
@PermitAll
@Operation(tags = "授权管理",summary = "使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
}
@PostMapping("/logout")
@PermitAll
@Operation(tags = "授权管理",summary = "登出系统")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> logout(HttpServletRequest request) {
logoutService(request);
return success(true);
}
@PostMapping("/switch-login")
@Operation(tags = "授权管理",summary = "切换部门登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> switchLogin(@RequestBody SwitchLoginReqVO reqVO, HttpServletRequest request) {
//先退出登录 ,然后再重新登录
Long loginUserId = getLoginUserId();
Long loginDeptId = reqVO.getLoginDeptId();
Long loginRoleId = reqVO.getLoginRoleId();
if(loginDeptId==null){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_DEPT_NULL);
}
if(loginRoleId==null){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_ROLE_NULL);
}
//获取该部门下的角色
AdminUserDO user = userService.getUser(loginUserId);
String deptIdsStr = user.getDeptId();
if (StrUtil.isEmpty(deptIdsStr)) {
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_BIND_DEPT_NULL);
}
Set<Long> deptId = StrUtils.str2setLong(user.getDeptId());
if(CollectionUtil.isEmpty(deptId)){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_BIND_DEPT_NULL);
}
if(loginDeptId!=-1 && !deptId.contains(loginDeptId)){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_NOTIN_DEPT);
}
//判断该角色
List<UserRoleDO> userRoleList = userService.getUserRoleList(user.getId(), loginDeptId);
if(CollectionUtil.isEmpty(userRoleList)){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_NOTIN_ROLE);
}
Map<Long, UserRoleDO> userRoleMap = CollectionUtils.convertMap(userRoleList, UserRoleDO::getRoleId);
if(loginRoleId!=-1 && !userRoleMap.containsKey(loginRoleId)){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_NOTIN_ROLE);
}
//校验通过
//1.先退出旧的
logoutService(request);
//2.重新登录
AuthLoginRespVO vo = authService.switchLogin(user.getId(), loginDeptId, loginRoleId);
return success(vo);
}
@PostMapping("/switch-tenant")
@Operation(tags = "授权管理",summary = "切换租户登录(只允许超级管理员操作)")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> switchTenant(@RequestBody SwitchTenantReqVO reqVO, HttpServletRequest request) {
Long tenantId = reqVO.getTenantId();
boolean supAdminToken = isSupAdmin();
if(!supAdminToken){
return CommonResult.error(ErrorCodeConstants.AUTH_SWITCH_LOGIN_USER_ISNOT_SUPADMIN);
}
//1.先退出旧的
logoutService(request);
//当前是超级管理员 -> 登录到当前租户下的管理
TenantContextHolder.setTenantId(tenantId);
AuthLoginRespVO vo = authService.supAdminSwitchTenantLogin(tenantId,true);
return success(vo);
}
@PostMapping("/refresh-token")
@PermitAll
@Operation(tags = "授权管理",summary = "刷新令牌")
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@Operation(tags = "授权管理",summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
// 1.1 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
AuthPermissionInfoRespVO vo = new AuthPermissionInfoRespVO();
return CommonResult.success(vo);
}
boolean supAdminFlag = userService.isSupAdmin(user.getId());//是否是超级管理员
boolean tenantAdminFlag = userService.isTenantAdmin(user.getId());//是否是租户管理员
//获取当前登录部门和角色
Long loginDeptId = getLoginDeptId();
Long loginRoleId = getLoginRoleId();
//获取所有按钮权限
Set<String> allButtonPermissionSets = menuService.getAllButtonPermissionSets();
// 1.2 获得角色列表
Set<Long> roleIds =new HashSet<>();
if(supAdminFlag || tenantAdminFlag){//超级管理员 或者租户管理员,直接查自身的所有权限
roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
}else{
if(loginRoleId!=null){//当前登录有角色
if(loginRoleId==-1){//该部门下的所有角色
List<UserRoleDO> userRoleList = userService.getUserRoleList(user.getId(), loginDeptId);
roleIds = userRoleList.stream()
.map(UserRoleDO::getRoleId)
.collect(Collectors.toSet());
}else{
roleIds.add(loginRoleId);
}
}
}
if (CollUtil.isEmpty(roleIds)) {
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList(),allButtonPermissionSets));
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = new ArrayList<>();
if (!CollUtil.isEmpty(menuIds)) {
menuList = menuService.getMenuList(menuIds);
menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
}
Set<Long> deptId = StrUtils.str2setLong(user.getDeptId());
//部门角色信息
List<UserRespVO.DeptInfo> deptInfoList = userService.getDeptInfo(user.getId(), deptId);
// 2. 拼接结果返回
AuthPermissionInfoRespVO vo = AuthConvert.INSTANCE.convert(user, roles, menuList, allButtonPermissionSets);
Map<String, List<String>> jeeLowCodeButtonPermissionMap = menuService.getJeeLowCodeButtonPermissionMap(vo.getPermissions());
vo.setJeeLowCodepermissions(jeeLowCodeButtonPermissionMap);
vo.setDeptInfoList(deptInfoList);
AuthPermissionInfoRespVO.UserVO userVo = vo.getUser();
userVo.setLoginDeptId(loginDeptId);
userVo.setLoginRoleId(loginRoleId);
userVo.setSupAdmin(supAdminFlag);//是否是超级管理员
userVo.setTenantAdmin(tenantAdminFlag);//是否是租户管理员
userVo.setSupAdminToken(SecurityFrameworkUtils.isSupAdmin());
return success(vo);
}
// ========== 短信登录相关 ==========
@PostMapping("/sms-login")
@PermitAll
@Operation(tags = "授权管理",summary = "使用短信验证码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
return success(authService.smsLogin(reqVO));
}
@PostMapping("/send-sms-code")
@PermitAll
@Operation(tags = "授权管理",summary = "发送手机验证码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
authService.sendSmsCode(reqVO);
return success(true);
}
// ========== 社交登录相关 ==========
@GetMapping("/social-auth-redirect")
@PermitAll
@Operation(tags = "授权管理",summary = "社交授权的跳转")
@Parameters({
@Parameter(name = "type", description = "社交类型", required = true),
@Parameter(name = "redirectUri", description = "回调路径")
})
public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri) {
return success(socialClientService.getAuthorizeUrl(
type, UserTypeEnum.ADMIN.getValue(), redirectUri));
}
@PostMapping("/social-login")
@PermitAll
@Operation(tags = "授权管理",summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
return success(authService.socialLogin(reqVO));
}
//退出登录
private void logoutService(HttpServletRequest request){
Long loginUserId = getLoginUserId();
String token = SecurityFrameworkUtils.obtainAuthorization(request,
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
//清空个人信息
String userRedisKey="JEE_LOW_CODE:USER:"+loginUserId+":*";
Set<String> keys = stringRedisTemplate.keys(userRedisKey);
if(keys!=null && keys.size()>0){
keys.forEach(key->{
stringRedisTemplate.delete(key);
});
}
}
}

View File

@@ -0,0 +1,56 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.util.StrUtil;
import com.jeelowcode.tool.framework.common.util.servlet.ServletUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
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;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
@Tag(name = "管理后台 - 验证码")
@RestController("adminCaptchaController")
@RequestMapping("/system/captcha")
public class CaptchaController {
@Resource
private CaptchaService captchaService;
@PostMapping({"/get"})
@Operation(tags = "验证码管理",summary = "获得验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
assert request.getRemoteHost() != null;
data.setBrowserInfo(getRemoteId(request));
return captchaService.get(data);
}
@PostMapping("/check")
@Operation(tags = "验证码管理",summary = "校验验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
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;
}
}

View File

@@ -0,0 +1,95 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.dept.dept.DeptListReqVO;
import com.jeelowcode.service.system.controller.vo.dept.dept.DeptRespVO;
import com.jeelowcode.service.system.controller.vo.dept.dept.DeptSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dept.dept.DeptSimpleRespVO;
import com.jeelowcode.service.system.entity.DeptDO;
import com.jeelowcode.service.system.service.IDeptService;
import com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils;
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 javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import java.util.List;
import java.util.Objects;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 部门")
@RestController
@RequestMapping("/system/dept")
@Validated
public class DeptController {
@Resource
private IDeptService deptService;
@PostMapping("create")
@Operation(tags = "部门管理", 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(tags = "部门管理", summary = "更新部门")
@PreAuthorize("@ss.hasPermission('system:dept:update')")
public CommonResult<Boolean> updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) {
deptService.updateDept(updateReqVO);
return success(true);
}
@DeleteMapping("delete")
@Operation(tags = "部门管理", 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);
}
@GetMapping("/list")
@Operation(tags = "部门管理", 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(tags = "部门管理", 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(tags = "部门管理", 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));
}
@GetMapping("/get-user-company")
@Operation(tags = "部门管理", summary = "获得用户所在部门的公司部门")
public CommonResult<DeptRespVO> getUserCompany() {
Long loginDeptId = Objects.requireNonNull(SecurityFrameworkUtils.getLoginDeptId());
DeptDO dept = deptService.getCompanyDept(loginDeptId);
return success(BeanUtils.toBean(dept, DeptRespVO.class));
}
}

View File

@@ -0,0 +1,104 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dict.data.DictDataPageReqVO;
import com.jeelowcode.service.system.controller.vo.dict.data.DictDataRespVO;
import com.jeelowcode.service.system.controller.vo.dict.data.DictDataSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dict.data.DictDataSimpleRespVO;
import com.jeelowcode.service.system.entity.DictDataDO;
import com.jeelowcode.service.system.service.IDictDataService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 字典数据")
@RestController
@RequestMapping("/system/dict-data")
@Validated
public class DictDataController {
@Resource
private IDictDataService dictDataService;
@PostMapping("/create")
@Operation(tags = "字典管理",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(tags = "字典管理",summary = "修改字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictData(@Valid @RequestBody DictDataSaveReqVO updateReqVO) {
dictDataService.updateDictData(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "字典管理",summary = "删除字典数据")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictData(Long id) {
dictDataService.deleteDictData(id);
return success(true);
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(tags = "字典管理",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(tags = "字典管理",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(tags = "字典管理",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")
@Operation(tags = "字典管理",summary = "导出字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:export')")
@OperateLog(type = 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));
}
}

View File

@@ -0,0 +1,102 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dict.type.DictTypePageReqVO;
import com.jeelowcode.service.system.controller.vo.dict.type.DictTypeRespVO;
import com.jeelowcode.service.system.controller.vo.dict.type.DictTypeSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dict.type.DictTypeSimpleRespVO;
import com.jeelowcode.service.system.entity.DictTypeDO;
import com.jeelowcode.service.system.service.IDictTypeService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 字典类型")
@RestController
@RequestMapping("/system/dict-type")
@Validated
public class DictTypeController {
@Resource
private IDictTypeService dictTypeService;
@PostMapping("/create")
@Operation(tags = "字典管理",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(tags = "字典管理",summary = "修改字典类型")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictType(@Valid @RequestBody DictTypeSaveReqVO updateReqVO) {
dictTypeService.updateDictType(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "字典管理",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);
}
@GetMapping("/page")
@Operation(tags = "字典管理",summary = "获得字典类型的分页列表")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictTypeRespVO>> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) {
PageResult<DictTypeDO> pageResult = dictTypeService.getDictTypePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class));
}
@Operation(tags = "字典管理",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(tags = "字典管理",summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
// 无需添加权限认证,因为前端全局都需要
public CommonResult<List<DictTypeSimpleRespVO>> getSimpleDictTypeList() {
List<DictTypeDO> list = dictTypeService.getDictTypeList();
return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class));
}
@Operation(tags = "字典管理",summary = "导出数据类型")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
@OperateLog(type = 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));
}
}

View File

@@ -0,0 +1,106 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dept.duty.DutyPageReqVO;
import com.jeelowcode.service.system.controller.vo.dept.duty.DutyRespVO;
import com.jeelowcode.service.system.controller.vo.dept.duty.DutySaveReqVO;
import com.jeelowcode.service.system.controller.vo.dept.duty.DutySimpleRespVO;
import com.jeelowcode.service.system.entity.DutyDO;
import com.jeelowcode.service.system.service.IDutyService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 职务")
@RestController
@RequestMapping("/system/duty")
@Validated
public class DutyController {
@Resource
private IDutyService dutyService;
@PostMapping("/create")
@Operation(tags = "职务管理",summary = "创建职务")
@PreAuthorize("@ss.hasPermission('system:duty:create')")
public CommonResult<Long> create(@Valid @RequestBody DutySaveReqVO createReqVO) {
Long id = dutyService.createDuty(createReqVO);
return success(id);
}
@PutMapping("/update")
@Operation(tags = "职务管理",summary = "修改职务")
@PreAuthorize("@ss.hasPermission('system:duty:update')")
public CommonResult<Boolean> update(@Valid @RequestBody DutySaveReqVO updateReqVO) {
dutyService.updateDuty(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "职务管理",summary = "删除职务")
@PreAuthorize("@ss.hasPermission('system:duty:delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
dutyService.deleteDuty(id);
return success(true);
}
@GetMapping(value = "/get")
@Operation(tags = "职务管理",summary = "获得职务信息")
@Parameter(name = "id", description = "职务编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:duty:query')")
public CommonResult<DutyRespVO> get(@RequestParam("id") Long id) {
DutyDO duty = dutyService.getDuty(id);
return success(BeanUtils.toBean(duty, DutyRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(tags = "职务管理",summary = "获取职务全列表", description = "只包含被开启的职务,主要用于前端的下拉选项")
public CommonResult<List<DutySimpleRespVO>> getSimpleList() {
// 获得职务列表,只要开启状态的
List<DutyDO> list = dutyService.getDutyList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(DutyDO::getSort));
return success(BeanUtils.toBean(list, DutySimpleRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "职务管理",summary = "获得职务分页列表")
@PreAuthorize("@ss.hasPermission('system:duty:query')")
public CommonResult<PageResult<DutyRespVO>> getPage(@Validated DutyPageReqVO pageReqVO) {
PageResult<DutyDO> pageResult = dutyService.getDutyPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DutyRespVO.class));
}
@GetMapping("/export")
@Operation(tags = "职务管理",summary = "职务管理")
@PreAuthorize("@ss.hasPermission('system:duty:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated DutyPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DutyDO> list = dutyService.getDutyPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "职务数据.xls", "职务列表", DutyRespVO.class,
BeanUtils.toBean(list, DutyRespVO.class));
}
}

View File

@@ -0,0 +1,93 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.errorcode.ErrorCodePageReqVO;
import com.jeelowcode.service.system.controller.vo.errorcode.ErrorCodeRespVO;
import com.jeelowcode.service.system.controller.vo.errorcode.ErrorCodeSaveReqVO;
import com.jeelowcode.service.system.entity.ErrorCodeDO;
import com.jeelowcode.service.system.service.IErrorCodeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 错误码")
@RestController
@RequestMapping("/system/error-code")
@Validated
public class ErrorCodeController {
@Resource
private IErrorCodeService errorCodeService;
@PostMapping("/create")
@Operation(tags = "错误码管理",summary = "创建错误码")
@PreAuthorize("@ss.hasPermission('system:error-code:create')")
public CommonResult<Long> createErrorCode(@Valid @RequestBody ErrorCodeSaveReqVO createReqVO) {
return success(errorCodeService.createErrorCode(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "错误码管理",summary = "更新错误码")
@PreAuthorize("@ss.hasPermission('system:error-code:update')")
public CommonResult<Boolean> updateErrorCode(@Valid @RequestBody ErrorCodeSaveReqVO updateReqVO) {
errorCodeService.updateErrorCode(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "错误码管理",summary = "删除错误码")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:error-code:delete')")
public CommonResult<Boolean> deleteErrorCode(@RequestParam("id") Long id) {
errorCodeService.deleteErrorCode(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "错误码管理",summary = "获得错误码")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:error-code:query')")
public CommonResult<ErrorCodeRespVO> getErrorCode(@RequestParam("id") Long id) {
ErrorCodeDO errorCode = errorCodeService.getErrorCode(id);
return success(BeanUtils.toBean(errorCode, ErrorCodeRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "错误码管理",summary = "获得错误码分页")
@PreAuthorize("@ss.hasPermission('system:error-code:query')")
public CommonResult<PageResult<ErrorCodeRespVO>> getErrorCodePage(@Valid ErrorCodePageReqVO pageVO) {
PageResult<ErrorCodeDO> pageResult = errorCodeService.getErrorCodePage(pageVO);
return success(BeanUtils.toBean(pageResult, ErrorCodeRespVO.class));
}
@GetMapping("/export-excel")
@Operation(tags = "错误码管理",summary = "导出错误码 Excel")
@PreAuthorize("@ss.hasPermission('system:error-code:export')")
@OperateLog(type = EXPORT)
public void exportErrorCodeExcel(@Valid ErrorCodePageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ErrorCodeDO> list = errorCodeService.getErrorCodePage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "错误码.xls", "数据", ErrorCodeRespVO.class,
BeanUtils.toBean(list, ErrorCodeRespVO.class));
}
}

View File

@@ -0,0 +1,59 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.logger.loginlog.LoginLogPageReqVO;
import com.jeelowcode.service.system.controller.vo.logger.loginlog.LoginLogRespVO;
import com.jeelowcode.service.system.entity.LoginLogDO;
import com.jeelowcode.service.system.service.ILoginLogService;
import io.swagger.v3.oas.annotations.Operation;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 登录日志")
@RestController
@RequestMapping("/system/login-log")
@Validated
public class LoginLogController {
@Resource
private ILoginLogService loginLogService;
@GetMapping("/page")
@Operation(tags = "审查日志",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")
@Operation(tags = "审查日志",summary = "导出登录日志 Excel")
@PreAuthorize("@ss.hasPermission('system:login-log:export')")
@OperateLog(type = 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));
}
}

View File

@@ -0,0 +1,81 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.mail.account.MailAccountPageReqVO;
import com.jeelowcode.service.system.controller.vo.mail.account.MailAccountRespVO;
import com.jeelowcode.service.system.controller.vo.mail.account.MailAccountSaveReqVO;
import com.jeelowcode.service.system.controller.vo.mail.account.MailAccountSimpleRespVO;
import com.jeelowcode.service.system.entity.MailAccountDO;
import com.jeelowcode.service.system.service.IMailAccountService;
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.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮箱账号")
@RestController
@RequestMapping("/system/mail-account")
public class MailAccountController {
@Resource
private IMailAccountService mailAccountService;
@PostMapping("/create")
@Operation(tags = "邮箱管理",summary = "创建邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:create')")
public CommonResult<Long> createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) {
return success(mailAccountService.createMailAccount(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "邮箱管理",summary = "修改邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:update')")
public CommonResult<Boolean> updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) {
mailAccountService.updateMailAccount(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "邮箱管理",summary = "删除邮箱账号")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
public CommonResult<Boolean> deleteMailAccount(@RequestParam Long id) {
mailAccountService.deleteMailAccount(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "邮箱管理",summary = "获得邮箱账号")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-account:get')")
public CommonResult<MailAccountRespVO> getMailAccount(@RequestParam("id") Long id) {
MailAccountDO account = mailAccountService.getMailAccount(id);
return success(BeanUtils.toBean(account, MailAccountRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "邮箱管理",summary = "获得邮箱账号分页")
@PreAuthorize("@ss.hasPermission('system:mail-account:query')")
public CommonResult<PageResult<MailAccountRespVO>> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) {
PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(tags = "邮箱管理",summary = "获得邮箱账号精简列表")
public CommonResult<List<MailAccountSimpleRespVO>> getSimpleMailAccountList() {
List<MailAccountDO> list = mailAccountService.getMailAccountList();
return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class));
}
}

View File

@@ -0,0 +1,49 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.mail.log.MailLogPageReqVO;
import com.jeelowcode.service.system.controller.vo.mail.log.MailLogRespVO;
import com.jeelowcode.service.system.entity.MailLogDO;
import com.jeelowcode.service.system.service.IMailLogService;
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.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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮件日志")
@RestController
@RequestMapping("/system/mail-log")
public class MailLogController {
@Resource
private IMailLogService mailLogService;
@GetMapping("/page")
@Operation(tags = "邮箱管理",summary = "获得邮箱日志分页")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<PageResult<MailLogRespVO>> getMailLogPage(@Valid MailLogPageReqVO pageVO) {
PageResult<MailLogDO> pageResult = mailLogService.getMailLogPage(pageVO);
return success(BeanUtils.toBean(pageResult, MailLogRespVO.class));
}
@GetMapping("/get")
@Operation(tags = "邮箱管理",summary = "获得邮箱日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<MailLogRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailLogDO log = mailLogService.getMailLog(id);
return success(BeanUtils.toBean(log, MailLogRespVO.class));
}
}

View File

@@ -0,0 +1,89 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.service.system.controller.vo.mail.template.*;
import com.jeelowcode.service.system.entity.MailTemplateDO;
import com.jeelowcode.service.system.service.IMailSendService;
import com.jeelowcode.service.system.service.IMailTemplateService;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
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.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 邮件模版")
@RestController
@RequestMapping("/system/mail-template")
public class MailTemplateController {
@Resource
private IMailTemplateService mailTempleService;
@Resource
private IMailSendService mailSendService;
@PostMapping("/create")
@Operation(tags = "邮箱管理",summary = "创建邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:create')")
public CommonResult<Long> createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){
return success(mailTempleService.createMailTemplate(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "邮箱管理",summary = "修改邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:update')")
public CommonResult<Boolean> updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){
mailTempleService.updateMailTemplate(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "邮箱管理",summary = "删除邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
public CommonResult<Boolean> deleteMailTemplate(@RequestParam("id") Long id) {
mailTempleService.deleteMailTemplate(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "邮箱管理",summary = "获得邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:get')")
public CommonResult<MailTemplateRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailTemplateDO template = mailTempleService.getMailTemplate(id);
return success(BeanUtils.toBean(template, MailTemplateRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "邮箱管理",summary = "获得邮件模版分页")
@PreAuthorize("@ss.hasPermission('system:mail-template:query')")
public CommonResult<PageResult<MailTemplateRespVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) {
PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(tags = "邮箱管理",summary = "获得邮件模版精简列表")
public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleTemplateList() {
List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class));
}
@PostMapping("/send-mail")
@Operation(tags = "邮箱管理",summary = "发送短信")
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
}

View File

@@ -0,0 +1,98 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.permission.menu.MenuListReqVO;
import com.jeelowcode.service.system.controller.vo.permission.menu.MenuRespVO;
import com.jeelowcode.service.system.controller.vo.permission.menu.MenuSaveVO;
import com.jeelowcode.service.system.controller.vo.permission.menu.MenuSimpleRespVO;
import com.jeelowcode.service.system.entity.MenuDO;
import com.jeelowcode.service.system.service.IMenuService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 菜单")
@RestController
@RequestMapping("/system/menu")
@Validated
public class MenuController {
@Resource
private IMenuService menuService;
@PostMapping("/create")
@Operation(tags = "菜单管理",summary = "创建菜单")
@PreAuthorize("@ss.hasPermission('system:menu:create')")
public CommonResult<Long> createMenu(@Valid @RequestBody MenuSaveVO createReqVO) {
Long menuId = menuService.createMenu(createReqVO);
return success(menuId);
}
@PostMapping("/batch/create")
@Operation(tags = "菜单管理",summary = "批量创建菜单")
@PreAuthorize("@ss.hasPermission('system:menu:create')")
public CommonResult<List<Long>> createBatchMenu(@Valid @RequestBody List<MenuSaveVO> createReqVO) {
List<Long> idList = menuService.createBatchMenu(createReqVO);
return success(idList);
}
@PutMapping("/update")
@Operation(tags = "菜单管理",summary = "修改菜单")
@PreAuthorize("@ss.hasPermission('system:menu:update')")
public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) {
menuService.updateMenu(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "菜单管理",summary = "删除菜单")
@Parameter(name = "id", description = "角色编号", required= true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:menu:delete')")
public CommonResult<Boolean> deleteMenu(@RequestBody List<Long> ids,String type) {
for(Long id:ids){
menuService.deleteMenu(id,type);
}
return success(true);
}
@GetMapping("/list")
@Operation(tags = "菜单管理",summary = "获取菜单列表", description = "用于【菜单管理】界面")
@PreAuthorize("@ss.hasPermission('system:menu:query')")
public CommonResult<List<MenuRespVO>> getMenuList(MenuListReqVO reqVO) {
List<MenuDO> list = menuService.getMenuList(reqVO);
list.sort(Comparator.comparing(MenuDO::getSort));
return success(BeanUtils.toBean(list, MenuRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(tags = "菜单管理",summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" +
"在多租户的场景下,会只返回租户所在套餐有的菜单")
public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() {
List<MenuDO> list = menuService.getMenuListByTenant(
new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
list.sort(Comparator.comparing(MenuDO::getSort));
return success(BeanUtils.toBean(list, MenuSimpleRespVO.class));
}
@GetMapping("/get")
@Operation(tags = "菜单管理",summary = "获取菜单信息")
@PreAuthorize("@ss.hasPermission('system:menu:query')")
public CommonResult<MenuRespVO> getMenu(Long id) {
MenuDO menu = menuService.getMenu(id);
return success(BeanUtils.toBean(menu, MenuRespVO.class));
}
}

View File

@@ -0,0 +1,92 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.lang.Assert;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.infra.api.IApiWebSocketSenderApi;
import com.jeelowcode.service.system.controller.vo.notice.NoticePageReqVO;
import com.jeelowcode.service.system.controller.vo.notice.NoticeRespVO;
import com.jeelowcode.service.system.controller.vo.notice.NoticeSaveReqVO;
import com.jeelowcode.service.system.entity.NoticeDO;
import com.jeelowcode.service.system.service.INoticeService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 通知公告")
@RestController
@RequestMapping("/system/notice")
@Validated
public class NoticeController {
@Resource
private INoticeService noticeService;
@Resource
private IApiWebSocketSenderApi apiWebSocketSenderApi;
@PostMapping("/create")
@Operation(tags = "通知公告",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(tags = "通知公告",summary = "修改通知公告")
@PreAuthorize("@ss.hasPermission('system:notice:update')")
public CommonResult<Boolean> updateNotice(@Valid @RequestBody NoticeSaveReqVO updateReqVO) {
noticeService.updateNotice(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "通知公告",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);
}
@GetMapping("/page")
@Operation(tags = "通知公告",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(tags = "通知公告",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(tags = "通知公告",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 推送给在线的用户
apiWebSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), "notice-push", notice);
return success(true);
}
}

View File

@@ -0,0 +1,96 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.notify.message.NotifyMessageMyPageReqVO;
import com.jeelowcode.service.system.controller.vo.notify.message.NotifyMessagePageReqVO;
import com.jeelowcode.service.system.controller.vo.notify.message.NotifyMessageRespVO;
import com.jeelowcode.service.system.entity.NotifyMessageDO;
import com.jeelowcode.service.system.service.INotifyMessageService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 我的站内信")
@RestController
@RequestMapping("/system/notify-message")
@Validated
public class NotifyMessageController {
@Resource
private INotifyMessageService notifyMessageServicerApi;
// ========== 管理所有的站内信 ==========
@GetMapping("/get")
@Operation(tags = "站内信管理",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 = notifyMessageServicerApi.getNotifyMessage(id);
return success(BeanUtils.toBean(message, NotifyMessageRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "站内信管理",summary = "获得站内信分页")
@PreAuthorize("@ss.hasPermission('system:notify-message:query')")
public CommonResult<PageResult<NotifyMessageRespVO>> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) {
PageResult<NotifyMessageDO> pageResult = notifyMessageServicerApi.getNotifyMessagePage(pageVO);
return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
}
// ========== 查看自己的站内信 ==========
@GetMapping("/my-page")
@Operation(tags = "站内信管理",summary = "获得我的站内信分页")
public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
PageResult<NotifyMessageDO> pageResult = notifyMessageServicerApi.getMyMyNotifyMessagePage(pageVO,
getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
}
@PutMapping("/update-read")
@Operation(tags = "站内信管理",summary = "标记站内信为已读")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
notifyMessageServicerApi.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE);
}
@PutMapping("/update-all-read")
@Operation(tags = "站内信管理",summary = "标记所有站内信为已读")
public CommonResult<Boolean> updateAllNotifyMessageRead() {
notifyMessageServicerApi.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE);
}
@GetMapping("/get-unread-list")
@Operation(tags = "站内信管理",summary = "获取当前用户的最新站内信列表,默认 10 条")
@Parameter(name = "size", description = "10")
public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
@RequestParam(name = "size", defaultValue = "10") Integer size) {
List<NotifyMessageDO> list = notifyMessageServicerApi.getUnreadNotifyMessageList(
getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
return success(BeanUtils.toBean(list, NotifyMessageRespVO.class));
}
@GetMapping("/get-unread-count")
// @Operation(tags = "站内信管理",summary = "获得当前用户的未读站内信数量") //定时请求的,不做记录存储
public CommonResult<Long> getUnreadNotifyMessageCount() {
return success(notifyMessageServicerApi.getUnreadNotifyMessageCount(
getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
}
}

View File

@@ -0,0 +1,88 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.notify.template.NotifyTemplatePageReqVO;
import com.jeelowcode.service.system.controller.vo.notify.template.NotifyTemplateRespVO;
import com.jeelowcode.service.system.controller.vo.notify.template.NotifyTemplateSaveReqVO;
import com.jeelowcode.service.system.controller.vo.notify.template.NotifyTemplateSendReqVO;
import com.jeelowcode.service.system.entity.NotifyTemplateDO;
import com.jeelowcode.service.system.service.INotifySendService;
import com.jeelowcode.service.system.service.INotifyTemplateService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 站内信模版")
@RestController
@RequestMapping("/system/notify-template")
@Validated
public class NotifyTemplateController {
@Resource
private INotifyTemplateService notifyTemplateService;
@Resource
private INotifySendService notifySendService;
@PostMapping("/create")
@Operation(tags = "站内信管理",summary = "创建站内信模版")
@PreAuthorize("@ss.hasPermission('system:notify-template:create')")
public CommonResult<Long> createNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO createReqVO) {
return success(notifyTemplateService.createNotifyTemplate(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "站内信管理",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(tags = "站内信管理",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);
}
@GetMapping("/get")
@Operation(tags = "站内信管理",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(tags = "站内信管理",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(tags = "站内信管理",summary = "发送站内信")
@PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
public CommonResult sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserIdList(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams());
return success("成功");
}
}

View File

@@ -0,0 +1,73 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.oauth2.client.OAuth2ClientPageReqVO;
import com.jeelowcode.service.system.controller.vo.oauth2.client.OAuth2ClientRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.client.OAuth2ClientSaveReqVO;
import com.jeelowcode.service.system.entity.OAuth2ClientDO;
import com.jeelowcode.service.system.service.IOAuth2ClientService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - OAuth2 客户端")
@RestController
@RequestMapping("/system/oauth2-client")
@Validated
public class OAuth2ClientController {
@Resource
private IOAuth2ClientService oAuth2ClientService;
@PostMapping("/create")
@Operation(tags = "OAuth2.0管理",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(tags = "OAuth2.0管理",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(tags = "OAuth2.0管理",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);
}
@GetMapping("/get")
@Operation(tags = "OAuth2.0管理",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(tags = "OAuth2.0管理",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));
}
}

View File

@@ -0,0 +1,302 @@
package com.jeelowcode.service.system.controller;
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.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.http.HttpUtils;
import com.jeelowcode.tool.framework.common.util.json.JsonUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenAccessTokenRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenAuthorizeInfoRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.open.OAuth2OpenCheckTokenRespVO;
import com.jeelowcode.service.system.config.convert.oauth2.OAuth2OpenConvert;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import com.jeelowcode.service.system.entity.OAuth2ApproveDO;
import com.jeelowcode.service.system.entity.OAuth2ClientDO;
import com.jeelowcode.service.system.enums.OAuth2GrantTypeEnum;
import com.jeelowcode.service.system.service.IOAuth2ApproveService;
import com.jeelowcode.service.system.service.IOAuth2ClientService;
import com.jeelowcode.service.system.service.IOAuth2GrantService;
import com.jeelowcode.service.system.service.IOAuth2TokenService;
import com.jeelowcode.service.system.util.OAuth2Utils;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.jeelowcode.tool.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static com.jeelowcode.tool.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList;
import static com.jeelowcode.tool.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 芋道源码
*/
@Tag(name = "管理后台 - OAuth2.0 授权")
@RestController
@RequestMapping("/system/oauth2")
@Validated
@Slf4j
public class OAuth2OpenController {
@Resource
private IOAuth2GrantService oauth2GrantService;
@Resource
private IOAuth2ClientService oauth2ClientService;
@Resource
private IOAuth2ApproveService oauth2ApproveService;
@Resource
private IOAuth2TokenService 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(tags = "OAuth2.0管理",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"),
})
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
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.getByGranType(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(tags = "OAuth2.0管理",summary = "删除访问令牌")
@Parameter(name = "token", required = true, description = "访问令牌", example = "biu")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
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(tags = "OAuth2.0管理",summary = "校验访问令牌")
@Parameter(name = "token", required = true, description = "访问令牌", example = "biu")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
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(tags = "OAuth2.0管理",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(tags = "OAuth2.0管理",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")
})
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
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;
}
}

View File

@@ -0,0 +1,50 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.oauth2.token.OAuth2AccessTokenPageReqVO;
import com.jeelowcode.service.system.controller.vo.oauth2.token.OAuth2AccessTokenRespVO;
import com.jeelowcode.service.system.entity.OAuth2AccessTokenDO;
import com.jeelowcode.service.system.enums.LoginLogTypeEnum;
import com.jeelowcode.service.system.service.IAdminAuthService;
import com.jeelowcode.service.system.service.IOAuth2TokenService;
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.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - OAuth2.0 令牌")
@RestController
@RequestMapping("/system/oauth2-token")
public class OAuth2TokenController {
@Resource
private IOAuth2TokenService oauth2TokenService;
@Resource
private IAdminAuthService authService;
@GetMapping("/page")
@Operation(tags = "OAuth2.0管理",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(tags = "OAuth2.0管理",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);
}
}

View File

@@ -0,0 +1,77 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.oauth2.user.OAuth2UserInfoRespVO;
import com.jeelowcode.service.system.controller.vo.oauth2.user.OAuth2UserUpdateReqVO;
import com.jeelowcode.service.system.controller.vo.user.profile.UserProfileUpdateReqVO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.service.IDeptService;
import com.jeelowcode.service.system.service.IPostService;
import com.jeelowcode.service.system.service.IAdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.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 芋道源码
*/
@Tag(name = "管理后台 - OAuth2.0 用户")
@RestController
@RequestMapping("/system/oauth2/user")
@Validated
@Slf4j
public class OAuth2UserController {
@Resource
private IAdminUserService userService;
@Resource
private IDeptService deptService;
@Resource
private IPostService postService;
@GetMapping("/get")
@Operation(tags = "OAuth2.0管理",summary = "获得用户基本信息")
@PreAuthorize("@ss.hasScope('user.read')") //
public CommonResult<OAuth2UserInfoRespVO> getUserInfo() {
// 获得用户基本信息
AdminUserDO user = userService.getUser(getLoginUserId());
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 (CollUtil.isNotEmpty(user.getPostIds())) {
List<PostDO> posts = postService.getPostList(user.getPostIds());
resp.setPosts(BeanUtils.toBean(posts, OAuth2UserInfoRespVO.Post.class));
}*/
return success(resp);
}
@PutMapping("/update")
@Operation(tags = "OAuth2.0管理",summary = "更新用户基本信息")
@PreAuthorize("@ss.hasScope('user.write')")
public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) {
// 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。
// 主要是AdminUserService 没有自己的 BO 对象,所以复用只能这么做
userService.updateUserProfile(getLoginUserId(), BeanUtils.toBean(reqVO, UserProfileUpdateReqVO.class));
return success(true);
}
}

View File

@@ -0,0 +1,71 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.logger.operatelog.OperateLogPageReqVO;
import com.jeelowcode.service.system.controller.vo.logger.operatelog.OperateLogRespVO;
import com.jeelowcode.service.system.config.convert.logger.OperateLogConvert;
import com.jeelowcode.service.system.entity.OperateLogDO;
import com.jeelowcode.service.system.entity.AdminUserDO;
import com.jeelowcode.service.system.service.IOperateLogService;
import com.jeelowcode.service.system.service.IAdminUserService;
import io.swagger.v3.oas.annotations.Operation;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 操作日志")
@RestController
@RequestMapping("/system/operate-log")
@Validated
public class OperateLogController {
@Resource
private IOperateLogService operateLogService;
@Resource
private IAdminUserService userService;
@GetMapping("/page")
@Operation(tags = "审查日志",summary = "查看操作日志分页列表")
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
public CommonResult<PageResult<OperateLogRespVO>> pageOperateLog(@Valid OperateLogPageReqVO pageReqVO) {
PageResult<OperateLogDO> pageResult = operateLogService.getOperateLogPage(pageReqVO);
// 获得拼接需要的数据
Map<Long, AdminUserDO> userMap = userService.getUserMap(
convertList(pageResult.getList(), OperateLogDO::getUserId));
return success(new PageResult<>(OperateLogConvert.INSTANCE.convertList(pageResult.getList(), userMap),
pageResult.getTotal()));
}
@Operation(tags = "审查日志",summary = "导出操作日志")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
@OperateLog(type = EXPORT)
public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<OperateLogDO> list = operateLogService.getOperateLogPage(exportReqVO).getList();
// 输出
Map<Long, AdminUserDO> userMap = userService.getUserMap(
convertList(list, OperateLogDO::getUserId));
ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogRespVO.class,
OperateLogConvert.INSTANCE.convertList(list, userMap));
}
}

View File

@@ -0,0 +1,82 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.collection.CollUtil;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.service.system.controller.vo.permission.permission.PermissionAssignRoleDataScopeReqVO;
import com.jeelowcode.service.system.controller.vo.permission.permission.PermissionAssignRoleMenuReqVO;
import com.jeelowcode.service.system.controller.vo.permission.permission.PermissionAssignUserRoleReqVO;
import com.jeelowcode.service.system.service.IPermissionService;
import com.jeelowcode.service.system.service.ITenantService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Set;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
/**
* 权限 Controller提供赋予用户、角色的权限的 API 接口
*
* @author 芋道源码
*/
@Tag(name = "管理后台 - 权限")
@RestController
@RequestMapping("/system/permission")
public class PermissionController {
@Resource
private IPermissionService permissionService;
@Resource
private ITenantService tenantService;
@Operation(tags = "菜单管理",summary = "获得角色拥有的菜单编号")
@Parameter(name = "roleId", description = "角色编号", required = true)
@GetMapping("/list-role-menus")
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
return success(permissionService.getRoleMenuListByRoleId(roleId));
}
@PostMapping("/assign-role-menu")
@Operation(tags = "菜单管理",summary = "赋予角色菜单")
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
public CommonResult<Boolean> assignRoleMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) {
// 开启多租户的情况下,需要过滤掉未开通的菜单
tenantService.handleTenantMenu(menuIds -> reqVO.getMenuIds().removeIf(menuId -> !CollUtil.contains(menuIds, menuId)));
// 执行菜单的分配
permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds());
return success(true);
}
@PostMapping("/assign-role-data-scope")
@Operation(tags = "菜单管理",summary = "赋予角色数据权限")
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')")
public CommonResult<Boolean> assignRoleDataScope(@Valid @RequestBody PermissionAssignRoleDataScopeReqVO reqVO) {
permissionService.assignRoleDataScope(reqVO.getRoleId(), reqVO.getDataScope(), reqVO.getDataScopeDeptIds());
return success(true);
}
@Operation(tags = "菜单管理",summary = "获得管理员拥有的角色编号列表")
@Parameter(name = "userId", description = "用户编号", required = true)
@GetMapping("/list-user-roles")
@PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')")
public CommonResult<Set<Long>> listAdminRoles(@RequestParam("userId") Long userId) {
return success(permissionService.getUserRoleIdListByUserId(userId));
}
@Operation(tags = "菜单管理",summary = "赋予用户角色")
@PostMapping("/assign-user-role")
@PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')")
public CommonResult<Boolean> assignUserRole(@Validated @RequestBody PermissionAssignUserRoleReqVO reqVO) {
permissionService.assignUserRole(reqVO.getUserId(), reqVO.getRoleIds());
return success(true);
}
}

View File

@@ -0,0 +1,106 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dept.position.PositionPageReqVO;
import com.jeelowcode.service.system.controller.vo.dept.position.PositionRespVO;
import com.jeelowcode.service.system.controller.vo.dept.position.PositionSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dept.position.PositionSimpleRespVO;
import com.jeelowcode.service.system.entity.PositionDO;
import com.jeelowcode.service.system.service.IPositionService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 职位")
@RestController
@RequestMapping("/system/position")
@Validated
public class PositionController {
@Resource
private IPositionService positionService;
@PostMapping("/create")
@Operation(tags = "职位管理",summary = "创建职位")
@PreAuthorize("@ss.hasPermission('system:position:create')")
public CommonResult<Long> create(@Valid @RequestBody PositionSaveReqVO createReqVO) {
Long id = positionService.createPosition(createReqVO);
return success(id);
}
@PutMapping("/update")
@Operation(tags = "职位管理",summary = "修改职位")
@PreAuthorize("@ss.hasPermission('system:position:update')")
public CommonResult<Boolean> update(@Valid @RequestBody PositionSaveReqVO updateReqVO) {
positionService.updatePosition(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "职位管理",summary = "删除职位")
@PreAuthorize("@ss.hasPermission('system:position:delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
positionService.deletePosition(id);
return success(true);
}
@GetMapping(value = "/get")
@Operation(tags = "职位管理",summary = "获得职位信息")
@Parameter(name = "id", description = "职位编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:position:query')")
public CommonResult<PositionRespVO> get(@RequestParam("id") Long id) {
PositionDO Position = positionService.getPosition(id);
return success(BeanUtils.toBean(Position, PositionRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(tags = "职位管理",summary = "获取职位全列表", description = "只包含被开启的职位,主要用于前端的下拉选项")
public CommonResult<List<PositionSimpleRespVO>> getSimpleList() {
// 获得职位列表,只要开启状态的
List<PositionDO> list = positionService.getPositionList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(PositionDO::getSort));
return success(BeanUtils.toBean(list, PositionSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "职位管理",summary = "获得职位分页列表")
@PreAuthorize("@ss.hasPermission('system:position:query')")
public CommonResult<PageResult<PositionRespVO>> getPage(@Validated PositionPageReqVO pageReqVO) {
PageResult<PositionDO> pageResult = positionService.getPositionPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PositionRespVO.class));
}
@GetMapping("/export")
@Operation(tags = "职位管理",summary = "职位管理")
@PreAuthorize("@ss.hasPermission('system:position:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated PositionPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PositionDO> list = positionService.getPositionPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "职位数据.xls", "职位列表", PositionRespVO.class,
BeanUtils.toBean(list, PositionRespVO.class));
}
}

View File

@@ -0,0 +1,106 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dept.post.PostPageReqVO;
import com.jeelowcode.service.system.controller.vo.dept.post.PostSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dept.post.PostRespVO;
import com.jeelowcode.service.system.controller.vo.dept.post.PostSimpleRespVO;
import com.jeelowcode.service.system.entity.PostDO;
import com.jeelowcode.service.system.service.IPostService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 岗位")
@RestController
@RequestMapping("/system/post")
@Validated
public class PostController {
@Resource
private IPostService postService;
@PostMapping("/create")
@Operation(tags = "岗位管理",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(tags = "岗位管理",summary = "修改岗位")
@PreAuthorize("@ss.hasPermission('system:post:update')")
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
postService.updatePost(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "岗位管理",summary = "删除岗位")
@PreAuthorize("@ss.hasPermission('system:post:delete')")
public CommonResult<Boolean> deletePost(@RequestParam("id") Long id) {
postService.deletePost(id);
return success(true);
}
@GetMapping(value = "/get")
@Operation(tags = "岗位管理",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(tags = "岗位管理",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(tags = "岗位管理",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")
@Operation(tags = "岗位管理",summary = "岗位管理")
@PreAuthorize("@ss.hasPermission('system:post:export')")
@OperateLog(type = 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));
}
}

View File

@@ -0,0 +1,106 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.dept.rank.RankPageReqVO;
import com.jeelowcode.service.system.controller.vo.dept.rank.RankRespVO;
import com.jeelowcode.service.system.controller.vo.dept.rank.RankSaveReqVO;
import com.jeelowcode.service.system.controller.vo.dept.rank.RankSimpleRespVO;
import com.jeelowcode.service.system.entity.RankDO;
import com.jeelowcode.service.system.service.IRankService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 职级")
@RestController
@RequestMapping("/system/rank")
@Validated
public class RankController {
@Resource
private IRankService rankService;
@PostMapping("/create")
@Operation(tags = "职级管理",summary = "创建职级")
@PreAuthorize("@ss.hasPermission('system:rank:create')")
public CommonResult<Long> create(@Valid @RequestBody RankSaveReqVO createReqVO) {
Long id = rankService.createRank(createReqVO);
return success(id);
}
@PutMapping("/update")
@Operation(tags = "职级管理",summary = "修改职级")
@PreAuthorize("@ss.hasPermission('system:rank:update')")
public CommonResult<Boolean> update(@Valid @RequestBody RankSaveReqVO updateReqVO) {
rankService.updateRank(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "职级管理",summary = "删除职级")
@PreAuthorize("@ss.hasPermission('system:rank:delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
rankService.deleteRank(id);
return success(true);
}
@GetMapping(value = "/get")
@Operation(tags = "职级管理",summary = "获得职级信息")
@Parameter(name = "id", description = "职级编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:rank:query')")
public CommonResult<RankRespVO> get(@RequestParam("id") Long id) {
RankDO Rank = rankService.getRank(id);
return success(BeanUtils.toBean(Rank, RankRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(tags = "职级管理",summary = "获取职级全列表", description = "只包含被开启的职级,主要用于前端的下拉选项")
public CommonResult<List<RankSimpleRespVO>> getSimpleList() {
// 获得职级列表,只要开启状态的
List<RankDO> list = rankService.getRankList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(RankDO::getSort));
return success(BeanUtils.toBean(list, RankSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "职级管理",summary = "获得职级分页列表")
@PreAuthorize("@ss.hasPermission('system:rank:query')")
public CommonResult<PageResult<RankRespVO>> getPage(@Validated RankPageReqVO pageReqVO) {
PageResult<RankDO> pageResult = rankService.getRankPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RankRespVO.class));
}
@GetMapping("/export")
@Operation(tags = "职级管理",summary = "职级管理")
@PreAuthorize("@ss.hasPermission('system:rank:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated RankPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RankDO> list = rankService.getRankPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "职级数据.xls", "职级列表", RankRespVO.class,
BeanUtils.toBean(list, RankRespVO.class));
}
}

View File

@@ -0,0 +1,127 @@
package com.jeelowcode.service.system.controller;
import cn.hutool.core.util.ObjectUtil;
import com.jeelowcode.service.system.controller.vo.permission.role.*;
import com.jeelowcode.service.system.entity.DictDataDO;
import com.jeelowcode.service.system.entity.RoleDO;
import com.jeelowcode.service.system.service.IDictDataService;
import com.jeelowcode.service.system.service.IRoleService;
import com.jeelowcode.tool.framework.common.enums.CommonStatusEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static java.util.Collections.singleton;
@Tag(name = "管理后台 - 角色")
@RestController
@RequestMapping("/system/role")
@Validated
public class RoleController {
@Resource
private IRoleService roleService;
@Resource
private IDictDataService dictDataService;
@PostMapping("/create")
@Operation(tags = "菜单管理",summary = "创建角色")
@PreAuthorize("@ss.hasPermission('system:role:create')")
public CommonResult<Long> createRole(@Valid @RequestBody RoleSaveReqVO createReqVO) {
return success(roleService.createRole(createReqVO, null,true));
}
@PutMapping("/update")
@Operation(tags = "菜单管理",summary = "修改角色")
@PreAuthorize("@ss.hasPermission('system:role:update')")
public CommonResult<Boolean> updateRole(@Valid @RequestBody RoleSaveReqVO updateReqVO) {
roleService.updateRole(updateReqVO,true);
return success(true);
}
@PutMapping("/update-status")
@Operation(tags = "菜单管理",summary = "修改角色状态")
@PreAuthorize("@ss.hasPermission('system:role:update')")
public CommonResult<Boolean> updateRoleStatus(@Valid @RequestBody RoleUpdateStatusReqVO reqVO) {
roleService.updateRoleStatus(reqVO.getId(), reqVO.getStatus());
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "菜单管理",summary = "删除角色")
@Parameter(name = "id", description = "角色编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:role:delete')")
public CommonResult<Boolean> deleteRole(@RequestParam("id") Long id) {
roleService.deleteRole(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "菜单管理",summary = "获得角色信息")
@PreAuthorize("@ss.hasPermission('system:role:query')")
public CommonResult<RoleRespVO> getRole(@RequestParam("id") Long id) {
RoleDO role = roleService.getRole(id);
return success(BeanUtils.toBean(role, RoleRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "菜单管理",summary = "获得角色分页")
@PreAuthorize("@ss.hasPermission('system:role:query')")
public CommonResult<PageResult<RoleRespVO>> getRolePage(RolePageReqVO pageReqVO) {
PageResult<RoleDO> pageResult = roleService.getRolePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RoleRespVO.class));
}
@GetMapping({"/list-all-simple", "/simple-list"})
@Operation(tags = "菜单管理",summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项")
public CommonResult<List<RoleSimpleRespVO>> getSimpleRoleList() {
List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus()));
list.sort(Comparator.comparing(RoleDO::getSort));
return success(BeanUtils.toBean(list, RoleSimpleRespVO.class));
}
@GetMapping("/export-excel")
@Operation(tags = "菜单管理",summary = "导出角色 Excel")
@OperateLog(type = EXPORT)
@PreAuthorize("@ss.hasPermission('system:role:export')")
public void export(HttpServletResponse response, @Validated RolePageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RoleDO> list = roleService.getRolePage(exportReqVO).getList();
List<CopyRoleRespVO> roleRespVOList = BeanUtils.toBean(list, CopyRoleRespVO.class);
List<DictDataDO> dictDataList = dictDataService.getListByDictType("system_data_scope");
Map<String, String> dataScopeMap = dictDataList.stream()
.collect(Collectors.toMap(DictDataDO::getValue, DictDataDO::getLabel, (existingValue, newValue) -> newValue));
roleRespVOList.stream()
.filter(item -> ObjectUtil.isNotEmpty(item.getDataScope()))
.forEach(item -> {
if (!dataScopeMap.containsKey(item.getDataScope())) {
return;
}
item.setDataScope(dataScopeMap.get(item.getDataScope()));
});
// 输出
ExcelUtils.write(response, "角色数据.xls", "数据", CopyRoleRespVO.class, roleRespVOList);
}
}

View File

@@ -0,0 +1,108 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.sensitiveword.SensitiveWordPageReqVO;
import com.jeelowcode.service.system.controller.vo.sensitiveword.SensitiveWordRespVO;
import com.jeelowcode.service.system.controller.vo.sensitiveword.SensitiveWordSaveVO;
import com.jeelowcode.service.system.entity.SensitiveWordDO;
import com.jeelowcode.service.system.service.ISensitiveWordService;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 敏感词")
@RestController
@RequestMapping("/system/sensitive-word")
@Validated
public class SensitiveWordController {
@Resource
private ISensitiveWordService sensitiveWordService;
@PostMapping("/create")
@Operation(tags = "敏感词管理",summary = "创建敏感词")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:create')")
public CommonResult<Long> createSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO createReqVO) {
return success(sensitiveWordService.createSensitiveWord(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "敏感词管理",summary = "更新敏感词")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:update')")
public CommonResult<Boolean> updateSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO updateReqVO) {
sensitiveWordService.updateSensitiveWord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "敏感词管理",summary = "删除敏感词")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:sensitive-word:delete')")
public CommonResult<Boolean> deleteSensitiveWord(@RequestParam("id") Long id) {
sensitiveWordService.deleteSensitiveWord(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "敏感词管理",summary = "获得敏感词")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
public CommonResult<SensitiveWordRespVO> getSensitiveWord(@RequestParam("id") Long id) {
SensitiveWordDO sensitiveWord = sensitiveWordService.getSensitiveWord(id);
return success(BeanUtils.toBean(sensitiveWord, SensitiveWordRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "敏感词管理",summary = "获得敏感词分页")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
public CommonResult<PageResult<SensitiveWordRespVO>> getSensitiveWordPage(@Valid SensitiveWordPageReqVO pageVO) {
PageResult<SensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(pageVO);
return success(BeanUtils.toBean(pageResult, SensitiveWordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(tags = "敏感词管理",summary = "导出敏感词 Excel")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:export')")
@OperateLog(type = EXPORT)
public void exportSensitiveWordExcel(@Valid SensitiveWordPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SensitiveWordDO> list = sensitiveWordService.getSensitiveWordPage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "敏感词.xls", "数据", SensitiveWordRespVO.class,
BeanUtils.toBean(list, SensitiveWordRespVO.class));
}
@GetMapping("/get-tags")
@Operation(tags = "敏感词管理",summary = "获取所有敏感词的标签数组")
@PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
public CommonResult<Set<String>> getSensitiveWordTagSet() {
return success(sensitiveWordService.getSensitiveWordTagSet());
}
@GetMapping("/validate-text")
@Operation(tags = "敏感词管理",summary = "获得文本所包含的不合法的敏感词数组")
public CommonResult<List<String>> validateText(@RequestParam("text") String text,
@RequestParam(value = "tags", required = false) List<String> tags) {
return success(sensitiveWordService.validateText(text, tags));
}
}

View File

@@ -0,0 +1,48 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.servlet.ServletUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.config.framework.sms.core.enums.SmsChannelEnum;
import com.jeelowcode.service.system.service.ISmsSendService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 短信回调")
@RestController
@RequestMapping("/system/sms/callback")
public class SmsCallbackController {
@Resource
private ISmsSendService smsSendService;
@PostMapping("/aliyun")
@PermitAll
@Operation(tags = "短信管理",summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/document_detail/120998.html 文档")
@OperateLog(enable = false)
public CommonResult<Boolean> receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable {
String text = ServletUtils.getBody(request);
smsSendService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text);
return success(true);
}
@PostMapping("/tencent")
@PermitAll
@Operation(tags = "短信管理",summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/52077 文档")
@OperateLog(enable = false)
public CommonResult<Boolean> receiveTencentSmsStatus(HttpServletRequest request) throws Throwable {
String text = ServletUtils.getBody(request);
smsSendService.receiveSmsStatus(SmsChannelEnum.TENCENT.getCode(), text);
return success(true);
}
}

View File

@@ -0,0 +1,82 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.sms.channel.SmsChannelPageReqVO;
import com.jeelowcode.service.system.controller.vo.sms.channel.SmsChannelRespVO;
import com.jeelowcode.service.system.controller.vo.sms.channel.SmsChannelSaveReqVO;
import com.jeelowcode.service.system.controller.vo.sms.channel.SmsChannelSimpleRespVO;
import com.jeelowcode.service.system.entity.SmsChannelDO;
import com.jeelowcode.service.system.service.ISmsChannelService;
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.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Comparator;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 短信渠道")
@RestController
@RequestMapping("system/sms-channel")
public class SmsChannelController {
@Resource
private ISmsChannelService smsChannelService;
@PostMapping("/create")
@Operation(tags = "短信管理",summary = "创建短信渠道")
@PreAuthorize("@ss.hasPermission('system:sms-channel:create')")
public CommonResult<Long> createSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO createReqVO) {
return success(smsChannelService.createSmsChannel(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "短信管理",summary = "更新短信渠道")
@PreAuthorize("@ss.hasPermission('system:sms-channel:update')")
public CommonResult<Boolean> updateSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO updateReqVO) {
smsChannelService.updateSmsChannel(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "短信管理",summary = "删除短信渠道")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:sms-channel:delete')")
public CommonResult<Boolean> deleteSmsChannel(@RequestParam("id") Long id) {
smsChannelService.deleteSmsChannel(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "短信管理",summary = "获得短信渠道")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
public CommonResult<SmsChannelRespVO> getSmsChannel(@RequestParam("id") Long id) {
SmsChannelDO channel = smsChannelService.getSmsChannel(id);
return success(BeanUtils.toBean(channel, SmsChannelRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "短信管理",summary = "获得短信渠道分页")
@PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
public CommonResult<PageResult<SmsChannelRespVO>> getSmsChannelPage(@Valid SmsChannelPageReqVO pageVO) {
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(pageVO);
return success(BeanUtils.toBean(pageResult, SmsChannelRespVO.class));
}
@GetMapping({"/list-all-simple", "/simple-list"})
@Operation(tags = "短信管理",summary = "获得短信渠道精简列表", description = "包含被禁用的短信渠道")
public CommonResult<List<SmsChannelSimpleRespVO>> getSimpleSmsChannelList() {
List<SmsChannelDO> list = smsChannelService.getSmsChannelList();
list.sort(Comparator.comparing(SmsChannelDO::getId));
return success(BeanUtils.toBean(list, SmsChannelSimpleRespVO.class));
}
}

View File

@@ -0,0 +1,60 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import com.jeelowcode.service.system.controller.vo.sms.log.SmsLogPageReqVO;
import com.jeelowcode.service.system.controller.vo.sms.log.SmsLogRespVO;
import com.jeelowcode.service.system.entity.SmsLogDO;
import com.jeelowcode.service.system.service.ISmsLogService;
import io.swagger.v3.oas.annotations.Operation;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 短信日志")
@RestController
@RequestMapping("/system/sms-log")
@Validated
public class SmsLogController {
@Resource
private ISmsLogService smsLogService;
@GetMapping("/page")
@Operation(tags = "短信管理",summary = "获得短信日志分页")
@PreAuthorize("@ss.hasPermission('system:sms-log:query')")
public CommonResult<PageResult<SmsLogRespVO>> getSmsLogPage(@Valid SmsLogPageReqVO pageReqVO) {
PageResult<SmsLogDO> pageResult = smsLogService.getSmsLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(tags = "短信管理",summary = "导出短信日志 Excel")
@PreAuthorize("@ss.hasPermission('system:sms-log:export')")
@OperateLog(type = EXPORT)
public void exportSmsLogExcel(@Valid SmsLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SmsLogDO> list = smsLogService.getSmsLogPage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "短信日志.xls", "数据", SmsLogRespVO.class,
BeanUtils.toBean(list, SmsLogRespVO.class));
}
}

View File

@@ -0,0 +1,102 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.PageParam;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.sms.template.SmsTemplatePageReqVO;
import com.jeelowcode.service.system.controller.vo.sms.template.SmsTemplateRespVO;
import com.jeelowcode.service.system.controller.vo.sms.template.SmsTemplateSaveReqVO;
import com.jeelowcode.service.system.controller.vo.sms.template.SmsTemplateSendReqVO;
import com.jeelowcode.service.system.entity.SmsTemplateDO;
import com.jeelowcode.service.system.service.ISmsTemplateService;
import com.jeelowcode.service.system.service.ISmsSendService;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.excel.core.util.ExcelUtils;
import com.jeelowcode.tool.framework.operatelog.core.annotations.OperateLog;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 短信模板")
@RestController
@RequestMapping("/system/sms-template")
public class SmsTemplateController {
@Resource
private ISmsTemplateService smsTemplateService;
@Resource
private ISmsSendService smsSendService;
@PostMapping("/create")
@Operation(tags = "短信管理",summary = "创建短信模板")
@PreAuthorize("@ss.hasPermission('system:sms-template:create')")
public CommonResult<Long> createSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO createReqVO) {
return success(smsTemplateService.createSmsTemplate(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "短信管理",summary = "更新短信模板")
@PreAuthorize("@ss.hasPermission('system:sms-template:update')")
public CommonResult<Boolean> updateSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO updateReqVO) {
smsTemplateService.updateSmsTemplate(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "短信管理",summary = "删除短信模板")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:sms-template:delete')")
public CommonResult<Boolean> deleteSmsTemplate(@RequestParam("id") Long id) {
smsTemplateService.deleteSmsTemplate(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "短信管理",summary = "获得短信模板")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:sms-template:query')")
public CommonResult<SmsTemplateRespVO> getSmsTemplate(@RequestParam("id") Long id) {
SmsTemplateDO template = smsTemplateService.getSmsTemplate(id);
return success(BeanUtils.toBean(template, SmsTemplateRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "短信管理",summary = "获得短信模板分页")
@PreAuthorize("@ss.hasPermission('system:sms-template:query')")
public CommonResult<PageResult<SmsTemplateRespVO>> getSmsTemplatePage(@Valid SmsTemplatePageReqVO pageVO) {
PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(pageVO);
return success(BeanUtils.toBean(pageResult, SmsTemplateRespVO.class));
}
@GetMapping("/export-excel")
@Operation(tags = "短信管理",summary = "导出短信模板 Excel")
@PreAuthorize("@ss.hasPermission('system:sms-template:export')")
@OperateLog(type = EXPORT)
public void exportSmsTemplateExcel(@Valid SmsTemplatePageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SmsTemplateDO> list = smsTemplateService.getSmsTemplatePage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "短信模板.xls", "数据", SmsTemplateRespVO.class,
BeanUtils.toBean(list, SmsTemplateRespVO.class));
}
@PostMapping("/send-sms")
@Operation(tags = "短信管理",summary = "发送短信")
@PreAuthorize("@ss.hasPermission('system:sms-template:send-sms')")
public CommonResult<Long> sendSms(@Valid @RequestBody SmsTemplateSendReqVO sendReqVO) {
return success(smsSendService.sendSingleSmsToAdmin(sendReqVO.getMobile(), sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
}

View File

@@ -0,0 +1,73 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.socail.client.SocialClientPageReqVO;
import com.jeelowcode.service.system.controller.vo.socail.client.SocialClientRespVO;
import com.jeelowcode.service.system.controller.vo.socail.client.SocialClientSaveReqVO;
import com.jeelowcode.service.system.entity.SocialClientDO;
import com.jeelowcode.service.system.service.ISocialClientService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 社交客户端")
@RestController
@RequestMapping("/system/social-client")
@Validated
public class SocialClientController {
@Resource
private ISocialClientService socialClientService;
@PostMapping("/create")
@Operation(tags = "社交管理",summary = "创建社交客户端")
@PreAuthorize("@ss.hasPermission('system:social-client:create')")
public CommonResult<Long> createSocialClient(@Valid @RequestBody SocialClientSaveReqVO createReqVO) {
return success(socialClientService.createSocialClient(createReqVO));
}
@PutMapping("/update")
@Operation(tags = "社交管理",summary = "更新社交客户端")
@PreAuthorize("@ss.hasPermission('system:social-client:update')")
public CommonResult<Boolean> updateSocialClient(@Valid @RequestBody SocialClientSaveReqVO updateReqVO) {
socialClientService.updateSocialClient(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(tags = "社交管理",summary = "删除社交客户端")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:social-client:delete')")
public CommonResult<Boolean> deleteSocialClient(@RequestParam("id") Long id) {
socialClientService.deleteSocialClient(id);
return success(true);
}
@GetMapping("/get")
@Operation(tags = "社交管理",summary = "获得社交客户端")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:social-client:query')")
public CommonResult<SocialClientRespVO> getSocialClient(@RequestParam("id") Long id) {
SocialClientDO client = socialClientService.getSocialClient(id);
return success(BeanUtils.toBean(client, SocialClientRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "社交管理",summary = "获得社交客户端分页")
@PreAuthorize("@ss.hasPermission('system:social-client:query')")
public CommonResult<PageResult<SocialClientRespVO>> getSocialClientPage(@Valid SocialClientPageReqVO pageVO) {
PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(pageVO);
return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class));
}
}

View File

@@ -0,0 +1,70 @@
package com.jeelowcode.service.system.controller;
import com.jeelowcode.tool.framework.common.enums.UserTypeEnum;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.pojo.PageResult;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import com.jeelowcode.service.system.controller.vo.socail.user.SocialUserBindReqVO;
import com.jeelowcode.service.system.controller.vo.socail.user.SocialUserUnbindReqVO;
import com.jeelowcode.service.system.controller.vo.socail.user.SocialUserPageReqVO;
import com.jeelowcode.service.system.controller.vo.socail.user.SocialUserRespVO;
import com.jeelowcode.service.system.config.convert.social.SocialUserConvert;
import com.jeelowcode.service.system.entity.SocialUserDO;
import com.jeelowcode.service.system.service.ISocialUserService;
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 javax.annotation.Resource;
import javax.validation.Valid;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
import static com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 社交用户")
@RestController
@RequestMapping("/system/social-user")
@Validated
public class SocialUserController {
@Resource
private ISocialUserService socialUserService;
@PostMapping("/bind")
@Operation(tags = "社交管理",summary = "社交绑定,使用 code 授权码")
public CommonResult<Boolean> socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) {
socialUserService.bindSocialUser(SocialUserConvert.INSTANCE.convert(
getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO));
return CommonResult.success(true);
}
@DeleteMapping("/unbind")
@Operation(tags = "社交管理",summary = "取消社交绑定")
public CommonResult<Boolean> socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) {
socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid());
return CommonResult.success(true);
}
// ==================== 社交用户 CRUD ====================
@GetMapping("/get")
@Operation(tags = "社交管理",summary = "获得社交用户")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:social-user:query')")
public CommonResult<SocialUserRespVO> getSocialUser(@RequestParam("id") Long id) {
SocialUserDO socialUser = socialUserService.getSocialUser(id);
return success(BeanUtils.toBean(socialUser, SocialUserRespVO.class));
}
@GetMapping("/page")
@Operation(tags = "社交管理",summary = "获得社交用户分页")
@PreAuthorize("@ss.hasPermission('system:social-user:query')")
public CommonResult<PageResult<SocialUserRespVO>> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) {
PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(pageVO);
return success(BeanUtils.toBean(pageResult, SocialUserRespVO.class));
}
}

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