初始化 spring cloud 项目的 system 和 infra 模块

This commit is contained in:
YunaiV
2022-06-01 23:59:01 +08:00
parent fcc5180ebf
commit 12e2ce99e1
1138 changed files with 65636 additions and 134 deletions

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* OAuth2.0 Token API 实现类
*
* @author 芋道源码
*/
@Service
public class OAuth2TokenApiImpl implements OAuth2TokenApi {
@Resource
private OAuth2TokenService oauth2TokenService;
@Override
public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
@Override
public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) {
return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken));
}
@Override
public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
@Override
public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
}

View File

@@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.convert.dept.DeptConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 部门 API 实现类
*
* @author 芋道源码
*/
@Service
public class DeptApiImpl implements DeptApi {
@Resource
private DeptService deptService;
@Override
public DeptRespDTO getDept(Long id) {
DeptDO dept = deptService.getDept(id);
return DeptConvert.INSTANCE.convert03(dept);
}
@Override
public List<DeptRespDTO> getDepts(Collection<Long> ids) {
List<DeptDO> depts = deptService.getDepts(ids);
return DeptConvert.INSTANCE.convertList03(depts);
}
@Override
public void validDepts(Collection<Long> ids) {
deptService.validDepts(ids);
}
@Override
public Map<Long, DeptRespDTO> getDeptMap(Set<Long> ids) {
Map<Long, DeptDO> depts = deptService.getDeptMap(ids);
return DeptConvert.INSTANCE.convertMap(depts);
}
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 岗位 API 实现类
*
* @author 芋道源码
*/
@Service
public class PostApiImpl implements PostApi {
@Resource
private PostService postService;
@Override
public void validPosts(Collection<Long> ids) {
postService.validPosts(ids);
}
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.api.dict;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 字典数据 API 实现类
*
* @author 芋道源码
*/
@Service
public class DictDataApiImpl implements DictDataApi {
@Resource
private DictDataService dictDataService;
@Override
public void validDictDatas(String dictType, Collection<String> values) {
dictDataService.validDictDatas(dictType, values);
}
}

View File

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

View File

@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Set;
/**
* 权限 API 实现类
*
* @author 芋道源码
*/
@Service
public class PermissionApiImpl implements PermissionApi {
@Resource
private PermissionService permissionService;
@Override
public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
return permissionService.getUserRoleIdListByRoleIds(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,24 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 角色 API 实现类
*
* @author 芋道源码
*/
@Service
public class RoleApiImpl implements RoleApi {
@Resource
private RoleService roleService;
@Override
public void validRoles(Collection<Long> ids) {
roleService.validRoles(ids);
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.api.sensitiveword;
import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 敏感词 API 实现类
*
* @author 永不言败
*/
@Service
public class SensitiveWordApiImpl implements SensitiveWordApi {
@Resource
private SensitiveWordService 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 cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsCodeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信验证码 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SmsCodeApiImpl implements SmsCodeApi {
@Resource
private SmsCodeService smsCodeService;
@Override
public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
smsCodeService.sendSmsCode(reqDTO);
}
@Override
public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
smsCodeService.useSmsCode(reqDTO);
}
@Override
public void checkSmsCode(SmsCodeCheckReqDTO reqDTO) {
smsCodeService.checkSmsCode(reqDTO);
}
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信发送 API 接口
*
* @author 芋道源码
*/
@Service
@Validated
public class SmsSendApiImpl implements SmsSendApi {
@Resource
private SmsSendService smsSendService;
@Override
public Long sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) {
return smsSendService.sendSingleSmsToAdmin(reqDTO.getMobile(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
@Override
public Long sendSingleSmsToMember(SmsSendSingleToUserReqDTO reqDTO) {
return smsSendService.sendSingleSmsToMember(reqDTO.getMobile(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 社交用户的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SocialUserApiImpl implements SocialUserApi {
@Resource
private SocialUserService socialUserService;
@Override
public String getAuthorizeUrl(Integer type, String redirectUri) {
return socialUserService.getAuthorizeUrl(type, redirectUri);
}
@Override
public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
socialUserService.bindSocialUser(reqDTO);
}
@Override
public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) {
socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(),
reqDTO.getType(), reqDTO.getUnionId());
}
@Override
public Long getBindUserId(Integer userType, Integer type, String code, String state) {
return socialUserService.getBindUserId(userType, type, code, state);
}
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.system.api.user;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.convert.user.UserConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Admin 用户 API 实现类
*
* @author 芋道源码
*/
@Service
public class AdminUserApiImpl implements AdminUserApi {
@Resource
private AdminUserService userService;
@Override
public AdminUserRespDTO getUser(Long id) {
AdminUserDO user = userService.getUser(id);
return UserConvert.INSTANCE.convert4(user);
}
@Override
public List<AdminUserRespDTO> getUsersByDeptIds(Collection<Long> deptIds) {
List<AdminUserDO> users = userService.getUsersByDeptIds(deptIds);
return UserConvert.INSTANCE.convertList4(users);
}
@Override
public List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds) {
List<AdminUserDO> users = userService.getUsersByPostIds(postIds);
return UserConvert.INSTANCE.convertList4(users);
}
@Override
public Map<Long, AdminUserRespDTO> getUserMap(Collection<Long> ids) {
Map<Long, AdminUserDO> userMap = userService.getUserMap(ids);
return UserConvert.INSTANCE.convertMap4(userMap);
}
@Override
public void validUsers(Set<Long> ids) {
userService.validUsers(ids);
}
}

View File

@@ -0,0 +1,32 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"username": "admin",
"password": "admin123",
"uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
### 请求 /login 接口 => 成功(无验证码)
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"username": "admin",
"password": "admin123"
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/system/auth/get-permission-info
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /list-menus 接口 => 成功
GET {{baseUrl}}/system/list-menus
Authorization: Bearer {{token}}
#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a
tenant-id: {{adminTenentId}}

View File

@@ -0,0 +1,163 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
import static java.util.Collections.singleton;
@Api(tags = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {
@Resource
private AdminAuthService authService;
@Resource
private AdminUserService userService;
@Resource
private RoleService roleService;
@Resource
private PermissionService permissionService;
@Resource
private SocialUserService socialUserService;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/login")
@ApiOperation("使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
}
@PostMapping("/logout")
@ApiOperation("登出系统")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = obtainAuthorization(request, securityProperties.getTokenHeader());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
return success(true);
}
@PostMapping("/refresh-token")
@ApiOperation("刷新令牌")
@ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@ApiOperation("获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
// 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return null;
}
// 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
// 获得菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 拼接结果返回
return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));
}
@GetMapping("/list-menus")
@ApiOperation("获得登录用户的菜单列表")
public CommonResult<List<AuthMenuRespVO>> getMenus() {
// 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
// 获得用户拥有的菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 转换成 Tree 结构返回
return success(AuthConvert.INSTANCE.buildMenuTree(menuList));
}
// ========== 短信登录相关 ==========
@PostMapping("/sms-login")
@ApiOperation("使用短信验证码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
return success(authService.smsLogin(reqVO));
}
@PostMapping("/send-sms-code")
@ApiOperation(value = "发送手机验证码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
authService.sendSmsCode(reqVO);
return success(true);
}
// ========== 社交登录相关 ==========
@GetMapping("/social-auth-redirect")
@ApiOperation("社交授权的跳转")
@ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "社交类型", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class)
})
public CommonResult<String> socialAuthRedirect(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri) {
return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri));
}
@PostMapping("/social-quick-login")
@ApiOperation("社交快捷登录,使用 code 授权码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) {
return success(authService.socialQuickLogin(reqVO));
}
@PostMapping("/social-bind-login")
@ApiOperation("社交绑定登录,使用 code 授权码 + 账号密码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) {
return success(authService.socialBindLogin(reqVO));
}
}

View File

@@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 账号密码登录 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginReqVO {
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
@ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String code;
@ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62", notes = "验证码开启时,需要传递")
@NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
private String uuid;
/**
* 开启验证码的 Group
*/
public interface CodeEnableGroup {}
}

View File

@@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel("管理后台 - 登录 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
private Long userId;
@ApiModelProperty(value = "访问令牌", required = true, example = "happy")
private String accessToken;
@ApiModelProperty(value = "刷新令牌", required = true, example = "nice")
private String refreshToken;
@ApiModelProperty(value = "过期时间", required = true)
private Date expiresTime;
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@ApiModel("管理后台 - 登录用户的菜单信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthMenuRespVO {
@ApiModelProperty(value = "菜单名称", required = true, example = "芋道")
private Long id;
@ApiModelProperty(value = "父菜单 ID", required = true, example = "1024")
private Long parentId;
@ApiModelProperty(value = "菜单名称", required = true, example = "芋道")
private String name;
@ApiModelProperty(value = "路由地址", example = "post", notes = "仅菜单类型为菜单或者目录时,才需要传")
private String path;
@ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传")
private String component;
@ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传")
private String icon;
@ApiModelProperty(value = "是否可见", required = true, example = "false")
private Boolean visible;
@ApiModelProperty(value = "是否缓存", required = true, example = "false")
private Boolean keepAlive;
/**
* 子路由
*/
private List<AuthMenuRespVO> children;
}

View File

@@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
@ApiModel(value = "管理后台 - 登录用户的权限信息 Response VO", description = "额外包括用户信息和角色列表")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthPermissionInfoRespVO {
@ApiModelProperty(value = "用户信息", required = true)
private UserVO user;
@ApiModelProperty(value = "角色标识数组", required = true)
private Set<String> roles;
@ApiModelProperty(value = "操作权限数组", required = true)
private Set<String> permissions;
@ApiModel("用户信息 VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class UserVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋道源码")
private String nickname;
@ApiModelProperty(value = "用户头像", required = true, example = "http://www.iocoder.cn/xx.jpg")
private String avatar;
}
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 短信验证码的呢老姑 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsLoginReqVO {
@ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Length(min = 11, max = 11, message = "手机号格式错误,仅支持大陆手机号")
@Pattern(regexp = "^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$", message = "账号格式为数字以及字母")
private String mobile;
@ApiModelProperty(value = "短信验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String code;
/**
* 开启验证码的 Group
*/
public interface CodeEnableGroup {}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 发送手机验证码 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsSendReqVO {
@ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Mobile
private String mobile;
@ApiModelProperty(value = "短信场景", required = true, example = "1")
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 社交绑定登录 Request VO使用 code 授权码 + 账号密码")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSocialBindLoginReqVO {
@ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值")
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
@ApiModelProperty(value = "授权码", required = true, example = "1024")
@NotEmpty(message = "授权码不能为空")
private String code;
@ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
@NotEmpty(message = "state 不能为空")
private String state;
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 社交快捷登录 Request VO使用 code 授权码")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSocialQuickLoginReqVO {
@ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值")
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
@ApiModelProperty(value = "授权码", required = true, example = "1024")
@NotEmpty(message = "授权码不能为空")
private String code;
@ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
@NotEmpty(message = "state 不能为空")
private String state;
}

View File

@@ -0,0 +1,3 @@
### 请求 /captcha/get-image 接口 => 成功
GET {{baseUrl}}/system/captcha/get-image
tenant-id: {{adminTenentId}}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.controller.admin.common;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 验证码")
@RestController
@RequestMapping("/system/captcha")
public class CaptchaController {
@Resource
private CaptchaService captchaService;
@GetMapping("/get-image")
@ApiOperation("生成图片验证码")
public CommonResult<CaptchaImageRespVO> getCaptchaImage() {
return success(captchaService.getCaptchaImage());
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.controller.admin.common.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 验证码图片 Response VO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CaptchaImageRespVO {
@ApiModelProperty(value = "是否开启", required = true, example = "true", notes = "如果为 false则关闭验证码功能")
private Boolean enable;
@ApiModelProperty(value = "uuid", example = "1b3b7d00-83a8-4638-9e37-d67011855968",
notes = "enable = true 时,非空!通过该 uuid 作为该验证码的标识")
private String uuid;
@ApiModelProperty(value = "图片", notes = "enable = true 时,非空!验证码的图片内容,使用 Base64 编码")
private String img;
}

View File

@@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.*;
import cn.iocoder.yudao.module.system.convert.dept.DeptConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 部门")
@RestController
@RequestMapping("/system/dept")
@Validated
public class DeptController {
@Resource
private DeptService deptService;
@PostMapping("create")
@ApiOperation("创建部门")
@PreAuthorize("@ss.hasPermission('system:dept:create')")
public CommonResult<Long> createDept(@Valid @RequestBody DeptCreateReqVO reqVO) {
Long deptId = deptService.createDept(reqVO);
return success(deptId);
}
@PutMapping("update")
@ApiOperation("更新部门")
@PreAuthorize("@ss.hasPermission('system:dept:update')")
public CommonResult<Boolean> updateDept(@Valid @RequestBody DeptUpdateReqVO reqVO) {
deptService.updateDept(reqVO);
return success(true);
}
@DeleteMapping("delete")
@ApiOperation("删除部门")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
public CommonResult<Boolean> deleteDept(@RequestParam("id") Long id) {
deptService.deleteDept(id);
return success(true);
}
@GetMapping("/list")
@ApiOperation("获取部门列表")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<List<DeptRespVO>> listDepts(DeptListReqVO reqVO) {
List<DeptDO> list = deptService.getSimpleDepts(reqVO);
list.sort(Comparator.comparing(DeptDO::getSort));
return success(DeptConvert.INSTANCE.convertList(list));
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获取部门精简信息列表", notes = "只包含被开启的部门,主要用于前端的下拉选项")
public CommonResult<List<DeptSimpleRespVO>> getSimpleDepts() {
// 获得部门列表,只要开启状态的
DeptListReqVO reqVO = new DeptListReqVO();
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
List<DeptDO> list = deptService.getSimpleDepts(reqVO);
// 排序后,返回给前端
list.sort(Comparator.comparing(DeptDO::getSort));
return success(DeptConvert.INSTANCE.convertList02(list));
}
@GetMapping("/get")
@ApiOperation("获得部门信息")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<DeptRespVO> getDept(@RequestParam("id") Long id) {
return success(DeptConvert.INSTANCE.convert(deptService.getDept(id)));
}
}

View File

@@ -0,0 +1,99 @@
package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.*;
import cn.iocoder.yudao.module.system.convert.dept.PostConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 岗位")
@RestController
@RequestMapping("/system/post")
@Validated
public class PostController {
@Resource
private PostService postService;
@PostMapping("/create")
@ApiOperation("创建岗位")
@PreAuthorize("@ss.hasPermission('system:post:create')")
public CommonResult<Long> createPost(@Valid @RequestBody PostCreateReqVO reqVO) {
Long postId = postService.createPost(reqVO);
return success(postId);
}
@PutMapping("/update")
@ApiOperation("修改岗位")
@PreAuthorize("@ss.hasPermission('system:post:update')")
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostUpdateReqVO reqVO) {
postService.updatePost(reqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除岗位")
@PreAuthorize("@ss.hasPermission('system:post:delete')")
public CommonResult<Boolean> deletePost(@RequestParam("id") Long id) {
postService.deletePost(id);
return success(true);
}
@GetMapping(value = "/get")
@ApiOperation("获得岗位信息")
@ApiImplicitParam(name = "id", value = "岗位编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
return success(PostConvert.INSTANCE.convert(postService.getPost(id)));
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获取岗位精简信息列表", notes = "只包含被开启的岗位,主要用于前端的下拉选项")
public CommonResult<List<PostSimpleRespVO>> getSimplePosts() {
// 获得岗位列表,只要开启状态的
List<PostDO> list = postService.getPosts(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(PostDO::getSort));
return success(PostConvert.INSTANCE.convertList02(list));
}
@GetMapping("/page")
@ApiOperation("获得岗位分页列表")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO reqVO) {
return success(PostConvert.INSTANCE.convertPage(postService.getPostPage(reqVO)));
}
@GetMapping("/export")
@ApiOperation("岗位管理")
@PreAuthorize("@ss.hasPermission('system:post:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated PostExportReqVO reqVO) throws IOException {
List<PostDO> posts = postService.getPosts(reqVO);
List<PostExcelVO> data = PostConvert.INSTANCE.convertList03(posts);
// 输出
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostExcelVO.class, data);
}
}

View File

@@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 部门 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class DeptBaseVO {
@ApiModelProperty(value = "菜单名称", required = true, example = "芋道")
@NotBlank(message = "部门名称不能为空")
@Size(max = 30, message = "部门名称长度不能超过30个字符")
private String name;
@ApiModelProperty(value = "父菜单 ID", example = "1024")
private Long parentId;
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@ApiModelProperty(value = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@ApiModelProperty(value = "联系电话", example = "15601691000")
@Size(max = 11, message = "联系电话长度不能超过11个字符")
private String phone;
@ApiModelProperty(value = "邮箱", example = "yudao@iocoder.cn")
@Email(message = "邮箱格式不正确")
@Size(max = 50, message = "邮箱长度不能超过50个字符")
private String email;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
}

View File

@@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("管理后台 - 部门创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DeptCreateReqVO extends DeptBaseVO {
}

View File

@@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("管理后台 - 部门列表 Request VO")
@Data
public class DeptListReqVO {
@ApiModelProperty(value = "部门名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@ApiModel("管理后台 - 部门信息 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptRespVO extends DeptBaseVO {
@ApiModelProperty(value = "部门编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 部门精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptSimpleRespVO {
@ApiModelProperty(value = "部门编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "部门名称", required = true, example = "芋道")
private String name;
@ApiModelProperty(value = "父部门 ID", required = true, example = "1024")
private Long parentId;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 部门更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptUpdateReqVO extends DeptBaseVO {
@ApiModelProperty(value = "部门编号", required = true, example = "1024")
@NotNull(message = "部门编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 岗位 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class PostBaseVO {
@ApiModelProperty(value = "岗位名称", required = true, example = "小博主")
@NotBlank(message = "岗位名称不能为空")
@Size(max = 50, message = "岗位名称长度不能超过50个字符")
private String name;
@ApiModelProperty(value = "岗位编码", required = true, example = "yudao")
@NotBlank(message = "岗位编码不能为空")
@Size(max = 64, message = "岗位编码长度不能超过64个字符")
private String code;
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
@ApiModelProperty(value = "备注", example = "快乐的备注")
private String remark;
}

View File

@@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 岗位创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostCreateReqVO extends PostBaseVO {
}

View File

@@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 岗位 Excel 导出响应 VO
*/
@Data
public class PostExcelVO {
@ExcelProperty("岗位序号")
private Long id;
@ExcelProperty("岗位编码")
private String code;
@ExcelProperty("岗位名称")
private String name;
@ExcelProperty("岗位排序")
private Integer sort;
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private String status;
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(value = "管理后台 - 岗位导出 Request VO", description = "参数和 PostExcelVO 是一致的")
@Data
public class PostExportReqVO {
@ApiModelProperty(value = "岗位编码", example = "yudao", notes = "模糊匹配")
private String code;
@ApiModelProperty(value = "岗位名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 岗位列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostListReqVO extends PostBaseVO {
@ApiModelProperty(value = "岗位名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 岗位分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostPageReqVO extends PageParam {
@ApiModelProperty(value = "岗位编码", example = "yudao", notes = "模糊匹配")
private String code;
@ApiModelProperty(value = "岗位名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@ApiModel("管理后台 - 岗位信息 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostRespVO extends PostBaseVO {
@ApiModelProperty(value = "岗位序号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 岗位精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PostSimpleRespVO {
@ApiModelProperty(value = "岗位编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "岗位名称", required = true, example = "芋道")
private String name;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 岗位更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostUpdateReqVO extends PostBaseVO {
@ApiModelProperty(value = "岗位编号", required = true, example = "1024")
@NotNull(message = "岗位编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,4 @@
### 请求 /menu/list 接口 => 成功
GET {{baseUrl}}/system/dict-data/list-all-simple
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.system.controller.admin.dict;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.*;
import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 字典数据")
@RestController
@RequestMapping("/system/dict-data")
@Validated
public class DictDataController {
@Resource
private DictDataService dictDataService;
@PostMapping("/create")
@ApiOperation("新增字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:create')")
public CommonResult<Long> createDictData(@Valid @RequestBody DictDataCreateReqVO reqVO) {
Long dictDataId = dictDataService.createDictData(reqVO);
return success(dictDataId);
}
@PutMapping("update")
@ApiOperation("修改字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictData(@Valid @RequestBody DictDataUpdateReqVO reqVO) {
dictDataService.updateDictData(reqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除字典数据")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictData(Long id) {
dictDataService.deleteDictData(id);
return success(true);
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地")
// 无需添加权限认证,因为前端全局都需要
public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDatas() {
List<DictDataDO> list = dictDataService.getDictDatas();
return success(DictDataConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("/获得字典类型的分页列表")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictDataRespVO>> getDictTypePage(@Valid DictDataPageReqVO reqVO) {
return success(DictDataConvert.INSTANCE.convertPage(dictDataService.getDictDataPage(reqVO)));
}
@GetMapping(value = "/get")
@ApiOperation("/查询字典数据详细")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<DictDataRespVO> getDictData(@RequestParam("id") Long id) {
return success(DictDataConvert.INSTANCE.convert(dictDataService.getDictData(id)));
}
@GetMapping("/export")
@ApiOperation("导出字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Valid DictDataExportReqVO reqVO) throws IOException {
List<DictDataDO> list = dictDataService.getDictDatas(reqVO);
List<DictDataExcelVO> data = DictDataConvert.INSTANCE.convertList02(list);
// 输出
ExcelUtils.write(response, "字典数据.xls", "数据列表", DictDataExcelVO.class, data);
}
}

View File

@@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.system.controller.admin.dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.*;
import cn.iocoder.yudao.module.system.convert.dict.DictTypeConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
import cn.iocoder.yudao.module.system.service.dict.DictTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 字典类型")
@RestController
@RequestMapping("/system/dict-type")
@Validated
public class DictTypeController {
@Resource
private DictTypeService dictTypeService;
@PostMapping("/create")
@ApiOperation("创建字典类型")
@PreAuthorize("@ss.hasPermission('system:dict:create')")
public CommonResult<Long> createDictType(@Valid @RequestBody DictTypeCreateReqVO reqVO) {
Long dictTypeId = dictTypeService.createDictType(reqVO);
return success(dictTypeId);
}
@PutMapping("/update")
@ApiOperation("修改字典类型")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictType(@Valid @RequestBody DictTypeUpdateReqVO reqVO) {
dictTypeService.updateDictType(reqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除字典类型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictType(Long id) {
dictTypeService.deleteDictType(id);
return success(true);
}
@ApiOperation("/获得字典类型的分页列表")
@GetMapping("/page")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictTypeRespVO>> pageDictTypes(@Valid DictTypePageReqVO reqVO) {
return success(DictTypeConvert.INSTANCE.convertPage(dictTypeService.getDictTypePage(reqVO)));
}
@ApiOperation("/查询字典类型详细")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@GetMapping(value = "/get")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<DictTypeRespVO> getDictType(@RequestParam("id") Long id) {
return success(DictTypeConvert.INSTANCE.convert(dictTypeService.getDictType(id)));
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获得全部字典类型列表", notes = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
// 无需添加权限认证,因为前端全局都需要
public CommonResult<List<DictTypeSimpleRespVO>> listSimpleDictTypes() {
List<DictTypeDO> list = dictTypeService.getDictTypeList();
return success(DictTypeConvert.INSTANCE.convertList(list));
}
@ApiOperation("导出数据类型")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Valid DictTypeExportReqVO reqVO) throws IOException {
List<DictTypeDO> list = dictTypeService.getDictTypeList(reqVO);
List<DictTypeExcelVO> data = DictTypeConvert.INSTANCE.convertList02(list);
// 输出
ExcelUtils.write(response, "字典类型.xls", "类型列表", DictTypeExcelVO.class, data);
}
}

View File

@@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 字典数据 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class DictDataBaseVO {
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@ApiModelProperty(value = "字典标签", required = true, example = "芋道")
@NotBlank(message = "字典标签不能为空")
@Size(max = 100, message = "字典标签长度不能超过100个字符")
private String label;
@ApiModelProperty(value = "字典值", required = true, example = "iocoder")
@NotBlank(message = "字典键值不能为空")
@Size(max = 100, message = "字典键值长度不能超过100个字符")
private String value;
@ApiModelProperty(value = "字典类型", required = true, example = "sys_common_sex")
@NotBlank(message = "字典类型不能为空")
@Size(max = 100, message = "字典类型长度不能超过100个字符")
private String dictType;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
@ApiModelProperty(value = "颜色类型", example = "default", notes = "default、primary、success、info、warning、danger")
private String colorType;
@ApiModelProperty(value = "css 样式", example = "btn-visible")
private String cssClass;
@ApiModelProperty(value = "备注", example = "我是一个角色")
private String remark;
}

View File

@@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 字典数据创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictDataCreateReqVO extends DictDataBaseVO {
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 字典数据 Excel 导出响应 VO
*/
@Data
public class DictDataExcelVO {
@ExcelProperty("字典编码")
private Long id;
@ExcelProperty("字典排序")
private Integer sort;
@ExcelProperty("字典标签")
private String label;
@ExcelProperty("字典键值")
private String value;
@ExcelProperty("字典类型")
private String dictType;
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Size;
@ApiModel("管理后台 - 字典类型导出 Request VO")
@Data
public class DictDataExportReqVO {
@ApiModelProperty(value = "字典标签", example = "芋道")
@Size(max = 100, message = "字典标签长度不能超过100个字符")
private String label;
@ApiModelProperty(value = "字典类型", example = "sys_common_sex", notes = "模糊匹配")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String dictType;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Size;
@ApiModel("管理后台 - 字典类型分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictDataPageReqVO extends PageParam {
@ApiModelProperty(value = "字典标签", example = "芋道")
@Size(max = 100, message = "字典标签长度不能超过100个字符")
private String label;
@ApiModelProperty(value = "字典类型", example = "sys_common_sex", notes = "模糊匹配")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String dictType;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel("管理后台 - 字典数据信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class DictDataRespVO extends DictDataBaseVO {
@ApiModelProperty(value = "字典数据编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("管理后台 - 数据字典精简 Response VO")
@Data
public class DictDataSimpleRespVO {
@ApiModelProperty(value = "字典类型", required = true, example = "gender")
private String dictType;
@ApiModelProperty(value = "字典键值", required = true, example = "1")
private String value;
@ApiModelProperty(value = "字典标签", required = true, example = "")
private String label;
@ApiModelProperty(value = "颜色类型", example = "default", notes = "default、primary、success、info、warning、danger")
private String colorType;
@ApiModelProperty(value = "css 样式", example = "btn-visible")
private String cssClass;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 字典数据更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictDataUpdateReqVO extends DictDataBaseVO {
@ApiModelProperty(value = "字典数据编号", required = true, example = "1024")
@NotNull(message = "字典数据编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 字典类型 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class DictTypeBaseVO {
@ApiModelProperty(value = "字典名称", required = true, example = "性别")
@NotBlank(message = "字典名称不能为空")
@Size(max = 100, message = "字典类型名称长度不能超过100个字符")
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
@NotNull(message = "状态不能为空")
private Integer status;
@ApiModelProperty(value = "备注", example = "快乐的备注")
private String remark;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@ApiModel("管理后台 - 字典类型创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictTypeCreateReqVO extends DictTypeBaseVO {
@ApiModelProperty(value = "字典类型", required = true, example = "sys_common_sex")
@NotNull(message = "字典类型不能为空")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String type;
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 字典类型 Excel 导出响应 VO
*/
@Data
public class DictTypeExcelVO {
@ExcelProperty("字典主键")
private Long id;
@ExcelProperty("字典名称")
private String name;
@ExcelProperty("字典类型")
private String type;
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 字典类型分页列表 Request VO")
@Data
public class DictTypeExportReqVO {
@ApiModelProperty(value = "字典类型名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "字典类型", example = "sys_common_sex", notes = "模糊匹配")
private String type;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Size;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 字典类型分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictTypePageReqVO extends PageParam {
@ApiModelProperty(value = "字典类型名称", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "字典类型", example = "sys_common_sex", notes = "模糊匹配")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String type;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel("管理后台 - 字典类型信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class DictTypeRespVO extends DictTypeBaseVO {
@ApiModelProperty(value = "字典类型编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "字典类型", required = true, example = "sys_common_sex")
private String type;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 字典类型精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DictTypeSimpleRespVO {
@ApiModelProperty(value = "字典类型编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "字典类型名称", required = true, example = "芋道")
private String name;
@ApiModelProperty(value = "字典类型", required = true, example = "sys_common_sex")
private String type;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 字典类型更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictTypeUpdateReqVO extends DictTypeBaseVO {
@ApiModelProperty(value = "字典类型编号", required = true, example = "1024")
@NotNull(message = "字典类型编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,13 @@
### 创建错误码
POST {{baseUrl}}/inra/error-code/create
Authorization: Bearer {{token}}
Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"code": 200,
"message": "成功",
"group": "test",
"type": 1
}

View File

@@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.convert.errorcode.ErrorCodeConvert;
import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO;
import cn.iocoder.yudao.module.system.service.errorcode.ErrorCodeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 错误码")
@RestController
@RequestMapping("/system/error-code")
@Validated
public class ErrorCodeController {
@Resource
private ErrorCodeService errorCodeService;
@PostMapping("/create")
@ApiOperation("创建错误码")
@PreAuthorize("@ss.hasPermission('system:error-code:create')")
public CommonResult<Long> createErrorCode(@Valid @RequestBody ErrorCodeCreateReqVO createReqVO) {
return success(errorCodeService.createErrorCode(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新错误码")
@PreAuthorize("@ss.hasPermission('system:error-code:update')")
public CommonResult<Boolean> updateErrorCode(@Valid @RequestBody ErrorCodeUpdateReqVO updateReqVO) {
errorCodeService.updateErrorCode(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除错误码")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:error-code:delete')")
public CommonResult<Boolean> deleteErrorCode(@RequestParam("id") Long id) {
errorCodeService.deleteErrorCode(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得错误码")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:error-code:query')")
public CommonResult<ErrorCodeRespVO> getErrorCode(@RequestParam("id") Long id) {
ErrorCodeDO errorCode = errorCodeService.getErrorCode(id);
return success(ErrorCodeConvert.INSTANCE.convert(errorCode));
}
@GetMapping("/page")
@ApiOperation("获得错误码分页")
@PreAuthorize("@ss.hasPermission('system:error-code:query')")
public CommonResult<PageResult<ErrorCodeRespVO>> getErrorCodePage(@Valid ErrorCodePageReqVO pageVO) {
PageResult<ErrorCodeDO> pageResult = errorCodeService.getErrorCodePage(pageVO);
return success(ErrorCodeConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出错误码 Excel")
@PreAuthorize("@ss.hasPermission('system:error-code:export')")
@OperateLog(type = EXPORT)
public void exportErrorCodeExcel(@Valid ErrorCodeExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<ErrorCodeDO> list = errorCodeService.getErrorCodeList(exportReqVO);
// 导出 Excel
List<ErrorCodeExcelVO> datas = ErrorCodeConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "错误码.xls", "数据", ErrorCodeExcelVO.class, datas);
}
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 错误码 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class ErrorCodeBaseVO {
@ApiModelProperty(value = "应用名", required = true, example = "dashboard")
@NotNull(message = "应用名不能为空")
private String applicationName;
@ApiModelProperty(value = "错误码编码", required = true, example = "1234")
@NotNull(message = "错误码编码不能为空")
private Integer code;
@ApiModelProperty(value = "错误码错误提示", required = true, example = "帅气")
@NotNull(message = "错误码错误提示不能为空")
private String message;
@ApiModelProperty(value = "备注", example = "哈哈哈")
private String memo;
}

View File

@@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("管理后台 - 错误码创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErrorCodeCreateReqVO extends ErrorCodeBaseVO {
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
//import cn.iocoder.yudao.adminserver.modules.infra.enums.InfDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 错误码 Excel VO
*
* @author 芋道源码
*/
@Data
public class ErrorCodeExcelVO {
@ExcelProperty("错误码编号")
private Long id;
@ExcelProperty(value = "错误码类型", converter = DictConvert.class)
@DictFormat("inf_error_code_type") // TODO 芋艿:得思考下杂解决枚举值
private Integer type;
@ExcelProperty("应用名")
private String applicationName;
@ExcelProperty("错误码编码")
private Integer code;
@ExcelProperty("错误码错误提示")
private String message;
@ExcelProperty("备注")
private String memo;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "管理后台 - 错误码 Excel 导出 Request VO", description = "参数和 InfErrorCodePageReqVO 是一致的")
@Data
public class ErrorCodeExportReqVO {
@ApiModelProperty(value = "错误码类型", example = "1")
private Integer type;
@ApiModelProperty(value = "应用名", example = "dashboard")
private String applicationName;
@ApiModelProperty(value = "错误码编码", example = "1234")
private Integer code;
@ApiModelProperty(value = "错误码错误提示", example = "帅气")
private String message;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 错误码分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErrorCodePageReqVO extends PageParam {
@ApiModelProperty(value = "错误码类型", example = "1", notes = "参见 ErrorCodeTypeEnum 枚举类")
private Integer type;
@ApiModelProperty(value = "应用名", example = "dashboard")
private String applicationName;
@ApiModelProperty(value = "错误码编码", example = "1234")
private Integer code;
@ApiModelProperty(value = "错误码错误提示", example = "帅气")
private String message;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - 错误码 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErrorCodeRespVO extends ErrorCodeBaseVO {
@ApiModelProperty(value = "错误码编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "错误码类型", required = true, example = "1", notes = "参见 ErrorCodeTypeEnum 枚举类")
private Integer type;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 错误码更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErrorCodeUpdateReqVO extends ErrorCodeBaseVO {
@ApiModelProperty(value = "错误码编号", required = true, example = "1024")
@NotNull(message = "错误码编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.system.controller.admin.logger;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogRespVO;
import cn.iocoder.yudao.module.system.convert.logger.LoginLogConvert;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 登录日志")
@RestController
@RequestMapping("/system/login-log")
@Validated
public class LoginLogController {
@Resource
private LoginLogService loginLogService;
@GetMapping("/page")
@ApiOperation("获得登录日志分页列表")
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
public CommonResult<PageResult<LoginLogRespVO>> getLoginLogPage(@Valid LoginLogPageReqVO reqVO) {
PageResult<LoginLogDO> page = loginLogService.getLoginLogPage(reqVO);
return CommonResult.success(LoginLogConvert.INSTANCE.convertPage(page));
}
@GetMapping("/export")
@ApiOperation("导出登录日志 Excel")
@PreAuthorize("@ss.hasPermission('system:login-log:export')")
@OperateLog(type = EXPORT)
public void exportLoginLog(HttpServletResponse response, @Valid LoginLogExportReqVO reqVO) throws IOException {
List<LoginLogDO> list = loginLogService.getLoginLogList(reqVO);
// 拼接数据
List<LoginLogExcelVO> data = LoginLogConvert.INSTANCE.convertList(list);
// 输出
ExcelUtils.write(response, "登录日志.xls", "数据列表", LoginLogExcelVO.class, data);
}
}

View File

@@ -0,0 +1,4 @@
### 请求 /system/operate-log/demo 接口 => 成功
GET {{baseUrl}}/system/operate-log/demo
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@@ -0,0 +1,85 @@
package cn.iocoder.yudao.module.system.controller.admin.logger;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 操作日志")
@RestController
@RequestMapping("/system/operate-log")
@Validated
public class OperateLogController {
@Resource
private OperateLogService operateLogService;
@Resource
private AdminUserService userService;
@GetMapping("/page")
@ApiOperation("查看操作日志分页列表")
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
public CommonResult<PageResult<OperateLogRespVO>> pageOperateLog(@Valid OperateLogPageReqVO reqVO) {
PageResult<OperateLogDO> pageResult = operateLogService.getOperateLogPage(reqVO);
// 获得拼接需要的数据
Collection<Long> userIds = CollectionUtils.convertList(pageResult.getList(), OperateLogDO::getUserId);
Map<Long, AdminUserDO> userMap = userService.getUserMap(userIds);
// 拼接数据
List<OperateLogRespVO> list = new ArrayList<>(pageResult.getList().size());
pageResult.getList().forEach(operateLog -> {
OperateLogRespVO respVO = OperateLogConvert.INSTANCE.convert(operateLog);
list.add(respVO);
// 拼接用户信息
MapUtils.findAndThen(userMap, operateLog.getUserId(), user -> respVO.setUserNickname(user.getNickname()));
});
return success(new PageResult<>(list, pageResult.getTotal()));
}
@ApiOperation("导出操作日志")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
@OperateLog(type = EXPORT)
public void exportOperateLog(HttpServletResponse response, @Valid OperateLogExportReqVO reqVO) throws IOException {
List<OperateLogDO> list = operateLogService.getOperateLogs(reqVO);
// 获得拼接需要的数据
Collection<Long> userIds = CollectionUtils.convertList(list, OperateLogDO::getUserId);
Map<Long, AdminUserDO> userMap = userService.getUserMap(userIds);
// 拼接数据
List<OperateLogExcelVO> excelDataList = OperateLogConvert.INSTANCE.convertList(list, userMap);
// 输出
ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogExcelVO.class, excelDataList);
}
}

View File

@@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 登录日志 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class LoginLogBaseVO {
@ApiModelProperty(value = "日志类型", required = true, example = "1", notes = "参见 LoginLogTypeEnum 枚举类")
@NotNull(message = "日志类型不能为空")
private Integer logType;
@ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
@ApiModelProperty(value = "用户账号", required = true, example = "yudao")
@NotBlank(message = "用户账号不能为空")
@Size(max = 30, message = "用户账号长度不能超过30个字符")
private String username;
@ApiModelProperty(value = "登录结果", required = true, example = "1", notes = "参见 LoginResultEnum 枚举类")
@NotNull(message = "登录结果不能为空")
private Integer result;
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 登录日志 Excel 导出响应 VO
*/
@Data
public class LoginLogExcelVO {
@ExcelProperty("日志主键")
private Long id;
@ExcelProperty("用户账号")
private String username;
@ExcelProperty(value = "日志类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOGIN_TYPE)
private Integer logType;
@ExcelProperty(value = "登录结果", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOGIN_RESULT)
private Integer result;
@ExcelProperty("登录 IP")
private String userIp;
@ExcelProperty("浏览器 UA")
private String userAgent;
@ExcelProperty("登录时间")
private Date createTime;
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 登录日志分页列表 Request VO")
@Data
public class LoginLogExportReqVO {
@ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模拟匹配")
private String userIp;
@ApiModelProperty(value = "用户账号", example = "芋道", notes = "模拟匹配")
private String username;
@ApiModelProperty(value = "操作状态", example = "true")
private Boolean status;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 登录日志分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class LoginLogPageReqVO extends PageParam {
@ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模拟匹配")
private String userIp;
@ApiModelProperty(value = "用户账号", example = "芋道", notes = "模拟匹配")
private String username;
@ApiModelProperty(value = "操作状态", example = "true")
private Boolean status;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.util.Date;
@ApiModel("管理后台 - 登录日志 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class LoginLogRespVO extends LoginLogBaseVO {
@ApiModelProperty(value = "日志编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户编号", required = true, example = "666")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举")
@NotNull(message = "用户类型不能为空")
private Integer userType;
@ApiModelProperty(value = "登录时间", required = true)
private Date createTime;
}

View File

@@ -0,0 +1,85 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class OperateLogBaseVO {
@ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "操作模块", required = true, example = "订单")
@NotEmpty(message = "操作模块不能为空")
private String module;
@ApiModelProperty(value = "操作名", required = true, example = "创建订单")
@NotEmpty(message = "操作名")
private String name;
@ApiModelProperty(value = "操作分类", required = true, example = "1", notes = "参见 OperateLogTypeEnum 枚举类")
@NotNull(message = "操作分类不能为空")
private Integer type;
@ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。")
private String content;
@ApiModelProperty(value = "拓展字段", example = "{'orderId': 1}")
private Map<String, Object> exts;
@ApiModelProperty(value = "请求方法名", required = true, example = "GET")
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
@ApiModelProperty(value = "请求地址", required = true, example = "/xxx/yyy")
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
@ApiModelProperty(value = "Java 方法名", required = true, example = "cn.iocoder.yudao.adminserver.UserController.save(...)")
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
@ApiModelProperty(value = "Java 方法的参数")
private String javaMethodArgs;
@ApiModelProperty(value = "开始时间", required = true)
@NotNull(message = "开始时间不能为空")
private Date startTime;
@ApiModelProperty(value = "执行时长,单位:毫秒", required = true)
@NotNull(message = "执行时长不能为空")
private Integer duration;
@ApiModelProperty(value = "结果码", required = true)
@NotNull(message = "结果码不能为空")
private Integer resultCode;
@ApiModelProperty(value = "结果提示")
private String resultMsg;
@ApiModelProperty(value = "结果数据")
private String resultData;
}

View File

@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 操作日志 Excel 导出响应 VO
*/
@Data
public class OperateLogExcelVO {
@ExcelProperty("日志编号")
private Long id;
@ExcelProperty("操作模块")
private String module;
@ExcelProperty("操作名")
private String name;
@ExcelProperty(value = "操作类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.OPERATE_TYPE)
private String type;
@ExcelProperty("操作人")
private String userNickname;
@ExcelProperty(value = "操作结果") // 成功 or 失败
private String successStr;
@ExcelProperty("操作日志")
private Date startTime;
@ExcelProperty("执行时长")
private Integer duration;
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 操作日志分页列表 Request VO")
@Data
public class OperateLogExportReqVO {
@ApiModelProperty(value = "操作模块", example = "订单", notes = "模拟匹配")
private String module;
@ApiModelProperty(value = "用户昵称", example = "芋道", notes = "模拟匹配")
private String userNickname;
@ApiModelProperty(value = "操作分类", example = "1", notes = "参见 OperateLogTypeEnum 枚举类")
private Integer type;
@ApiModelProperty(value = "操作状态", example = "true")
private Boolean success;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 操作日志分页列表 Request VO")
@Data
public class OperateLogPageReqVO extends PageParam {
@ApiModelProperty(value = "操作模块", example = "订单", notes = "模拟匹配")
private String module;
@ApiModelProperty(value = "用户昵称", example = "芋道", notes = "模拟匹配")
private String userNickname;
@ApiModelProperty(value = "操作分类", example = "1", notes = "参见 OperateLogTypeEnum 枚举类")
private Integer type;
@ApiModelProperty(value = "操作状态", example = "true")
private Boolean success;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("管理后台 - 操作日志 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OperateLogRespVO extends OperateLogBaseVO {
@ApiModelProperty(value = "日志编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String userNickname;
}

View File

@@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.system.controller.admin.notice;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeRespVO;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.notice.NoticeConvert;
import cn.iocoder.yudao.module.system.service.notice.NoticeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 通知公告")
@RestController
@RequestMapping("/system/notice")
@Validated
public class NoticeController {
@Resource
private NoticeService noticeService;
@PostMapping("/create")
@ApiOperation("创建通知公告")
@PreAuthorize("@ss.hasPermission('system:notice:create')")
public CommonResult<Long> createNotice(@Valid @RequestBody NoticeCreateReqVO reqVO) {
Long noticeId = noticeService.createNotice(reqVO);
return success(noticeId);
}
@PutMapping("/update")
@ApiOperation("修改通知公告")
@PreAuthorize("@ss.hasPermission('system:notice:update')")
public CommonResult<Boolean> updateNotice(@Valid @RequestBody NoticeUpdateReqVO reqVO) {
noticeService.updateNotice(reqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除通知公告")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notice:delete')")
public CommonResult<Boolean> deleteNotice(@RequestParam("id") Long id) {
noticeService.deleteNotice(id);
return success(true);
}
@GetMapping("/page")
@ApiOperation("获取通知公告列表")
@PreAuthorize("@ss.hasPermission('system:notice:query')")
public CommonResult<PageResult<NoticeRespVO>> pageNotices(@Validated NoticePageReqVO reqVO) {
return success(NoticeConvert.INSTANCE.convertPage(noticeService.pageNotices(reqVO)));
}
@GetMapping("/get")
@ApiOperation("获得通知公告")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notice:query')")
public CommonResult<NoticeRespVO> getNotice(@RequestParam("id") Long id) {
return success(NoticeConvert.INSTANCE.convert(noticeService.getNotice(id)));
}
}

View File

@@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.notice.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 通知公告 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class NoticeBaseVO {
@ApiModelProperty(value = "公告标题", required = true, example = "小博主")
@NotBlank(message = "公告标题不能为空")
@Size(max = 50, message = "公告标题不能超过50个字符")
private String title;
@ApiModelProperty(value = "公告类型", required = true, example = "小博主")
@NotNull(message = "公告类型不能为空")
private Integer type;
@ApiModelProperty(value = "公告内容", required = true, example = "半生编码")
private String content;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.system.controller.admin.notice.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 通知公告创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class NoticeCreateReqVO extends NoticeBaseVO {
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.controller.admin.notice.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 通知公告分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class NoticePageReqVO extends PageParam {
@ApiModelProperty(value = "通知公告名称", example = "芋道", notes = "模糊匹配")
private String title;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.notice.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@ApiModel("管理后台 - 通知公告信息 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class NoticeRespVO extends NoticeBaseVO {
@ApiModelProperty(value = "通知公告序号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.notice.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 岗位公告更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class NoticeUpdateReqVO extends NoticeBaseVO {
@ApiModelProperty(value = "岗位公告编号", required = true, example = "1024")
@NotNull(message = "岗位公告编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,23 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/oauth2-client/create
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"id": "1",
"secret": "admin123",
"name": "芋道源码",
"logo": "https://www.iocoder.cn/images/favicon.ico",
"description": "我是描述",
"status": 0,
"accessTokenValiditySeconds": 180,
"refreshTokenValiditySeconds": 8640,
"redirectUris": ["https://www.iocoder.cn"],
"autoApprove": true,
"authorizedGrantTypes": ["password"],
"scopes": ["user_info"],
"authorities": ["system:user:query"],
"resource_ids": ["1024"],
"additionalInformation": "{}"
}

View File

@@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - OAuth2 客户端")
@RestController
@RequestMapping("/system/oauth2-client")
@Validated
public class OAuth2ClientController {
@Resource
private OAuth2ClientService oAuth2ClientService;
@PostMapping("/create")
@ApiOperation("创建 OAuth2 客户端")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:create')")
public CommonResult<Long> createOAuth2Client(@Valid @RequestBody OAuth2ClientCreateReqVO createReqVO) {
return success(oAuth2ClientService.createOAuth2Client(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新 OAuth2 客户端")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:update')")
public CommonResult<Boolean> updateOAuth2Client(@Valid @RequestBody OAuth2ClientUpdateReqVO updateReqVO) {
oAuth2ClientService.updateOAuth2Client(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除 OAuth2 客户端")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')")
public CommonResult<Boolean> deleteOAuth2Client(@RequestParam("id") Long id) {
oAuth2ClientService.deleteOAuth2Client(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得 OAuth2 客户端")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
public CommonResult<OAuth2ClientRespVO> getOAuth2Client(@RequestParam("id") Long id) {
OAuth2ClientDO oAuth2Client = oAuth2ClientService.getOAuth2Client(id);
return success(OAuth2ClientConvert.INSTANCE.convert(oAuth2Client));
}
@GetMapping("/page")
@ApiOperation("获得OAuth2 客户端分页")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
public CommonResult<PageResult<OAuth2ClientRespVO>> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) {
PageResult<OAuth2ClientDO> pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO);
return success(OAuth2ClientConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@@ -0,0 +1,54 @@
### 请求 /system/oauth2/authorize 接口 => 成功
GET {{baseUrl}}/system/oauth2/authorize?clientId=default
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/authorize + token 接口 => 成功
POST {{baseUrl}}/system/oauth2/authorize
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
response_type=token&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
### 请求 /system/oauth2/authorize + code 接口 => 成功
POST {{baseUrl}}/system/oauth2/authorize
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=false
### 请求 /system/oauth2/token + code 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a
### 请求 /system/oauth2/token + password 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=password&username=admin&password=admin123&scope=user.read
### 请求 /system/oauth2/token + refresh_token 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588
### 请求 /system/oauth2/token + DELETE 接口 => 成功
DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/check-token 接口 => 成功
POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}

View File

@@ -0,0 +1,298 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.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 芋道源码
*/
@Api(tags = "管理后台 - OAuth2.0 授权")
@RestController
@RequestMapping("/system/oauth2")
@Validated
@Slf4j
public class OAuth2OpenController {
@Resource
private OAuth2GrantService oauth2GrantService;
@Resource
private OAuth2ClientService oauth2ClientService;
@Resource
private OAuth2ApproveService oauth2ApproveService;
@Resource
private OAuth2TokenService oauth2TokenService;
/**
* 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法
*
* 授权码 authorization_code 模式时code + redirectUri + state 参数
* 密码 password 模式时username + password + scope 参数
* 刷新 refresh_token 模式时refreshToken 参数
* 客户端 client_credentials 模式scope 参数
* 简化 implicit 模式时:不支持
*
* 注意,默认需要传递 client_id + client_secret 参数
*/
@PostMapping("/token")
@ApiOperation(value = "获得访问令牌", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
@ApiImplicitParams({
@ApiImplicitParam(name = "grant_type", required = true, value = "授权类型", example = "code", dataTypeClass = String.class),
@ApiImplicitParam(name = "code", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class),
@ApiImplicitParam(name = "redirect_uri", value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class),
@ApiImplicitParam(name = "state", value = "状态", example = "1", dataTypeClass = String.class),
@ApiImplicitParam(name = "username", example = "tudou", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", example = "cai", dataTypeClass = String.class), // 多个使用空格分隔
@ApiImplicitParam(name = "scope", example = "user_info", dataTypeClass = String.class),
@ApiImplicitParam(name = "refresh_token", example = "123424233", dataTypeClass = String.class),
})
@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);
// 授权类型
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 授权模式");
}
// 校验客户端
String[] clientIdAndSecret = obtainBasicAuthorization(request);
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
grantType, scopes, redirectUri);
// 根据授权模式,获取访问令牌
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")
@ApiOperation(value = "删除访问令牌")
@ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class)
@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")
@ApiOperation(value = "校验访问令牌")
@ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class)
@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")
@ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
@ApiImplicitParam(name = "clientId", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class)
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")
@ApiOperation(value = "申请授权", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【提交】调用")
@ApiImplicitParams({
@ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class),
@ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class),
@ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 使用 Map<String, Boolean> 格式Spring MVC 暂时不支持这么接收参数
@ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class),
@ApiImplicitParam(name = "auto_approve", required = true, value = "用户是否接受", example = "true", dataTypeClass = Boolean.class),
@ApiImplicitParam(name = "state", example = "1", dataTypeClass = String.class)
})
@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 cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - OAuth2.0 令牌")
@RestController
@RequestMapping("/system/oauth2-token")
public class OAuth2TokenController {
@Resource
private OAuth2TokenService oauth2TokenService;
@Resource
private AdminAuthService authService;
@GetMapping("/page")
@ApiOperation(value = "获得访问令牌分页", notes = "只返回有效期内的")
@PreAuthorize("@ss.hasPermission('system:oauth2-token:page')")
public CommonResult<PageResult<OAuth2AccessTokenRespVO>> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) {
PageResult<OAuth2AccessTokenDO> pageResult = oauth2TokenService.getAccessTokenPage(reqVO);
return success(OAuth2TokenConvert.INSTANCE.convert(pageResult));
}
@DeleteMapping("/delete")
@ApiOperation("删除访问令牌")
@ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class, 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,14 @@
### 请求 /system/oauth2/user/get 接口 => 成功
GET {{baseUrl}}/system/oauth2/user/get
Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/user/update 接口 => 成功
PUT {{baseUrl}}/system/oauth2/user/update
Content-Type: application/json
Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d
tenant-id: {{adminTenentId}}
{
"nickname": "芋道源码"
}

View File

@@ -0,0 +1,80 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2UserConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.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 芋道源码
*/
@Api(tags = "管理后台 - OAuth2.0 用户")
@RestController
@RequestMapping("/system/oauth2/user")
@Validated
@Slf4j
public class OAuth2UserController {
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@Resource
private PostService postService;
@GetMapping("/get")
@ApiOperation("获得用户基本信息")
@PreAuthorize("@ss.hasScope('user.read')") //
public CommonResult<OAuth2UserInfoRespVO> getUserInfo() {
// 获得用户基本信息
AdminUserDO user = userService.getUser(getLoginUserId());
OAuth2UserInfoRespVO resp = OAuth2UserConvert.INSTANCE.convert(user);
// 获得部门信息
if (user.getDeptId() != null) {
DeptDO dept = deptService.getDept(user.getDeptId());
resp.setDept(OAuth2UserConvert.INSTANCE.convert(dept));
}
// 获得岗位信息
if (CollUtil.isNotEmpty(user.getPostIds())) {
List<PostDO> posts = postService.getPosts(user.getPostIds());
resp.setPosts(OAuth2UserConvert.INSTANCE.convertList(posts));
}
return success(resp);
}
@PutMapping("/update")
@ApiOperation("更新用户基本信息")
@PreAuthorize("@ss.hasScope('user.write')")
public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) {
// 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。
// 主要是AdminUserService 没有自己的 BO 对象,所以复用只能这么做
userService.updateUserProfile(getLoginUserId(), OAuth2UserConvert.INSTANCE.convert(reqVO));
return success(true);
}
}

View File

@@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* OAuth2 客户端 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class OAuth2ClientBaseVO {
@ApiModelProperty(value = "客户端编号", required = true, example = "tudou")
@NotNull(message = "客户端编号不能为空")
private String clientId;
@ApiModelProperty(value = "客户端密钥", required = true, example = "fan")
@NotNull(message = "客户端密钥不能为空")
private String secret;
@ApiModelProperty(value = "应用名", required = true, example = "土豆")
@NotNull(message = "应用名不能为空")
private String name;
@ApiModelProperty(value = "应用图标", required = true, example = "https://www.iocoder.cn/xx.png")
@NotNull(message = "应用图标不能为空")
@URL(message = "应用图标的地址不正确")
private String logo;
@ApiModelProperty(value = "应用描述", example = "我是一个应用")
private String description;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
private Integer status;
@ApiModelProperty(value = "访问令牌的有效期", required = true, example = "8640")
@NotNull(message = "访问令牌的有效期不能为空")
private Integer accessTokenValiditySeconds;
@ApiModelProperty(value = "刷新令牌的有效期", required = true, example = "8640000")
@NotNull(message = "刷新令牌的有效期不能为空")
private Integer refreshTokenValiditySeconds;
@ApiModelProperty(value = "可重定向的 URI 地址", required = true, example = "https://www.iocoder.cn")
@NotNull(message = "可重定向的 URI 地址不能为空")
private List<@NotEmpty(message = "重定向的 URI 不能为空")
@URL(message = "重定向的 URI 格式不正确") String> redirectUris;
@ApiModelProperty(value = "授权类型", required = true, example = "password", notes = "参见 OAuth2GrantTypeEnum 枚举")
@NotNull(message = "授权类型不能为空")
private List<String> authorizedGrantTypes;
@ApiModelProperty(value = "授权范围", example = "user_info")
private List<String> scopes;
@ApiModelProperty(value = "自动通过的授权范围", example = "user_info")
private List<String> autoApproveScopes;
@ApiModelProperty(value = "权限", example = "system:user:query")
private List<String> authorities;
@ApiModelProperty(value = "资源", example = "1024")
private List<String> resourceIds;
@ApiModelProperty(value = "附加信息", example = "{yunai: true}")
private String additionalInformation;
@AssertTrue(message = "附加信息必须是 JSON 格式")
public boolean isAdditionalInformationJson() {
return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation);
}
}

View File

@@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import lombok.*;
import io.swagger.annotations.*;
@ApiModel("管理后台 - OAuth2 客户端创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientCreateReqVO extends OAuth2ClientBaseVO {
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import lombok.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ApiModel("管理后台 - OAuth2 客户端分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientPageReqVO extends PageParam {
@ApiModelProperty(value = "应用名", example = "土豆", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "状态", example = "1", notes = "参见 CommonStatusEnum 枚举")
private Integer status;
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - OAuth2 客户端 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientRespVO extends OAuth2ClientBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

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