Merge branch 'master' of gitee.com:zhijiantianya/ruoyi-vue-pro into feature/ut-job

This commit is contained in:
neilz 2021-03-14 12:36:52 +08:00
commit 08bc389ba5
46 changed files with 1791 additions and 948 deletions

4
lombok.config Normal file
View File

@ -0,0 +1,4 @@
config.stopBubbling = true
lombok.tostring.callsuper=true
lombok.equalsandhashcode.callsuper=true
lombok.accessors.chain=true

View File

@ -8,3 +8,19 @@ export function exportHtml() {
responseType: 'blob'
})
}
export function exportWord() {
return request({
url: '/infra/db-doc/export-word',
method: 'get',
responseType: 'blob'
})
}
export function exportMarkdown() {
return request({
url: '/infra/db-doc/export-markdown',
method: 'get',
responseType: 'blob'
})
}

View File

@ -25,7 +25,10 @@ import {
download,
handleTree,
downloadExcel,
downloadZip
downloadWord,
downloadZip,
downloadHtml,
downloadMarkdown,
} from "@/utils/ruoyi";
import Pagination from "@/components/Pagination";
// 自定义表格工具扩展
@ -48,6 +51,9 @@ Vue.prototype.getDictDataLabel = getDictDataLabel
Vue.prototype.DICT_TYPE = DICT_TYPE
Vue.prototype.download = download
Vue.prototype.downloadExcel = downloadExcel
Vue.prototype.downloadWord = downloadWord
Vue.prototype.downloadHtml = downloadHtml
Vue.prototype.downloadMarkdown = downloadMarkdown
Vue.prototype.downloadZip = downloadZip
Vue.prototype.handleTree = handleTree

View File

@ -120,11 +120,26 @@ export function downloadExcel(data, fileName) {
download0(data, fileName, 'application/vnd.ms-excel');
}
// 下载 Word 方法
export function downloadWord(data, fileName) {
download0(data, fileName, 'application/msword');
}
// 下载 Zip 方法
export function downloadZip(data, fileName) {
download0(data, fileName, 'application/zip');
}
// 下载 Html 方法
export function downloadHtml(data, fileName) {
download0(data, fileName, 'text/html');
}
// 下载 Markdown 方法
export function downloadMarkdown(data, fileName) {
download0(data, fileName, 'text/markdown');
}
function download0(data, fileName, mineType) {
// 创建 blob
let blob = new Blob([data], {type: mineType});

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,21 @@
<template>
<div v-loading="loading" :style="'height:'+ height">
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
<div class="app-container">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportHtml">导出 HTML</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportWord">导出 Word</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportMarkdown">导出 Markdown</el-button>
</el-col>
</el-row>
<!-- 展示文档 -->
<div v-loading="loading" :style="'height:'+ height">
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
</div>
</div>
</template>
<script>
import {exportHtml} from "@/api/infra/dbDoc";
import { exportHtml, exportWord, exportMarkdown} from "@/api/infra/dbDoc";
export default {
name: "DBDoc",
@ -25,10 +36,31 @@ export default {
};
},
created() {
// Html
exportHtml().then(response => {
// var blob = new Blob(['<a id="a"><b id="b">hey!</b></a>'], {type : 'text/html'});
this.src = window.URL.createObjectURL(response);
let blob = new Blob([response], {type : 'text/html'});
this.src = window.URL.createObjectURL(blob);
})
},
methods: {
/** 处理导出 HTML */
handleExportHtml() {
exportHtml().then(response => {
this.downloadHtml(response, '数据库文档.html');
})
},
/** 处理导出 Word */
handleExportWord() {
exportWord().then(response => {
this.downloadWord(response, '数据库文档.doc');
})
},
/** 处理导出 Markdown */
handleExportMarkdown() {
exportMarkdown().then(response => {
this.downloadMarkdown(response, '数据库文档.md');
})
}
}
};
</script>

View File

@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.logger.apilog.core.service;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiAccessLogCreateDTO;
import javax.validation.Valid;
import java.util.concurrent.Future;
/**
* API 访问日志 Framework Service 接口
@ -15,7 +16,8 @@ public interface ApiAccessLogFrameworkService {
* 创建 API 访问日志
*
* @param createDTO 创建信息
* @return 是否创建成功
*/
void createApiAccessLogAsync(@Valid ApiAccessLogCreateDTO createDTO);
Future<Boolean> createApiAccessLogAsync(@Valid ApiAccessLogCreateDTO createDTO);
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.logger.apilog.core.service;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO;
import javax.validation.Valid;
import java.util.concurrent.Future;
/**
* API 错误日志 Framework Service 接口
@ -15,7 +16,8 @@ public interface ApiErrorLogFrameworkService {
* 创建 API 错误日志
*
* @param createDTO 创建信息
* @return 是否创建成功
*/
void createApiErrorLogAsync(@Valid ApiErrorLogCreateDTO createDTO);
Future<Boolean> createApiErrorLogAsync(@Valid ApiErrorLogCreateDTO createDTO);
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.dashboard.modules.infra.controller.doc;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.dashboard.util.servlet.ServletUtils;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
@ -10,18 +12,18 @@ import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
@Api(tags = "数据库文档")
@ -34,36 +36,79 @@ public class InfDbDocController {
private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
+ "db-doc";
private static final EngineFileType FILE_OUTPUT_TYPE = EngineFileType.HTML; // 可以设置 Word 或者 Markdown 格式
private static final String DOC_FILE_NAME = "数据库文档";
private static final String DOC_VERSION = "1.0.0";
private static final String DOC_DESCRIPTION = "文档描述";
@Resource
private DataSource dataSource;
@GetMapping("/export-html")
public synchronized void exportHtml(HttpServletResponse response) throws FileNotFoundException {
@ApiOperation("导出 html 格式的数据文档")
@ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", dataTypeClass = Boolean.class)
public void exportHtml(@RequestParam(defaultValue = "true") Boolean deleteFile,
HttpServletResponse response) throws IOException {
doExportFile(EngineFileType.HTML, deleteFile, response);
}
@GetMapping("/export-word")
@ApiOperation("导出 word 格式的数据文档")
@ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", dataTypeClass = Boolean.class)
public void exportWord(@RequestParam(defaultValue = "true") Boolean deleteFile,
HttpServletResponse response) throws IOException {
doExportFile(EngineFileType.WORD, deleteFile, response);
}
@GetMapping("/export-markdown")
@ApiOperation("导出 markdown 格式的数据文档")
@ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", dataTypeClass = Boolean.class)
public void exportMarkdown(@RequestParam(defaultValue = "true") Boolean deleteFile,
HttpServletResponse response) throws IOException {
doExportFile(EngineFileType.MD, deleteFile, response);
}
private void doExportFile(EngineFileType fileOutputType, Boolean deleteFile,
HttpServletResponse response) throws IOException {
String docFileName = DOC_FILE_NAME + "_" + IdUtil.fastSimpleUUID();
String filePath = doExportFile(fileOutputType, docFileName);
String downloadFileName = DOC_FILE_NAME + fileOutputType.getFileSuffix(); //下载后的文件名
try {
// 读取返回
ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath));
} finally {
handleDeleteFile(deleteFile, filePath);
}
}
/**
* 输出文件返回文件路径
*
* @param fileOutputType 文件类型
* @param fileName 文件名, 无需 ".docx" 等文件后缀
* @return 生成的文件所在路径
*/
private String doExportFile(EngineFileType fileOutputType, String fileName) {
try (HikariDataSource dataSource = buildDataSource()) {
// 创建 screw 的配置
Configuration config = Configuration.builder()
.version(DOC_VERSION) // 版本
.description(DOC_DESCRIPTION) // 描述
.dataSource(dataSource) // 数据源
.engineConfig(buildEngineConfig()) // 引擎配置
.engineConfig(buildEngineConfig(fileOutputType, fileName)) // 引擎配置
.produceConfig(buildProcessConfig()) // 处理配置
.build();
// 执行 screw生成数据库文档
new DocumentationExecute(config).execute();
// 读取返回
ServletUtil.write(response,
new FileInputStream(FILE_OUTPUT_DIR + File.separator + DOC_FILE_NAME + FILE_OUTPUT_TYPE.getFileSuffix()),
MediaType.TEXT_HTML_VALUE);
return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix();
}
}
private void handleDeleteFile(Boolean deleteFile, String filePath) {
if (!deleteFile) {
return;
}
FileUtil.del(filePath);
}
/**
* 创建数据源
*/
@ -71,7 +116,6 @@ public class InfDbDocController {
private HikariDataSource buildDataSource() {
// 创建 HikariConfig 配置类
HikariConfig hikariConfig = new HikariConfig();
// hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariConfig.setJdbcUrl(dataSourceProperties.getUrl());
hikariConfig.setUsername(dataSourceProperties.getUsername());
hikariConfig.setPassword(dataSourceProperties.getPassword());
@ -83,13 +127,13 @@ public class InfDbDocController {
/**
* 创建 screw 的引擎配置
*/
private static EngineConfig buildEngineConfig() {
private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) {
return EngineConfig.builder()
.fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径
.openOutputDir(false) // 打开目录
.fileType(FILE_OUTPUT_TYPE) // 文件类型
.fileType(fileOutputType) // 文件类型
.produceType(EngineTemplateType.freemarker) // 文件类型
.fileName(DOC_FILE_NAME) // 自定义文件名称
.fileName(docFileName) // 自定义文件名称
.build();
}

View File

@ -14,7 +14,7 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU
public class InfApiErrorLogExportReqVO {
@ApiModelProperty(value = "用户编号", example = "666")
private Integer userId;
private Long userId;
@ApiModelProperty(value = "用户类型", example = "1")
private Integer userType;

View File

@ -19,7 +19,7 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU
public class InfApiErrorLogPageReqVO extends PageParam {
@ApiModelProperty(value = "用户编号", example = "666")
private Integer userId;
private Long userId;
@ApiModelProperty(value = "用户类型", example = "1")
private Integer userType;

View File

@ -37,7 +37,7 @@ public class InfApiAccessLogDO extends BaseDO {
/**
* 用户编号
*/
private Integer userId;
private Long userId;
/**
* 用户类型
*

View File

@ -30,7 +30,7 @@ public class InfApiErrorLogDO extends BaseDO {
/**
* 用户编号
*/
private Integer userId;
private Long userId;
/**
* 链路追踪编号
*
@ -148,6 +148,6 @@ public class InfApiErrorLogDO extends BaseDO {
*
* 关联 {@link SysUserDO#getId()}
*/
private Integer processUserId;
private Long processUserId;
}

View File

@ -43,7 +43,7 @@ public class InfJobServiceImpl implements InfJobService {
private SchedulerManager schedulerManager;
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public Long createJob(InfJobCreateReqVO createReqVO) throws SchedulerException {
validateCronExpression(createReqVO.getCronExpression());
// 校验唯一性
@ -68,7 +68,7 @@ public class InfJobServiceImpl implements InfJobService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void updateJob(InfJobUpdateReqVO updateReqVO) throws SchedulerException {
validateCronExpression(updateReqVO.getCronExpression());
// 校验存在
@ -88,7 +88,7 @@ public class InfJobServiceImpl implements InfJobService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void updateJobStatus(Long id, Integer status) throws SchedulerException {
// 校验 status
if (!containsAny(status, InfJobStatusEnum.NORMAL.getStatus(), InfJobStatusEnum.STOP.getStatus())) {
@ -122,7 +122,7 @@ public class InfJobServiceImpl implements InfJobService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void deleteJob(Long id) throws SchedulerException {
// 校验存在
InfJobDO job = this.validateJobExists(id);

View File

@ -9,12 +9,13 @@ import cn.iocoder.dashboard.modules.infra.dal.dataobject.logger.InfApiAccessLogD
import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiAccessLogMapper;
import cn.iocoder.dashboard.modules.infra.service.logger.InfApiAccessLogService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.concurrent.Future;
/**
* API 访问日志 Service 实现类
@ -30,10 +31,11 @@ public class InfApiAccessLogServiceImpl implements InfApiAccessLogService {
@Override
@Async
public void createApiAccessLogAsync(ApiAccessLogCreateDTO createDTO) {
public Future<Boolean> createApiAccessLogAsync(ApiAccessLogCreateDTO createDTO) {
// 插入
InfApiAccessLogDO apiAccessLog = InfApiAccessLogConvert.INSTANCE.convert(createDTO);
apiAccessLogMapper.insert(apiAccessLog);
int insert = apiAccessLogMapper.insert(apiAccessLog);
return new AsyncResult<>(insert == 1);
}
@Override

View File

@ -10,12 +10,14 @@ import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiErrorLogMapper;
import cn.iocoder.dashboard.modules.infra.enums.logger.InfApiErrorLogProcessStatusEnum;
import cn.iocoder.dashboard.modules.infra.service.logger.InfApiErrorLogService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_NOT_FOUND;
@ -35,10 +37,11 @@ public class InfApiErrorLogServiceImpl implements InfApiErrorLogService {
@Override
@Async
public void createApiErrorLogAsync(ApiErrorLogCreateDTO createDTO) {
public Future<Boolean> createApiErrorLogAsync(ApiErrorLogCreateDTO createDTO) {
InfApiErrorLogDO apiErrorLog = InfApiErrorLogConvert.INSTANCE.convert(createDTO);
apiErrorLog.setProcessStatus(InfApiErrorLogProcessStatusEnum.INIT.getStatus());
apiErrorLogMapper.insert(apiErrorLog);
int insert = apiErrorLogMapper.insert(apiErrorLog);
return new AsyncResult<>(insert == 1);
}
@Override
@ -62,7 +65,7 @@ public class InfApiErrorLogServiceImpl implements InfApiErrorLogService {
}
// 标记处理
apiErrorLogMapper.updateById(InfApiErrorLogDO.builder().id(id).processStatus(processStatus)
.processUserId(processStatus).processTime(new Date()).build());
.processUserId(processUserId).processTime(new Date()).build());
}
}

View File

@ -21,8 +21,8 @@ public class SysCaptchaController {
@Resource
private SysCaptchaService captchaService;
@ApiOperation("生成图片验证码")
@GetMapping("/get-image")
@ApiOperation("生成图片验证码")
public CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
return success(captchaService.getCaptchaImage());
}

View File

@ -40,8 +40,8 @@ public class SysUserController {
@Resource
private SysDeptService deptService;
@ApiOperation("获得用户分页列表")
@GetMapping("/page")
@ApiOperation("获得用户分页列表")
@PreAuthorize("@ss.hasPermission('system:user:list')")
public CommonResult<PageResult<SysUserPageItemRespVO>> pageUsers(@Validated SysUserPageReqVO reqVO) {
// 获得用户分页列表
@ -66,9 +66,9 @@ public class SysUserController {
/**
* 根据用户编号获取详细信息
*/
@GetMapping("/get")
@ApiOperation("获得用户详情")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@GetMapping("/get")
// @PreAuthorize("@ss.hasPermi('system:user:query')")
public CommonResult<SysUserRespVO> getInfo(@RequestParam("id") Long id) {
return success(SysUserConvert.INSTANCE.convert(userService.getUser(id)));

View File

@ -1,92 +1,80 @@
package cn.iocoder.dashboard.modules.system.controller.user;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileUpdateReqVO;
import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
import cn.iocoder.dashboard.modules.system.convert.user.SysUserConvert;
import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService;
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
import cn.iocoder.dashboard.util.collection.CollectionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_IS_EMPTY;
/**
* @author niudehua
*/
@RestController
@RequestMapping("/system/user/profile")
@Api(tags = "用户个人中心")
@Slf4j
public class SysUserProfileController {
// /**
// * 个人信息
// */
// @GetMapping
// public AjaxResult profile()
// {
// LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
// SysUser user = loginUser.getUser();
// AjaxResult ajax = AjaxResult.success(user);
// ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
// ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
// return ajax;
// }
//
// /**
// * 修改用户
// */
// @Log(title = "个人信息", businessType = BusinessType.UPDATE)
// @PutMapping
// public AjaxResult updateProfile(@RequestBody SysUser user)
// {
// if (userService.updateUserProfile(user) > 0)
// {
// LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
// // 更新缓存用户信息
// loginUser.getUser().setNickName(user.getNickName());
// loginUser.getUser().setPhonenumber(user.getPhonenumber());
// loginUser.getUser().setEmail(user.getEmail());
// loginUser.getUser().setSex(user.getSex());
// tokenService.setLoginUser(loginUser);
// return AjaxResult.success();
// }
// return AjaxResult.error("修改个人信息异常,请联系管理员");
// }
//
// /**
// * 重置密码
// */
// @Log(title = "个人信息", businessType = BusinessType.UPDATE)
// @PutMapping("/updatePwd")
// public AjaxResult updatePwd(String oldPassword, String newPassword)
// {
// LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
// String userName = loginUser.getUsername();
// String password = loginUser.getPassword();
// if (!SecurityUtils.matchesPassword(oldPassword, password))
// {
// return AjaxResult.error("修改密码失败,旧密码错误");
// }
// if (SecurityUtils.matchesPassword(newPassword, password))
// {
// return AjaxResult.error("新密码不能与旧密码相同");
// }
// if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0)
// {
// // 更新缓存用户密码
// loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
// tokenService.setLoginUser(loginUser);
// return AjaxResult.success();
// }
// return AjaxResult.error("修改密码异常,请联系管理员");
// }
//
// /**
// * 头像上传
// */
// @Log(title = "用户头像", businessType = BusinessType.UPDATE)
// @PostMapping("/avatar")
// public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws IOException
// {
// if (!file.isEmpty())
// {
// LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
// String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
// if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
// {
// AjaxResult ajax = AjaxResult.success();
// ajax.put("imgUrl", avatar);
// // 更新缓存用户头像
// loginUser.getUser().setAvatar(avatar);
// tokenService.setLoginUser(loginUser);
// return ajax;
// }
// }
// return AjaxResult.error("上传图片异常,请联系管理员");
// }
@Resource
private SysUserService userService;
@Resource
private SysPermissionService permissionService;
@Resource
private SysRoleService roleService;
@GetMapping("/get")
@ApiOperation("获得登录用户信息")
public CommonResult<SysUserProfileRespVO> profile() {
// 获取用户信息
Long userId = SecurityFrameworkUtils.getLoginUserId();
SysUserDO user = userService.getUser(userId);
SysUserProfileRespVO userProfileRespVO = SysUserConvert.INSTANCE.convert03(user);
List<SysRoleDO> userRoles = roleService.listRolesFromCache(permissionService.listUserRoleIs(userId));
userProfileRespVO.setRoles(CollectionUtils.convertSet(userRoles, SysUserConvert.INSTANCE::convert));
return success(userProfileRespVO);
}
@PostMapping("/update")
@ApiOperation("修改用户个人信息")
public CommonResult<Boolean> updateProfile(@RequestBody SysUserProfileUpdateReqVO reqVO, HttpServletRequest request) {
userService.updateUserProfile(reqVO);
SecurityFrameworkUtils.setLoginUser(SysAuthConvert.INSTANCE.convert(reqVO), request);
return success(true);
}
@PostMapping("/upload-avatar")
@ApiOperation("上传用户个人头像")
public CommonResult<Boolean> uploadAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException {
if (file.isEmpty()) {
throw ServiceExceptionUtil.exception(FILE_IS_EMPTY);
}
userService.updateAvatar(SecurityFrameworkUtils.getLoginUserId(), file.getInputStream());
return success(true);
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.dashboard.modules.system.controller.user.vo.user;
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.Set;
@ApiModel("用户个人中心信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class SysUserProfileRespVO extends SysUserRespVO {
/**
* 所属角色
*/
@ApiModelProperty(value = "所属角色", required = true, example = "123456")
private Set<Role> roles;
@ApiModel("角色")
@Data
public static class Role {
@ApiModelProperty(value = "角色编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "角色名称", required = true, example = "普通角色")
private String name;
}
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.dashboard.modules.system.controller.user.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@ApiModel("用户个人信息更新 Request VO")
@Data
public class SysUserProfileUpdateReqVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
@NotNull(message = "用户编号不能为空")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
@Size(max = 30, message = "用户昵称长度不能超过30个字符")
private String nickname;
@ApiModelProperty(value = "用户邮箱", example = "yudao@iocoder.cn")
@Email(message = "邮箱格式不正确")
@Size(max = 50, message = "邮箱长度不能超过50个字符")
private String email;
@ApiModelProperty(value = "手机号码", example = "15601691300")
@Size(max = 11, message = "手机号码长度不能超过11个字符")
private String mobile;
@ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SysSexEnum 枚举类")
private Integer sex;
@ApiModelProperty(value = "用户头像", example = "http://www.iocoder.cn/xxx.png")
private String avatar;
@ApiModelProperty(value = "旧密码", required = true, example = "123456")
private String oldPassword;
@ApiModelProperty(value = "新密码", required = true, example = "654321")
private String newPassword;
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.convert.auth;
import cn.iocoder.dashboard.framework.security.core.LoginUser;
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO;
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthPermissionInfoRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
@ -13,26 +14,33 @@ import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Mapper
public interface SysAuthConvert {
SysAuthConvert INSTANCE = Mappers.getMapper(SysAuthConvert.class);
@Mapping(source = "updateTime", target = "updateTime", ignore = true) // 字段相同但是含义不同忽略
@Mapping(source = "updateTime", target = "updateTime", ignore = true)
// 字段相同但是含义不同忽略
LoginUser convert(SysUserDO bean);
default SysAuthPermissionInfoRespVO convert(SysUserDO user, List<SysRoleDO> roleList, List<SysMenuDO> menuList) {
return SysAuthPermissionInfoRespVO.builder()
.user(SysAuthPermissionInfoRespVO.UserVO.builder().nickname(user.getNickname()).avatar(user.getAvatar()).build())
.roles(CollectionUtils.convertSet(roleList, SysRoleDO::getCode))
.permissions(CollectionUtils.convertSet(menuList, SysMenuDO::getPermission))
.build();
.user(SysAuthPermissionInfoRespVO.UserVO.builder().nickname(user.getNickname()).avatar(user.getAvatar()).build())
.roles(CollectionUtils.convertSet(roleList, SysRoleDO::getCode))
.permissions(CollectionUtils.convertSet(menuList, SysMenuDO::getPermission))
.build();
}
SysAuthMenuRespVO convertTreeNode(SysMenuDO menu);
LoginUser convert(SysUserProfileUpdateReqVO reqVO);
/**
* 将菜单列表构建成菜单树
*
@ -47,12 +55,12 @@ public interface SysAuthConvert {
Map<Long, SysAuthMenuRespVO> treeNodeMap = new LinkedHashMap<>();
menuList.forEach(menu -> treeNodeMap.put(menu.getId(), SysAuthConvert.INSTANCE.convertTreeNode(menu)));
// 处理父子关系
treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach((childNode) -> {
treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach(childNode -> {
// 获得父节点
SysAuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId());
if (parentNode == null) {
LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
childNode.getId(), childNode.getParentId());
childNode.getId(), childNode.getParentId());
return;
}
// 将自己添加到父节点中

View File

@ -1,7 +1,14 @@
package cn.iocoder.dashboard.modules.system.convert.user;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.*;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserExcelVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserImportExcelVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageItemRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileUpdateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -23,4 +30,12 @@ public interface SysUserConvert {
SysUserDO convert(SysUserImportExcelVO bean);
SysUserProfileRespVO convert03(SysUserDO bean);
SysUserProfileRespVO.Role convert(SysRoleDO bean);
SysUserDO convert(SysUserProfileUpdateReqVO bean);
}

View File

@ -40,6 +40,7 @@ public interface SysErrorCodeConstants {
ErrorCode USER_EMAIL_EXISTS = new ErrorCode(1002004002, "邮箱已经存在");
ErrorCode USER_NOT_EXISTS = new ErrorCode(1002004003, "用户不存在");
ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1002004004, "导入用户数据不能为空!");
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1002004005, "用户密码校验失败");
// ========== 部门模块 1002005000 ==========
ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1002004001, "已经存在该名字的部门");
@ -74,5 +75,7 @@ public interface SysErrorCodeConstants {
// ========== 文件 1002009000 ==========
ErrorCode FILE_PATH_EXISTS = new ErrorCode(1002009001, "文件路径已经存在");
ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败");
ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空");
}

View File

@ -206,7 +206,7 @@ public class SysMenuServiceImpl implements SysMenuService {
*
* @param menuId 菜单编号
*/
@Transactional
@Transactional(rollbackFor = Exception.class)
public void deleteMenu(Long menuId) {
// 校验更新的菜单是否存在
if (menuMapper.selectById(menuId) == null) {

View File

@ -176,7 +176,7 @@ public class SysPermissionServiceImpl implements SysPermissionService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
// 获得角色拥有菜单编号
Set<Long> dbMenuIds = CollectionUtils.convertSet(roleMenuMapper.selectListByRoleId(roleId),

View File

@ -174,7 +174,7 @@ public class SysRoleServiceImpl implements SysRoleService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void deleteRole(Long id) {
// 校验是否可以更新
this.checkUpdateRole(id);

View File

@ -2,10 +2,17 @@ package cn.iocoder.dashboard.modules.system.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.*;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserImportExcelVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserImportRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileUpdateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.util.collection.CollectionUtils;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -102,6 +109,14 @@ public interface SysUserService {
*/
void updateUser(SysUserUpdateReqVO reqVO);
/**
* 修改用户个人信息
*
* @param reqVO 用户个人信息
* @return 修改结果
*/
void updateUserProfile(SysUserProfileUpdateReqVO reqVO);
/**
* 删除用户
*
@ -112,7 +127,7 @@ public interface SysUserService {
/**
* 修改密码
*
* @param id 用户编号
* @param id 用户编号
* @param password 密码
*/
void updateUserPassword(Long id, String password);
@ -120,7 +135,7 @@ public interface SysUserService {
/**
* 修改密码
*
* @param id 用户编号
* @param id 用户编号
* @param status 状态
*/
void updateUserStatus(Long id, Integer status);
@ -128,12 +143,20 @@ public interface SysUserService {
/**
* 批量导入用户
*
* @param importUsers 导入用户列表
* @param importUsers 导入用户列表
* @param isUpdateSupport 是否支持更新
* @return 导入结果
*/
SysUserImportRespVO importUsers(List<SysUserImportExcelVO> importUsers, boolean isUpdateSupport);
/**
* 更新用户头像
*
* @param id 用户 id
* @param avatarFile 头像文件
*/
void updateAvatar(Long id, InputStream avatarFile);
//
// /**
// * 修改用户基本信息

View File

@ -1,17 +1,26 @@
package cn.iocoder.dashboard.modules.system.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.exception.ServiceException;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.*;
import cn.iocoder.dashboard.modules.infra.service.file.InfFileService;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserImportExcelVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserImportRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserProfileUpdateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.convert.user.SysUserConvert;
import cn.iocoder.dashboard.modules.system.dal.mysql.user.SysUserMapper;
import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysPostDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.user.SysUserMapper;
import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService;
import cn.iocoder.dashboard.modules.system.service.dept.SysPostService;
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
@ -22,7 +31,14 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
@ -49,18 +65,8 @@ public class SysUserServiceImpl implements SysUserService {
@Resource
private PasswordEncoder passwordEncoder;
// /**
// * 根据条件分页查询用户列表
// *
// * @param user 用户信息
// * @return 用户信息集合信息
// */
// @Override
// @DataScope(deptAlias = "d", userAlias = "u")
// public List<SysUser> selectUserList(SysUser user)
// {
// return userMapper.selectUserList(user);
// }
@Resource
private InfFileService fileService;
@Override
public SysUserDO getUserByUserName(String username) {
@ -108,7 +114,7 @@ public class SysUserServiceImpl implements SysUserService {
return Collections.emptySet();
}
Set<Long> deptIds = CollectionUtils.convertSet(deptService.listDeptsByParentIdFromCache(
deptId, true), SysDeptDO::getId);
deptId, true), SysDeptDO::getId);
deptIds.add(deptId); // 包括自身
return deptIds;
}
@ -117,7 +123,7 @@ public class SysUserServiceImpl implements SysUserService {
public Long createUser(SysUserCreateReqVO reqVO) {
// 校验正确性
this.checkCreateOrUpdate(null, reqVO.getUsername(), reqVO.getMobile(), reqVO.getEmail(),
reqVO.getDeptId(), reqVO.getPostIds());
reqVO.getDeptId(), reqVO.getPostIds());
// 插入用户
SysUserDO user = SysUserConvert.INSTANCE.convert(reqVO);
user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
@ -130,12 +136,31 @@ public class SysUserServiceImpl implements SysUserService {
public void updateUser(SysUserUpdateReqVO reqVO) {
// 校验正确性
this.checkCreateOrUpdate(reqVO.getId(), reqVO.getUsername(), reqVO.getMobile(), reqVO.getEmail(),
reqVO.getDeptId(), reqVO.getPostIds());
reqVO.getDeptId(), reqVO.getPostIds());
// 更新用户
SysUserDO updateObj = SysUserConvert.INSTANCE.convert(reqVO);
userMapper.updateById(updateObj);
}
@Override
public void updateUserProfile(SysUserProfileUpdateReqVO reqVO) {
// 校验正确性
this.checkUserExists(reqVO.getId());
this.checkEmailUnique(reqVO.getId(), reqVO.getEmail());
this.checkMobileUnique(reqVO.getId(), reqVO.getMobile());
// 校验填写密码
String encode = null;
if (this.checkOldPassword(reqVO.getId(), reqVO.getOldPassword(), reqVO.getNewPassword())) {
// 更新密码
encode = passwordEncoder.encode(reqVO.getNewPassword());
}
SysUserDO updateObj = SysUserConvert.INSTANCE.convert(reqVO);
if (StrUtil.isNotBlank(encode)) {
updateObj.setPassword(encode);
}
userMapper.updateById(updateObj);
}
@Override
public void deleteUser(Long id) {
// 校验用户存在
@ -278,19 +303,42 @@ public class SysUserServiceImpl implements SysUserService {
});
}
/**
* 校验旧密码新密码
*
* @param id 用户 id
* @param oldPassword 旧密码
* @param newPassword 新密码
* @return 校验结果
*/
private boolean checkOldPassword(Long id, String oldPassword, String newPassword) {
if (id == null || StrUtil.isBlank(oldPassword) || StrUtil.isBlank(newPassword)) {
return false;
}
SysUserDO user = userMapper.selectById(id);
if (user == null) {
throw ServiceExceptionUtil.exception(USER_NOT_EXISTS);
}
if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
throw ServiceExceptionUtil.exception(USER_PASSWORD_FAILED);
}
return true;
}
@Override
@Transactional // 添加事务异常则回滚所有导入
@Transactional(rollbackFor = Exception.class) // 添加事务异常则回滚所有导入
public SysUserImportRespVO importUsers(List<SysUserImportExcelVO> importUsers, boolean isUpdateSupport) {
if (CollUtil.isEmpty(importUsers)) {
throw ServiceExceptionUtil.exception(USER_IMPORT_LIST_IS_EMPTY);
}
SysUserImportRespVO respVO = SysUserImportRespVO.builder().createUsernames(new ArrayList<>())
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
importUsers.forEach(importUser -> {
// 校验判断是否有不符合的原因
try {
checkCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
importUser.getDeptId(), null);
importUser.getDeptId(), null);
} catch (ServiceException ex) {
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
return;
@ -316,4 +364,16 @@ public class SysUserServiceImpl implements SysUserService {
return respVO;
}
@Override
public void updateAvatar(Long id, InputStream avatarFile) {
this.checkUserExists(id);
// 存储文件
String avatar = fileService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile));
// 更新路径
SysUserDO sysUserDO = new SysUserDO();
sysUserDO.setId(id);
sysUserDO.setAvatar(avatar);
userMapper.updateById(sysUserDO);
}
}

View File

@ -109,7 +109,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public List<Long> createCodegenListFromDB(List<String> tableNames) {
List<Long> ids = new ArrayList<>(tableNames.size());
// 遍历添加虽然效率会低一点但是没必要做成完全批量因为不会这么大量
@ -118,7 +118,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void updateCodegen(ToolCodegenUpdateReqVO updateReqVO) {
// 校验是否已经存在
if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
@ -134,7 +134,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void syncCodegenFromDB(Long tableId) {
// 校验是否已经存在
ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
@ -149,7 +149,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void syncCodegenFromSQL(Long tableId, String sql) {
// 校验是否已经存在
ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
@ -201,7 +201,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void deleteCodegen(Long tableId) {
// 校验是否已经存在
if (codegenTableMapper.selectById(tableId) == null) {

View File

@ -145,14 +145,14 @@ yudao:
swagger:
title: 管理后台
description: 提供管理员管理的所有功能
version: ${yudao.info.base-package}
version: ${yudao.info.version}
base-package: ${yudao.info.base-package}.modules
captcha:
timeout: 5m
width: 160
height: 60
file:
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/infra/file/get/
base-path: http://127.0.0.1:${server.port}${yudao.web.api-prefix}/system/file/get/
codegen:
base-package: ${yudao.info.base-package}
db-schemas: ${spring.datasource.name}

View File

@ -145,14 +145,14 @@ yudao:
swagger:
title: 管理后台
description: 提供管理员管理的所有功能
version: ${yudao.info.base-package}
version: ${yudao.info.version}
base-package: ${yudao.info.base-package}.modules
captcha:
timeout: 5m
width: 160
height: 60
file:
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/infra/file/get/
base-path: http://127.0.0.1:${server.port}${yudao.web.api-prefix}/system/file/get/
codegen:
base-package: ${yudao.info.base-package}
db-schemas: ${spring.datasource.name}

View File

@ -16,9 +16,9 @@ import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
/**
* 依赖内存 DB 的单元测试
* 依赖内存 DB + Redis 的单元测试
*
* 注意Service 层同样适用对于 Service 层的单元测试我们针对自己模块的 Mapper 走的是 H2 内存数据库针对别的模块的 Service 走的是 Mock 方法
* 相比 {@link BaseDbUnitTest} 来说额外增加了内存 Redis
*
* @author 芋道源码
*/

View File

@ -0,0 +1,32 @@
package cn.iocoder.dashboard;
import cn.iocoder.dashboard.config.RedisTestConfiguration;
import cn.iocoder.dashboard.framework.redis.config.RedisConfig;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
/**
* 依赖内存 Redis 的单元测试
*
* 相比 {@link BaseDbUnitTest} 来说从内存 DB 改成了内存 Redis
*
* @author 芋道源码
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisUnitTest.Application.class)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
public class BaseRedisUnitTest {
@Import({
// Redis 配置类
RedisTestConfiguration.class, // Redis 测试配置类用于启动 RedisServer
RedisAutoConfiguration.class, // Spring Redis 自动配置类
RedisConfig.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}

View File

@ -1,32 +0,0 @@
package cn.iocoder.dashboard;
import org.junit.jupiter.api.AfterEach;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import javax.annotation.Resource;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后清理 DB
@Deprecated
public class BaseSpringBootUnitTest {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 每个单元测试结束后清理 Redis
*/
@AfterEach
public void cleanRedis() {
stringRedisTemplate.execute((RedisCallback<Object>) connection -> {
connection.flushDb();
return null;
});
}
}

View File

@ -1,19 +1,17 @@
package cn.iocoder.dashboard.config;
import com.github.fppt.jedismock.RedisServer;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import java.io.IOException;
@Configuration(proxyBeanMethods = false)
@Lazy(false) // 禁止延迟加载
@EnableConfigurationProperties(RedisProperties.class)
@AutoConfigureBefore({RedisAutoConfiguration.class, RedissonAutoConfiguration.class}) // Redis 自动配置前进行初始化
public class RedisTestConfiguration {
/**

View File

@ -1,14 +1,14 @@
package cn.iocoder.dashboard.framework.quartz.core.scheduler;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.modules.system.job.auth.SysUserSessionTimeoutJob;
import org.junit.jupiter.api.Test;
import org.quartz.SchedulerException;
import javax.annotation.Resource;
class SchedulerManagerTest extends BaseSpringBootUnitTest {
class SchedulerManagerTest extends BaseDbUnitTest {
@Resource
private SchedulerManager schedulerManager;

View File

@ -0,0 +1,177 @@
package cn.iocoder.dashboard.modules.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiAccessLogCreateDTO;
import cn.iocoder.dashboard.modules.infra.controller.logger.vo.apiaccesslog.InfApiAccessLogExportReqVO;
import cn.iocoder.dashboard.modules.infra.controller.logger.vo.apiaccesslog.InfApiAccessLogPageReqVO;
import cn.iocoder.dashboard.modules.infra.dal.dataobject.logger.InfApiAccessLogDO;
import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiAccessLogMapper;
import cn.iocoder.dashboard.modules.infra.service.logger.impl.InfApiAccessLogServiceImpl;
import cn.iocoder.dashboard.util.RandomUtils;
import cn.iocoder.dashboard.util.object.ObjectUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* {@link InfApiAccessLogServiceImpl} 单元测试
*/
@Import(InfApiAccessLogServiceImpl.class)
public class InfApiAccessLogServiceImplTest extends BaseDbUnitTest {
@Resource
private InfApiAccessLogService infApiAccessLogServiceImpl;
@Resource
private InfApiAccessLogMapper infApiAccessLogMapper;
@Test
public void testCreateApiAccessLogAsync() throws Exception {
ApiAccessLogCreateDTO createDTO = RandomUtils.randomPojo(
ApiAccessLogCreateDTO.class,
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue())
);
// 执行service方法
Future<Boolean> future = infApiAccessLogServiceImpl.createApiAccessLogAsync(createDTO);
// 等异步执行完
future.get();
InfApiAccessLogDO infApiAccessLogDO = infApiAccessLogMapper.selectOne(null);
// 断言
assertNotNull(infApiAccessLogDO);
// 断言忽略基本字段
assertPojoEquals(createDTO, infApiAccessLogDO);
}
@Test
public void testGetApiAccessLogPage() {
// 构造测试数据
long userId = 2233L;
int userType = UserTypeEnum.ADMIN.getValue();
String applicationName = "ruoyi-test";
String requestUrl = "foo";
Date beginTime = buildTime(2021, 3, 13);
int duration = 1000;
int resultCode = GlobalErrorCodeConstants.SUCCESS.getCode();
InfApiAccessLogDO infApiAccessLogDO = RandomUtils.randomPojo(InfApiAccessLogDO.class, dto -> {
dto.setUserId(userId);
dto.setUserType(userType);
dto.setApplicationName(applicationName);
dto.setRequestUrl(requestUrl);
dto.setBeginTime(beginTime);
dto.setDuration(duration);
dto.setResultCode(resultCode);
});
infApiAccessLogMapper.insert(infApiAccessLogDO);
// 下面几个都是不匹配的数据
// userId 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
// duration 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
// resultCode 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
// 构造调用参数
InfApiAccessLogPageReqVO reqVO = new InfApiAccessLogPageReqVO();
reqVO.setUserId(userId);
reqVO.setUserType(userType);
reqVO.setApplicationName(applicationName);
reqVO.setRequestUrl(requestUrl);
reqVO.setBeginBeginTime(buildTime(2021, 3, 12));
reqVO.setEndBeginTime(buildTime(2021, 3, 14));
reqVO.setDuration(duration);
reqVO.setResultCode(resultCode);
// 调用service方法
PageResult<InfApiAccessLogDO> pageResult = infApiAccessLogServiceImpl.getApiAccessLogPage(reqVO);
// 断言只查到了一条符合条件的
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(infApiAccessLogDO, pageResult.getList().get(0));
}
@Test
public void testGetApiAccessLogList() {
// 构造测试数据
long userId = 2233L;
int userType = UserTypeEnum.ADMIN.getValue();
String applicationName = "ruoyi-test";
String requestUrl = "foo";
Date beginTime = buildTime(2021, 3, 13);
int duration = 1000;
int resultCode = GlobalErrorCodeConstants.SUCCESS.getCode();
InfApiAccessLogDO infApiAccessLogDO = RandomUtils.randomPojo(InfApiAccessLogDO.class, dto -> {
dto.setUserId(userId);
dto.setUserType(userType);
dto.setApplicationName(applicationName);
dto.setRequestUrl(requestUrl);
dto.setBeginTime(beginTime);
dto.setDuration(duration);
dto.setResultCode(resultCode);
});
infApiAccessLogMapper.insert(infApiAccessLogDO);
// 下面几个都是不匹配的数据
// userId 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
// duration 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
// resultCode 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
// 构造调用参数
InfApiAccessLogExportReqVO reqVO = new InfApiAccessLogExportReqVO();
reqVO.setUserId(userId);
reqVO.setUserType(userType);
reqVO.setApplicationName(applicationName);
reqVO.setRequestUrl(requestUrl);
reqVO.setBeginBeginTime(buildTime(2021, 3, 12));
reqVO.setEndBeginTime(buildTime(2021, 3, 14));
reqVO.setDuration(duration);
reqVO.setResultCode(resultCode);
// 调用service方法
List<InfApiAccessLogDO> list = infApiAccessLogServiceImpl.getApiAccessLogList(reqVO);
// 断言只查到了一条符合条件的
assertEquals(1, list.size());
assertPojoEquals(infApiAccessLogDO, list.get(0));
}
}

View File

@ -0,0 +1,207 @@
package cn.iocoder.dashboard.modules.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO;
import cn.iocoder.dashboard.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogExportReqVO;
import cn.iocoder.dashboard.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogPageReqVO;
import cn.iocoder.dashboard.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiErrorLogMapper;
import cn.iocoder.dashboard.modules.infra.enums.logger.InfApiErrorLogProcessStatusEnum;
import cn.iocoder.dashboard.modules.infra.service.logger.impl.InfApiErrorLogServiceImpl;
import cn.iocoder.dashboard.util.RandomUtils;
import cn.iocoder.dashboard.util.object.ObjectUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_NOT_FOUND;
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_PROCESSED;
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* {@link InfApiErrorLogServiceImpl} 单元测试
*/
@Import(InfApiErrorLogServiceImpl.class)
public class InfApiErrorLogServiceImplTest extends BaseDbUnitTest {
@Resource
private InfApiErrorLogService infApiErrorLogServiceImpl;
@Resource
private InfApiErrorLogMapper infApiErrorLogMapper;
@Test
public void testCreateApiErrorLogAsync() throws Exception {
ApiErrorLogCreateDTO createDTO = RandomUtils.randomPojo(
ApiErrorLogCreateDTO.class,
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue())
);
// 执行service方法
Future<Boolean> future = infApiErrorLogServiceImpl.createApiErrorLogAsync(createDTO);
// 等异步执行完
future.get();
InfApiErrorLogDO infApiErrorLogDO = infApiErrorLogMapper.selectOne(null);
// 断言
assertNotNull(infApiErrorLogDO);
// 断言忽略基本字段
assertPojoEquals(createDTO, infApiErrorLogDO);
}
@Test
public void testGetApiErrorLogPage() {
// 构造测试数据
long userId = 2233L;
int userType = UserTypeEnum.ADMIN.getValue();
String applicationName = "ruoyi-test";
String requestUrl = "foo";
Date beginTime = buildTime(2021, 3, 13);
int progressStatus = InfApiErrorLogProcessStatusEnum.INIT.getStatus();
InfApiErrorLogDO infApiErrorLogDO = RandomUtils.randomPojo(InfApiErrorLogDO.class, logDO -> {
logDO.setUserId(userId);
logDO.setUserType(userType);
logDO.setApplicationName(applicationName);
logDO.setRequestUrl(requestUrl);
logDO.setExceptionTime(beginTime);
logDO.setProcessStatus(progressStatus);
});
infApiErrorLogMapper.insert(infApiErrorLogDO);
// 下面几个都是不匹配的数据
// userId 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
// progressStatus 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
// 构造调用参数
InfApiErrorLogPageReqVO reqVO = new InfApiErrorLogPageReqVO();
reqVO.setUserId(userId);
reqVO.setUserType(userType);
reqVO.setApplicationName(applicationName);
reqVO.setRequestUrl(requestUrl);
reqVO.setBeginExceptionTime(buildTime(2021, 3, 12));
reqVO.setEndExceptionTime(buildTime(2021, 3, 14));
reqVO.setProcessStatus(progressStatus);
// 调用service方法
PageResult<InfApiErrorLogDO> pageResult = infApiErrorLogServiceImpl.getApiErrorLogPage(reqVO);
// 断言只查到了一条符合条件的
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(infApiErrorLogDO, pageResult.getList().get(0));
}
@Test
public void testGetApiErrorLogList() {
// 构造测试数据
long userId = 2233L;
int userType = UserTypeEnum.ADMIN.getValue();
String applicationName = "ruoyi-test";
String requestUrl = "foo";
Date beginTime = buildTime(2021, 3, 13);
int progressStatus = InfApiErrorLogProcessStatusEnum.INIT.getStatus();
InfApiErrorLogDO infApiErrorLogDO = RandomUtils.randomPojo(InfApiErrorLogDO.class, logDO -> {
logDO.setUserId(userId);
logDO.setUserType(userType);
logDO.setApplicationName(applicationName);
logDO.setRequestUrl(requestUrl);
logDO.setExceptionTime(beginTime);
logDO.setProcessStatus(progressStatus);
});
infApiErrorLogMapper.insert(infApiErrorLogDO);
// 下面几个都是不匹配的数据
// userId 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
// progressStatus 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
// 构造调用参数
InfApiErrorLogExportReqVO reqVO = new InfApiErrorLogExportReqVO();
reqVO.setUserId(userId);
reqVO.setUserType(userType);
reqVO.setApplicationName(applicationName);
reqVO.setRequestUrl(requestUrl);
reqVO.setBeginExceptionTime(buildTime(2021, 3, 12));
reqVO.setEndExceptionTime(buildTime(2021, 3, 14));
reqVO.setProcessStatus(progressStatus);
// 调用service方法
List<InfApiErrorLogDO> list = infApiErrorLogServiceImpl.getApiErrorLogList(reqVO);
// 断言只查到了一条符合条件的
assertEquals(1, list.size());
assertPojoEquals(infApiErrorLogDO, list.get(0));
}
@Test
public void testUpdateApiErrorLogProcess() {
// 先构造两条数据第一条用于抛出异常第二条用于正常的执行update操作
Long processUserId = 2233L;
InfApiErrorLogDO first = RandomUtils.randomPojo(InfApiErrorLogDO.class, logDO -> {
logDO.setProcessUserId(processUserId);
logDO.setUserType(UserTypeEnum.ADMIN.getValue());
logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus());
});
infApiErrorLogMapper.insert(first);
InfApiErrorLogDO second = RandomUtils.randomPojo(InfApiErrorLogDO.class, logDO -> {
logDO.setProcessUserId(1122L);
logDO.setUserType(UserTypeEnum.ADMIN.getValue());
logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.INIT.getStatus());
});
infApiErrorLogMapper.insert(second);
Long firstId = first.getId();
Long secondId = second.getId();
// 执行正常的 update 操作
infApiErrorLogServiceImpl.updateApiErrorLogProcess(secondId, InfApiErrorLogProcessStatusEnum.DONE.getStatus(), processUserId);
InfApiErrorLogDO secondSelect = infApiErrorLogMapper.selectOne("id", secondId);
// id 0 查询不到应该抛出异常 API_ERROR_LOG_NOT_FOUND
assertServiceException(() -> infApiErrorLogServiceImpl.updateApiErrorLogProcess(0L, InfApiErrorLogProcessStatusEnum.DONE.getStatus(), processUserId), API_ERROR_LOG_NOT_FOUND);
// id first progressStatus DONE 应该抛出 API_ERROR_LOG_PROCESSED
assertServiceException(() -> infApiErrorLogServiceImpl.updateApiErrorLogProcess(firstId, InfApiErrorLogProcessStatusEnum.DONE.getStatus(), processUserId), API_ERROR_LOG_PROCESSED);
// 验证 progressStatus 是否修改成功
assertEquals(InfApiErrorLogProcessStatusEnum.DONE.getStatus(), secondSelect.getProcessStatus());
// 验证 progressUserId 是否修改成功
assertEquals(processUserId, secondSelect.getProcessUserId());
}
}

View File

@ -0,0 +1,66 @@
package cn.iocoder.dashboard.modules.system.service.common;
import cn.iocoder.dashboard.BaseRedisUnitTest;
import cn.iocoder.dashboard.framework.captcha.config.CaptchaProperties;
import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageRespVO;
import cn.iocoder.dashboard.modules.system.dal.redis.common.SysCaptchaRedisDAO;
import cn.iocoder.dashboard.modules.system.service.common.impl.SysCaptchaServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.dashboard.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
@Import({SysCaptchaServiceImpl.class, CaptchaProperties.class, SysCaptchaRedisDAO.class})
public class SysCaptchaServiceTest extends BaseRedisUnitTest {
@Resource
private SysCaptchaServiceImpl captchaService;
@Resource
private SysCaptchaRedisDAO captchaRedisDAO;
@Resource
private CaptchaProperties captchaProperties;
@Test
public void testGetCaptchaImage() {
// 调用
SysCaptchaImageRespVO respVO = captchaService.getCaptchaImage();
// 断言
assertNotNull(respVO.getUuid());
assertNotNull(respVO.getImg());
String captchaCode = captchaRedisDAO.get(respVO.getUuid());
assertNotNull(captchaCode);
}
@Test
public void testGetCaptchaCode() {
// 准备参数
String uuid = randomString();
String code = randomString();
// mock 数据
captchaRedisDAO.set(uuid, code, captchaProperties.getTimeout());
// 调用
String resultCode = captchaService.getCaptchaCode(uuid);
// 断言
assertEquals(code, resultCode);
}
@Test
public void testDeleteCaptchaCode() {
// 准备参数
String uuid = randomString();
String code = randomString();
// mock 数据
captchaRedisDAO.set(uuid, code, captchaProperties.getTimeout());
// 调用
captchaService.deleteCaptchaCode(uuid);
// 断言
assertNull(captchaRedisDAO.get(uuid));
}
}

View File

@ -1,6 +1,6 @@
package cn.iocoder.dashboard.modules.tool.dal.mysql.codegen;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
import org.junit.jupiter.api.Test;
@ -9,7 +9,7 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ToolInformationSchemaColumnMapperTest extends BaseSpringBootUnitTest {
public class ToolInformationSchemaColumnMapperTest extends BaseDbUnitTest {
@Resource
private ToolSchemaColumnMapper toolInformationSchemaColumnMapper;

View File

@ -1,6 +1,6 @@
package cn.iocoder.dashboard.modules.tool.dal.mysql.codegen;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaTableDO;
import org.junit.jupiter.api.Test;
@ -9,7 +9,7 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ToolInformationSchemaTableMapperTest extends BaseSpringBootUnitTest {
class ToolInformationSchemaTableMapperTest extends BaseDbUnitTest {
@Resource
private ToolSchemaTableMapper toolInformationSchemaTableMapper;

View File

@ -1,18 +1,17 @@
package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.codegen.ToolCodegenColumnMapper;
import cn.iocoder.dashboard.modules.tool.dal.mysql.codegen.ToolCodegenTableMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
public class ToolCodegenEngineTest extends BaseSpringBootUnitTest {
public class ToolCodegenEngineTest extends BaseDbUnitTest {
@Resource
private ToolCodegenTableMapper codegenTableMapper;

View File

@ -1,9 +1,9 @@
package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import org.junit.jupiter.api.Test;
public class ToolCodegenSQLParserTest extends BaseSpringBootUnitTest {
public class ToolCodegenSQLParserTest extends BaseDbUnitTest {
@Test
public void testParse() {

View File

@ -1,12 +1,11 @@
package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
import cn.iocoder.dashboard.BaseDbUnitTest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
class ToolCodegenServiceImplTest extends BaseSpringBootUnitTest {
class ToolCodegenServiceImplTest extends BaseDbUnitTest {
@Resource
private ToolCodegenServiceImpl toolCodegenService;

View File

@ -131,7 +131,7 @@ CREATE TABLE IF NOT EXISTS "sys_menu" (
PRIMARY KEY ("id")
) COMMENT '菜单权限表';
CREATE TABLE "sys_dict_type" (
CREATE TABLE IF NOT EXISTS "sys_dict_type" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(100) NOT NULL DEFAULT '',
"type" varchar(100) NOT NULL DEFAULT '',
@ -145,7 +145,7 @@ CREATE TABLE "sys_dict_type" (
PRIMARY KEY ("id")
) COMMENT '字典类型表';
CREATE TABLE `sys_user_session` (
CREATE TABLE IF NOT EXISTS `sys_user_session` (
`id` varchar(32) NOT NULL,
`user_id` bigint DEFAULT NULL,
`username` varchar(50) NOT NULL DEFAULT '',
@ -209,7 +209,7 @@ CREATE TABLE IF NOT EXISTS `sys_login_log` (
) COMMENT ='系统访问记录';
CREATE TABLE `sys_operate_log` (
CREATE TABLE IF NOT EXISTS `sys_operate_log` (
`id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`trace_id` varchar(64) NOT NULL DEFAULT '',
`user_id` bigint(20) NOT NULL,
@ -237,7 +237,7 @@ CREATE TABLE `sys_operate_log` (
PRIMARY KEY (`id`)
) COMMENT ='操作日志记录';
create table "sys_user" (
create table IF NOT EXISTS "sys_user" (
"id" bigint not null GENERATED BY DEFAULT AS IDENTITY,
"username" varchar(30) not null,
"password" varchar(100) not null default '',
@ -259,3 +259,60 @@ create table "sys_user" (
"deleted" bit not null default false,
primary key ("id")
) comment '用户信息表';
create table "inf_api_access_log" (
"id" bigint not null GENERATED BY DEFAULT AS IDENTITY,
"trace_id" varchar(64) not null default '',
"user_id" bigint not null default '0',
"user_type" tinyint not null default '0',
"application_name" varchar(50) not null,
"request_method" varchar(16) not null default '',
"request_url" varchar(255) not null default '',
"request_params" varchar(8000) not null default '',
"user_ip" varchar(50) not null,
"user_agent" varchar(512) not null,
"begin_time" timestamp not null,
"end_time" timestamp not null,
"duration" integer not null,
"result_code" integer not null default '0',
"result_msg" varchar(512) default '',
"creator" varchar(64) default '',
"create_time" timestamp not null default current_timestamp,
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
primary key ("id")
) comment 'API 访问日志表';
create table "inf_api_error_log" (
"id" integer not null GENERATED BY DEFAULT AS IDENTITY,
"trace_id" varchar(64) not null,
"user_id" bigint not null default '0',
"user_type" tinyint not null default '0',
"application_name" varchar(50) not null,
"request_method" varchar(16) not null,
"request_url" varchar(255) not null,
"request_params" varchar(8000) not null,
"user_ip" varchar(50) not null,
"user_agent" varchar(512) not null,
"exception_time" timestamp not null,
"exception_name" varchar(128) not null default '',
"exception_message" clob not null,
"exception_root_cause_message" clob not null,
"exception_stack_trace" clob not null,
"exception_class_name" varchar(512) not null,
"exception_file_name" varchar(512) not null,
"exception_method_name" varchar(512) not null,
"exception_line_number" integer not null,
"process_status" tinyint not null,
"process_time" timestamp default null,
"process_user_id" bigint default '0',
"creator" varchar(64) default '',
"create_time" timestamp not null default current_timestamp,
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
primary key ("id")
) comment '系统异常日志';