Merge branch 'master' into unit_logger_system
# Conflicts: # src/test/resources/sql/clean.sql # src/test/resources/sql/create_tables.sql
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.dashboard.framework.mybatis.config;
|
||||
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -13,7 +15,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class)
|
||||
@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class,
|
||||
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
|
||||
public class MybatisConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -23,4 +26,9 @@ public class MybatisConfiguration {
|
||||
return mybatisPlusInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetaObjectHandler defaultMetaObjectHandler(){
|
||||
return new DefaultDBFieldHandler(); // 自动填充参数类
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.dashboard.framework.mybatis.core.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -15,19 +17,27 @@ public class BaseDO implements Serializable {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
/**
|
||||
* 创建者 TODO 芋艿:迁移成编号
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
private String createBy;
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String creator;
|
||||
/**
|
||||
* 更新者 TODO 芋艿:迁移成编号
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
private String updateBy;
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updater;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
|
@@ -0,0 +1,63 @@
|
||||
package cn.iocoder.dashboard.framework.mybatis.core.handler;
|
||||
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 通用参数填充实现类
|
||||
*
|
||||
* 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值
|
||||
*
|
||||
* @author hexiaowu
|
||||
*/
|
||||
public class DefaultDBFieldHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
||||
Date current = new Date();
|
||||
|
||||
// 创建时间为空,则以当前时间为插入时间
|
||||
if (Objects.isNull(baseDO.getCreateTime())) {
|
||||
baseDO.setCreateTime(current);
|
||||
}
|
||||
// 更新时间为空,则以当前时间为更新时间
|
||||
if (Objects.isNull(baseDO.getUpdateTime())) {
|
||||
baseDO.setUpdateTime(current);
|
||||
}
|
||||
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getCreator())) {
|
||||
baseDO.setCreator(loginUser.getId().toString());
|
||||
}
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(loginUser.getId().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
Object modifyTime = getFieldValByName("updateTime", metaObject);
|
||||
Object modifier = getFieldValByName("updater", metaObject);
|
||||
// 获取登录用户信息
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
|
||||
// 更新时间为空,则以当前时间为更新时间
|
||||
if (Objects.isNull(modifyTime)) {
|
||||
setFieldValByName("updateTime", new Date(), metaObject);
|
||||
}
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(modifier)) {
|
||||
setFieldValByName("updater", loginUser.getId().toString(), metaObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,6 +28,10 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
|
||||
return selectOne(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
default Integer selectCount(String field, Object value) {
|
||||
return selectCount(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
default List<T> selectList() {
|
||||
return selectList(new QueryWrapper<>());
|
||||
}
|
||||
|
@@ -1 +0,0 @@
|
||||
<http://www.iocoder.cn/Spring-Boot/Spring-Security/?github>
|
@@ -0,0 +1 @@
|
||||
<https://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao>
|
@@ -152,7 +152,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.headers().frameOptions().disable();
|
||||
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
|
||||
httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler);
|
||||
// 添加 JWT Filter
|
||||
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.dashboard.framework.security.core.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
|
||||
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
|
||||
@@ -36,6 +37,6 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
|
||||
securityFrameworkService.logout(token);
|
||||
}
|
||||
// 返回成功
|
||||
ServletUtils.writeJSON(response, null);
|
||||
ServletUtils.writeJSON(response, CommonResult.success(null));
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,10 @@ package cn.iocoder.dashboard.framework.security.core.util;
|
||||
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -40,9 +43,20 @@ public class SecurityFrameworkUtils {
|
||||
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return 当前用户
|
||||
*/
|
||||
@Nullable
|
||||
public static LoginUser getLoginUser() {
|
||||
return (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
Authentication authentication = context.getAuthentication();
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,8 +64,10 @@ public class SecurityFrameworkUtils {
|
||||
*
|
||||
* @return 用户编号
|
||||
*/
|
||||
@Nullable
|
||||
public static Long getLoginUserId() {
|
||||
return getLoginUser().getId();
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser != null ? loginUser.getId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,8 +75,10 @@ public class SecurityFrameworkUtils {
|
||||
*
|
||||
* @return 角色编号数组
|
||||
*/
|
||||
@Nullable
|
||||
public static Set<Long> getLoginUserRoleIds() {
|
||||
return getLoginUser().getRoleIds();
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser != null ? loginUser.getRoleIds() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -10,15 +10,17 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.service.*;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.ApiKey;
|
||||
import springfox.documentation.service.AuthorizationScope;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.service.SecurityReference;
|
||||
import springfox.documentation.service.SecurityScheme;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
import springfox.documentation.service.ApiKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -27,9 +27,10 @@ public class WebConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
// 设置 API 前缀,仅仅匹配 controller 包下的
|
||||
configurer.addPathPrefix(webProperties.getApiPrefix(), clazz ->
|
||||
clazz.isAnnotationPresent(RestController.class)
|
||||
&& clazz.getPackage().getName().startsWith(webProperties.getControllerPackage()));
|
||||
&& clazz.getPackage().getName().startsWith(webProperties.getControllerPackage())); // 仅仅匹配 controller 包
|
||||
}
|
||||
|
||||
// ========== Filter 相关 ==========
|
||||
|
@@ -1,11 +1,9 @@
|
||||
package cn.iocoder.dashboard.modules.infra.controller.config;
|
||||
|
||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.dashboard.framework.idempotent.core.annotation.Idempotent;
|
||||
import cn.iocoder.dashboard.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver;
|
||||
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.config.vo.*;
|
||||
import cn.iocoder.dashboard.modules.infra.convert.config.InfConfigConvert;
|
||||
import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
|
||||
@@ -13,95 +11,95 @@ import cn.iocoder.dashboard.modules.infra.service.config.InfConfigService;
|
||||
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.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_SENSITIVE;
|
||||
|
||||
@Api(tags = "参数配置")
|
||||
@RestController
|
||||
@RequestMapping("/infra/config")
|
||||
@Validated
|
||||
public class InfConfigController {
|
||||
|
||||
@Resource
|
||||
private InfConfigService configService;
|
||||
|
||||
@ApiOperation("获取参数配置分页")
|
||||
@GetMapping("/page")
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:list')")
|
||||
public CommonResult<PageResult<InfConfigRespVO>> getConfigPage(@Validated InfConfigPageReqVO reqVO) {
|
||||
PageResult<InfConfigDO> page = configService.getConfigPage(reqVO);
|
||||
return success(InfConfigConvert.INSTANCE.convertPage(page));
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:create')")
|
||||
public CommonResult<Long> createConfig(@Valid @RequestBody InfConfigCreateReqVO reqVO) {
|
||||
return success(configService.createConfig(reqVO));
|
||||
}
|
||||
|
||||
@ApiOperation("导出参数配置")
|
||||
@GetMapping("/export")
|
||||
// @Log(title = "参数管理", businessType = BusinessType.EXPORT)
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:export')")
|
||||
public void exportSysConfig(HttpServletResponse response, @Validated InfConfigExportReqVO reqVO) throws IOException {
|
||||
List<InfConfigDO> list = configService.getConfigList(reqVO);
|
||||
// 拼接数据
|
||||
List<InfConfigExcelVO> excelDataList = InfConfigConvert.INSTANCE.convertList(list);
|
||||
// 输出
|
||||
ExcelUtils.write(response, "参数配置.xls", "配置列表",
|
||||
InfConfigExcelVO.class, excelDataList);
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("修改参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:update')")
|
||||
public CommonResult<Boolean> updateConfig(@Valid @RequestBody InfConfigUpdateReqVO reqVO) {
|
||||
configService.updateConfig(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@ApiOperation("删除参数配置")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
|
||||
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
|
||||
configService.deleteConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get")
|
||||
@ApiOperation("获得参数配置")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@GetMapping(value = "/get")
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:query')")
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:query')")
|
||||
public CommonResult<InfConfigRespVO> getConfig(@RequestParam("id") Long id) {
|
||||
return success(InfConfigConvert.INSTANCE.convert(configService.getConfig(id)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get-value-by-key")
|
||||
@ApiOperation(value = "根据参数键名查询参数值", notes = "敏感配置,不允许返回给前端")
|
||||
@ApiImplicitParam(name = "key", value = "参数键", required = true, example = "yunai.biz.username", dataTypeClass = String.class)
|
||||
@GetMapping(value = "/get-value-by-key")
|
||||
public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
|
||||
InfConfigDO config = configService.getConfigByKey(key);
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
if (config.getSensitive()) {
|
||||
throw ServiceExceptionUtil.exception(CONFIG_GET_VALUE_ERROR_IF_SENSITIVE);
|
||||
throw exception(CONFIG_GET_VALUE_ERROR_IF_SENSITIVE);
|
||||
}
|
||||
return success(config.getValue());
|
||||
}
|
||||
|
||||
@ApiOperation("新增参数配置")
|
||||
@PostMapping("/create")
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:add')")
|
||||
// @Log(title = "参数管理", businessType = BusinessType.INSERT)
|
||||
@Idempotent(timeout = 60, keyResolver = ExpressionIdempotentKeyResolver.class, keyArg = "#reqVO.key")
|
||||
public CommonResult<Long> createConfig(@Validated @RequestBody InfConfigCreateReqVO reqVO) {
|
||||
return success(configService.createConfig(reqVO));
|
||||
@GetMapping("/page")
|
||||
@ApiOperation("获取参数配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:query')")
|
||||
public CommonResult<PageResult<InfConfigRespVO>> getConfigPage(@Valid InfConfigPageReqVO reqVO) {
|
||||
PageResult<InfConfigDO> page = configService.getConfigPage(reqVO);
|
||||
return success(InfConfigConvert.INSTANCE.convertPage(page));
|
||||
}
|
||||
|
||||
@ApiOperation("修改参数配置")
|
||||
@PutMapping("/update")
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:edit')")
|
||||
// @Log(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@Idempotent(timeout = 60)
|
||||
public CommonResult<Boolean> updateConfig(@Validated @RequestBody InfConfigUpdateReqVO reqVO) {
|
||||
configService.updateConfig(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@ApiOperation("删除参数配置")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@DeleteMapping("/delete")
|
||||
// @PreAuthorize("@ss.hasPermi('infra:config:remove')")
|
||||
// @Log(title = "参数管理", businessType = BusinessType.DELETE)
|
||||
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
|
||||
configService.deleteConfig(id);
|
||||
return success(true);
|
||||
@GetMapping("/export")
|
||||
@ApiOperation("导出参数配置")
|
||||
@PreAuthorize("@ss.hasPermission('infra:config:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportSysConfig(@Valid InfConfigExportReqVO reqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
List<InfConfigDO> list = configService.getConfigList(reqVO);
|
||||
// 拼接数据
|
||||
List<InfConfigExcelVO> datas = InfConfigConvert.INSTANCE.convertList(list);
|
||||
// 输出
|
||||
ExcelUtils.write(response, "参数配置.xls", "数据", InfConfigExcelVO.class, datas);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -75,7 +75,7 @@ public class InfJobLogController {
|
||||
List<InfJobLogDO> list = jobLogService.getJobLogList(exportReqVO);
|
||||
// 导出 Excel
|
||||
List<InfJobLogExcelVO> datas = InfJobLogConvert.INSTANCE.convertList02(list);
|
||||
ExcelUtils.write(response, "定时任务.xls", "数据", InfJobLogExcelVO.class, datas);
|
||||
ExcelUtils.write(response, "任务日志.xls", "数据", InfJobLogExcelVO.class, datas);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -14,20 +14,21 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface InfConfigMapper extends BaseMapperX<InfConfigDO> {
|
||||
|
||||
default PageResult<InfConfigDO> selectPage(InfConfigPageReqVO reqVO) {
|
||||
return selectPage(reqVO,
|
||||
new QueryWrapperX<InfConfigDO>().likeIfPresent("name", reqVO.getName())
|
||||
.likeIfPresent("`key`", reqVO.getKey())
|
||||
.eqIfPresent("`type`", reqVO.getType())
|
||||
.betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
|
||||
}
|
||||
|
||||
default InfConfigDO selectByKey(String key) {
|
||||
return selectOne(new QueryWrapper<InfConfigDO>().eq("`key`", key));
|
||||
}
|
||||
|
||||
default PageResult<InfConfigDO> selectPage(InfConfigPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new QueryWrapperX<InfConfigDO>()
|
||||
.likeIfPresent("name", reqVO.getName())
|
||||
.likeIfPresent("`key`", reqVO.getKey())
|
||||
.eqIfPresent("`type`", reqVO.getType())
|
||||
.betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
|
||||
}
|
||||
|
||||
default List<InfConfigDO> selectList(InfConfigExportReqVO reqVO) {
|
||||
return selectList(new QueryWrapperX<InfConfigDO>().likeIfPresent("name", reqVO.getName())
|
||||
return selectList(new QueryWrapperX<InfConfigDO>()
|
||||
.likeIfPresent("name", reqVO.getName())
|
||||
.likeIfPresent("`key`", reqVO.getKey())
|
||||
.eqIfPresent("`type`", reqVO.getType())
|
||||
.betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
|
||||
|
@@ -7,28 +7,37 @@ import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigPageReqV
|
||||
import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 参数配置 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface InfConfigService {
|
||||
|
||||
/**
|
||||
* 获得参数配置分页列表
|
||||
* 创建参数配置
|
||||
*
|
||||
* @param reqVO 分页条件
|
||||
* @return 分页列表
|
||||
* @param reqVO 创建信息
|
||||
* @return 配置编号
|
||||
*/
|
||||
PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO);
|
||||
Long createConfig(@Valid InfConfigCreateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 获得参数配置列表
|
||||
* 更新参数配置
|
||||
*
|
||||
* @param reqVO 列表
|
||||
* @return 列表
|
||||
* @param reqVO 更新信息
|
||||
*/
|
||||
List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO);
|
||||
void updateConfig(@Valid InfConfigUpdateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 删除参数配置
|
||||
*
|
||||
* @param id 配置编号
|
||||
*/
|
||||
void deleteConfig(Long id);
|
||||
|
||||
/**
|
||||
* 获得参数配置
|
||||
@@ -47,25 +56,20 @@ public interface InfConfigService {
|
||||
InfConfigDO getConfigByKey(String key);
|
||||
|
||||
/**
|
||||
* 创建参数配置
|
||||
* 获得参数配置分页列表
|
||||
*
|
||||
* @param reqVO 创建信息
|
||||
* @return 配置编号
|
||||
* @param reqVO 分页条件
|
||||
* @return 分页列表
|
||||
*/
|
||||
Long createConfig(InfConfigCreateReqVO reqVO);
|
||||
PageResult<InfConfigDO> getConfigPage(@Valid InfConfigPageReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 更新参数配置
|
||||
* 获得参数配置列表
|
||||
*
|
||||
* @param reqVO 更新信息
|
||||
* @param reqVO 列表
|
||||
* @return 列表
|
||||
*/
|
||||
void updateConfig(InfConfigUpdateReqVO reqVO);
|
||||
List<InfConfigDO> getConfigList(@Valid InfConfigExportReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 删除参数配置
|
||||
*
|
||||
* @param id 配置编号
|
||||
*/
|
||||
void deleteConfig(Long id);
|
||||
|
||||
}
|
||||
|
@@ -12,8 +12,10 @@ import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
|
||||
import cn.iocoder.dashboard.modules.infra.enums.config.InfConfigTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.infra.mq.producer.config.InfConfigProducer;
|
||||
import cn.iocoder.dashboard.modules.infra.service.config.InfConfigService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@@ -26,6 +28,7 @@ import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@Validated
|
||||
public class InfConfigServiceImpl implements InfConfigService {
|
||||
|
||||
@Resource
|
||||
@@ -34,26 +37,6 @@ public class InfConfigServiceImpl implements InfConfigService {
|
||||
@Resource
|
||||
private InfConfigProducer configProducer;
|
||||
|
||||
@Override
|
||||
public PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO) {
|
||||
return configMapper.selectPage(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO) {
|
||||
return configMapper.selectList(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfConfigDO getConfig(Long id) {
|
||||
return configMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfConfigDO getConfigByKey(String key) {
|
||||
return configMapper.selectByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createConfig(InfConfigCreateReqVO reqVO) {
|
||||
// 校验正确性
|
||||
@@ -92,6 +75,26 @@ public class InfConfigServiceImpl implements InfConfigService {
|
||||
configProducer.sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfConfigDO getConfig(Long id) {
|
||||
return configMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfConfigDO getConfigByKey(String key) {
|
||||
return configMapper.selectByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO) {
|
||||
return configMapper.selectPage(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO) {
|
||||
return configMapper.selectList(reqVO);
|
||||
}
|
||||
|
||||
private void checkCreateOrUpdate(Long id, String key) {
|
||||
// 校验自己存在
|
||||
checkConfigExists(id);
|
||||
@@ -99,7 +102,8 @@ public class InfConfigServiceImpl implements InfConfigService {
|
||||
checkConfigKeyUnique(id, key);
|
||||
}
|
||||
|
||||
private InfConfigDO checkConfigExists(Long id) {
|
||||
@VisibleForTesting
|
||||
public InfConfigDO checkConfigExists(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -110,7 +114,8 @@ public class InfConfigServiceImpl implements InfConfigService {
|
||||
return config;
|
||||
}
|
||||
|
||||
private void checkConfigKeyUnique(Long id, String key) {
|
||||
@VisibleForTesting
|
||||
public void checkConfigKeyUnique(Long id, String key) {
|
||||
InfConfigDO config = configMapper.selectByKey(key);
|
||||
if (config == null) {
|
||||
return;
|
||||
|
@@ -25,8 +25,8 @@ public class SysDeptBaseVO {
|
||||
private Long parentId;
|
||||
|
||||
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
|
||||
@NotBlank(message = "显示顺序不能为空")
|
||||
private String sort;
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "负责人", example = "芋道")
|
||||
private String leader;
|
||||
|
@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
@@ -24,8 +25,8 @@ public class SysPostBaseVO {
|
||||
private String code;
|
||||
|
||||
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
|
||||
@NotBlank(message = "显示顺序不能为空")
|
||||
private String sort;
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
|
||||
private Integer status;
|
||||
|
@@ -23,7 +23,7 @@ public class SysPostExcelVO {
|
||||
private String name;
|
||||
|
||||
@ExcelProperty("岗位排序")
|
||||
private String sort;
|
||||
private Integer sort;
|
||||
|
||||
@ExcelProperty(value = "状态", converter = DictConvert.class)
|
||||
@DictFormat(SYS_COMMON_STATUS)
|
||||
|
@@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
|
||||
public class SysDictDataBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
|
||||
@NotBlank(message = "显示顺序不能为空")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "字典标签", required = true, example = "芋道")
|
||||
|
@@ -28,8 +28,8 @@ public class SysMenuBaseVO {
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
|
||||
@NotBlank(message = "显示顺序不能为空")
|
||||
private String sort;
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "父菜单 ID", required = true, example = "1024")
|
||||
@NotNull(message = "父菜单 ID 不能为空")
|
||||
|
@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
@@ -24,8 +25,8 @@ public class SysRoleBaseVO {
|
||||
private String code;
|
||||
|
||||
@ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
|
||||
@NotBlank(message = "显示顺序不能为空")
|
||||
private String sort;
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "角色类型", required = true, example = "1", notes = "见 SysRoleTypeEnum 枚举")
|
||||
private Integer type;
|
||||
|
@@ -10,6 +10,8 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 在线用户表
|
||||
*
|
||||
@@ -36,6 +38,14 @@ public class SysUserSessionDO extends BaseDO {
|
||||
* 关联 {@link SysUserDO#getId()}
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*
|
||||
* 冗余,因为账号可以变更
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
@@ -44,5 +54,9 @@ public class SysUserSessionDO extends BaseDO {
|
||||
* 浏览器 UA
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 会话超时时间
|
||||
*/
|
||||
private Date sessionTimeout;
|
||||
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ public class SysDeptDO extends BaseDO {
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private String sort;
|
||||
private Integer sort;
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
|
@@ -34,7 +34,7 @@ public class SysPostDO extends BaseDO {
|
||||
/**
|
||||
* 岗位排序
|
||||
*/
|
||||
private String sort;
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
|
@@ -49,7 +49,7 @@ public class SysMenuDO extends BaseDO {
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private String sort;
|
||||
private Integer sort;
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
|
@@ -8,6 +8,8 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserSessionMapper extends BaseMapperX<SysUserSessionDO> {
|
||||
@@ -18,4 +20,7 @@ public interface SysUserSessionMapper extends BaseMapperX<SysUserSessionDO> {
|
||||
.likeIfPresent("user_ip", reqVO.getUserIp()));
|
||||
}
|
||||
|
||||
default List<SysUserSessionDO> selectListBySessionTimoutLt() {
|
||||
return selectList(new QueryWrapperX<SysUserSessionDO>().lt("session_timeout",new Date()));
|
||||
}
|
||||
}
|
||||
|
@@ -15,13 +15,13 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
|
||||
|
||||
default SysDictDataDO selectByDictTypeAndLabel(String dictType, String label) {
|
||||
default SysDictDataDO selectByDictTypeAndValue(String dictType, String value) {
|
||||
return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
|
||||
.eq("label", label));
|
||||
.eq("value", value));
|
||||
}
|
||||
|
||||
default int selectCountByDictType(String dictType) {
|
||||
return selectCount(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType));
|
||||
return selectCount("dict_type", dictType);
|
||||
}
|
||||
|
||||
default PageResult<SysDictDataDO> selectPage(SysDictDataPageReqVO reqVO) {
|
||||
|
@@ -16,7 +16,7 @@ public interface SysRedisKeyConstants {
|
||||
|
||||
RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登陆用户的缓存",
|
||||
"login_user:%s", // 参数为 sessionId
|
||||
STRING, LoginUser.class, Duration.ofMinutes(30));
|
||||
STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
|
||||
|
||||
RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
|
||||
"captcha_code:%s", // 参数为 uuid
|
||||
|
@@ -1,11 +1,13 @@
|
||||
package cn.iocoder.dashboard.modules.system.dal.redis.auth;
|
||||
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||
import cn.iocoder.dashboard.util.json.JsonUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
|
||||
import static cn.iocoder.dashboard.modules.system.dal.redis.SysRedisKeyConstants.LOGIN_USER;
|
||||
|
||||
@@ -19,6 +21,8 @@ public class SysLoginUserRedisDAO {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private SysUserSessionService sysUserSessionService;
|
||||
|
||||
public LoginUser get(String sessionId) {
|
||||
String redisKey = formatKey(sessionId);
|
||||
@@ -27,7 +31,8 @@ public class SysLoginUserRedisDAO {
|
||||
|
||||
public void set(String sessionId, LoginUser loginUser) {
|
||||
String redisKey = formatKey(sessionId);
|
||||
stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser), LOGIN_USER.getTimeout());
|
||||
stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser),
|
||||
Duration.ofMillis(sysUserSessionService.getSessionTimeoutMillis()));
|
||||
}
|
||||
|
||||
public void delete(String sessionId) {
|
||||
|
@@ -1,23 +1,30 @@
|
||||
package cn.iocoder.dashboard.modules.system.job.auth;
|
||||
|
||||
import cn.iocoder.dashboard.framework.quartz.core.handler.JobHandler;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 用户 Session 超时 Job
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @author 願
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SysUserSessionTimeoutJob implements JobHandler {
|
||||
|
||||
@Resource
|
||||
private SysUserSessionService sysUserSessionService;
|
||||
|
||||
@Override
|
||||
public String execute(String param) throws Exception {
|
||||
// System.out.println("执行了一次任务");
|
||||
log.info("[execute][执行任务:{}]", param);
|
||||
return null;
|
||||
// 执行过期
|
||||
Long timeoutCount = sysUserSessionService.clearSessionTimeout();
|
||||
// 返回结果,记录每次的超时数量
|
||||
return String.format("移除在线会话数量为 %s 个", timeoutCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -60,4 +60,10 @@ public interface SysUserSessionService {
|
||||
*/
|
||||
PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 移除超时的在线用户
|
||||
*
|
||||
* @return {@link Long } 移出的超时用户数量
|
||||
**/
|
||||
long clearSessionTimeout();
|
||||
}
|
||||
|
@@ -160,7 +160,26 @@ public class SysAuthServiceImpl implements SysAuthService {
|
||||
|
||||
@Override
|
||||
public void logout(String token) {
|
||||
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); TODO 需要搞一搞
|
||||
// 查询用户信息
|
||||
LoginUser loginUser = userSessionService.getLoginUser(token);
|
||||
if (loginUser == null) {
|
||||
return;
|
||||
}
|
||||
// 删除 session
|
||||
userSessionService.deleteUserSession(token);
|
||||
// 记录登出日子和
|
||||
this.createLogoutLog(loginUser.getUsername());
|
||||
}
|
||||
|
||||
private void createLogoutLog(String username) {
|
||||
SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
|
||||
reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
|
||||
reqVO.setTraceId(TracerUtils.getTraceId());
|
||||
reqVO.setUsername(username);
|
||||
reqVO.setUserAgent(ServletUtils.getUserAgent());
|
||||
reqVO.setUserIp(ServletUtils.getClientIP());
|
||||
reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
|
||||
loginLogService.createLoginLog(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -6,20 +6,28 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
|
||||
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
|
||||
import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
|
||||
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||
import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
|
||||
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.dashboard.util.date.DateUtils.addTime;
|
||||
|
||||
/**
|
||||
* 在线用户 Session Service 实现类
|
||||
@@ -31,14 +39,14 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
@Resource
|
||||
private SysLoginUserRedisDAO loginUserRedisDAO;
|
||||
@Resource
|
||||
private SysUserSessionMapper userSessionMapper;
|
||||
|
||||
@Resource
|
||||
private SysUserService userService;
|
||||
@Resource
|
||||
private SysLoginLogService loginLogService;
|
||||
|
||||
@Override
|
||||
public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
|
||||
@@ -49,7 +57,9 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
|
||||
loginUserRedisDAO.set(sessionId, loginUser);
|
||||
// 写入 DB 中
|
||||
SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
|
||||
.userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).build();
|
||||
.userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
|
||||
.sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
|
||||
.build();
|
||||
userSessionMapper.insert(userSession);
|
||||
// 返回 Session 编号
|
||||
return sessionId;
|
||||
@@ -62,7 +72,9 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
|
||||
loginUserRedisDAO.set(sessionId, loginUser);
|
||||
// 更新 DB 中
|
||||
SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
|
||||
updateObj.setUsername(loginUser.getUsername());
|
||||
updateObj.setUpdateTime(new Date());
|
||||
updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
|
||||
userSessionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@@ -97,6 +109,36 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
|
||||
return userSessionMapper.selectPage(reqVO, userIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long clearSessionTimeout() {
|
||||
// 获取db里已经超时的用户列表
|
||||
List<SysUserSessionDO> sessionTimeoutDOS = userSessionMapper.selectListBySessionTimoutLt();
|
||||
Map<String, SysUserSessionDO> timeoutSessionDOMap = sessionTimeoutDOS
|
||||
.stream()
|
||||
.filter(sessionDO -> loginUserRedisDAO.get(sessionDO.getId()) == null)
|
||||
.collect(Collectors.toMap(SysUserSessionDO::getId, o -> o));
|
||||
// 确认已经超时,按批次移出在线用户列表
|
||||
if (CollUtil.isNotEmpty(timeoutSessionDOMap)) {
|
||||
Lists.partition(new ArrayList<>(timeoutSessionDOMap.keySet()), 100).forEach(userSessionMapper::deleteBatchIds);
|
||||
//记录用户超时退出日志
|
||||
createTimeoutLogoutLog(timeoutSessionDOMap.values());
|
||||
}
|
||||
return timeoutSessionDOMap.size();
|
||||
}
|
||||
|
||||
private void createTimeoutLogoutLog(Collection<SysUserSessionDO> timeoutSessionDOS) {
|
||||
for (SysUserSessionDO timeoutSessionDO : timeoutSessionDOS) {
|
||||
SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
|
||||
reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_TIMEOUT.getType());
|
||||
reqVO.setTraceId(TracerUtils.getTraceId());
|
||||
reqVO.setUsername(timeoutSessionDO.getUsername());
|
||||
reqVO.setUserAgent(timeoutSessionDO.getUserAgent());
|
||||
reqVO.setUserIp(timeoutSessionDO.getUserIp());
|
||||
reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
|
||||
loginLogService.createLoginLog(reqVO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Session 编号,目前采用 UUID 算法
|
||||
*
|
||||
|
@@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.dict.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
|
||||
@@ -10,12 +9,13 @@ import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataEx
|
||||
import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
|
||||
import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -28,6 +28,7 @@ import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
@@ -156,7 +157,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
|
||||
@Override
|
||||
public Long createDictData(SysDictDataCreateReqVO reqVO) {
|
||||
// 校验正确性
|
||||
this.checkCreateOrUpdate(null, reqVO.getLabel(), reqVO.getDictType());
|
||||
this.checkCreateOrUpdate(null, reqVO.getValue(), reqVO.getDictType());
|
||||
// 插入字典类型
|
||||
SysDictDataDO dictData = SysDictDataConvert.INSTANCE.convert(reqVO);
|
||||
dictDataMapper.insert(dictData);
|
||||
@@ -168,7 +169,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
|
||||
@Override
|
||||
public void updateDictData(SysDictDataUpdateReqVO reqVO) {
|
||||
// 校验正确性
|
||||
this.checkCreateOrUpdate(reqVO.getId(), reqVO.getLabel(), reqVO.getDictType());
|
||||
this.checkCreateOrUpdate(reqVO.getId(), reqVO.getValue(), reqVO.getDictType());
|
||||
// 更新字典类型
|
||||
SysDictDataDO updateObj = SysDictDataConvert.INSTANCE.convert(reqVO);
|
||||
dictDataMapper.updateById(updateObj);
|
||||
@@ -191,46 +192,49 @@ public class SysDictDataServiceImpl implements SysDictDataService {
|
||||
return dictDataMapper.selectCountByDictType(dictType);
|
||||
}
|
||||
|
||||
private void checkCreateOrUpdate(Long id, String label, String dictType) {
|
||||
private void checkCreateOrUpdate(Long id, String value, String dictType) {
|
||||
// 校验自己存在
|
||||
checkDictDataExists(id);
|
||||
// 校验字典类型有效
|
||||
checkDictTypeValid(dictType);
|
||||
// 校验字典数据的值的唯一性
|
||||
checkDictDataValueUnique(id, dictType, label);
|
||||
checkDictDataValueUnique(id, dictType, value);
|
||||
}
|
||||
|
||||
private void checkDictDataValueUnique(Long id, String dictType, String label) {
|
||||
SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndLabel(dictType, label);
|
||||
@VisibleForTesting
|
||||
public void checkDictDataValueUnique(Long id, String dictType, String value) {
|
||||
SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value);
|
||||
if (dictData == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的字典数据
|
||||
if (id == null) {
|
||||
throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
|
||||
throw exception(DICT_DATA_VALUE_DUPLICATE);
|
||||
}
|
||||
if (!dictData.getId().equals(id)) {
|
||||
throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
|
||||
throw exception(DICT_DATA_VALUE_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDictDataExists(Long id) {
|
||||
@VisibleForTesting
|
||||
public void checkDictDataExists(Long id) {
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
SysDictDataDO dictData = dictDataMapper.selectById(id);
|
||||
if (dictData == null) {
|
||||
throw ServiceExceptionUtil.exception(DICT_DATA_NOT_EXISTS);
|
||||
throw exception(DICT_DATA_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDictTypeValid(String type) {
|
||||
@VisibleForTesting
|
||||
public void checkDictTypeValid(String type) {
|
||||
SysDictTypeDO dictType = dictTypeService.getDictType(type);
|
||||
if (dictType == null) {
|
||||
throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_EXISTS);
|
||||
throw exception(DICT_TYPE_NOT_EXISTS);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_ENABLE);
|
||||
throw exception(DICT_TYPE_NOT_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
|
||||
import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
|
||||
import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -97,8 +98,9 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
|
||||
checkDictTypeUnique(id, type);
|
||||
}
|
||||
|
||||
private void checkDictTypeNameUnique(Long id, String type) {
|
||||
SysDictTypeDO dictType = dictTypeMapper.selectByName(type);
|
||||
@VisibleForTesting
|
||||
public void checkDictTypeNameUnique(Long id, String name) {
|
||||
SysDictTypeDO dictType = dictTypeMapper.selectByName(name);
|
||||
if (dictType == null) {
|
||||
return;
|
||||
}
|
||||
@@ -111,7 +113,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDictTypeUnique(Long id, String type) {
|
||||
@VisibleForTesting
|
||||
public void checkDictTypeUnique(Long id, String type) {
|
||||
SysDictTypeDO dictType = dictTypeMapper.selectByType(type);
|
||||
if (dictType == null) {
|
||||
return;
|
||||
@@ -125,7 +128,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
|
||||
}
|
||||
}
|
||||
|
||||
private SysDictTypeDO checkDictTypeExists(Long id) {
|
||||
@VisibleForTesting
|
||||
public SysDictTypeDO checkDictTypeExists(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import cn.iocoder.dashboard.modules.system.convert.notice.SysNoticeConvert;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.notice.SysNoticeMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.notice.SysNoticeDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.notice.SysNoticeService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -60,7 +61,8 @@ public class SysNoticeServiceImpl implements SysNoticeService {
|
||||
noticeMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void checkNoticeExists(Long id) {
|
||||
@VisibleForTesting
|
||||
public void checkNoticeExists(Long id) {
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ package cn.iocoder.dashboard.util.collection;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Array 工具类
|
||||
*
|
||||
@@ -18,11 +20,11 @@ public class ArrayUtils {
|
||||
* @return 结果数组
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> T[] append(T object, T... newElements) {
|
||||
public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newElements) {
|
||||
if (object == null) {
|
||||
return newElements;
|
||||
}
|
||||
T[] result = ArrayUtil.newArray(object.getClass(), 1 + newElements.length);
|
||||
Consumer<T>[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length);
|
||||
result[0] = object;
|
||||
System.arraycopy(newElements, 0, result, 1, newElements.length);
|
||||
return result;
|
||||
|
@@ -19,4 +19,14 @@ public class ObjectUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T extends Comparable<T>> T max(T obj1, T obj2) {
|
||||
if (obj1 == null) {
|
||||
return obj2;
|
||||
}
|
||||
if (obj2 == null) {
|
||||
return obj1;
|
||||
}
|
||||
return obj1.compareTo(obj2) > 0 ? obj1 : obj2;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
package cn.iocoder.dashboard;
|
||||
|
||||
import cn.iocoder.dashboard.config.RedisTestConfiguration;
|
||||
import cn.iocoder.dashboard.framework.datasource.config.DataSourceConfiguration;
|
||||
import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration;
|
||||
import cn.iocoder.dashboard.framework.redis.config.RedisConfig;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.redisson.spring.starter.RedissonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
/**
|
||||
* 依赖内存 DB 的单元测试
|
||||
*
|
||||
* 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
|
||||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
||||
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
|
||||
public class BaseDbAndRedisUnitTest {
|
||||
|
||||
@Import({
|
||||
// DB 配置类
|
||||
DataSourceConfiguration.class, // 自己的 DB 配置类
|
||||
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
|
||||
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
|
||||
// MyBatis 配置类
|
||||
MybatisConfiguration.class, // 自己的 MyBatis 配置类
|
||||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
||||
// Redis 配置类
|
||||
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
|
||||
RedisAutoConfiguration.class, // Spring Redis 自动配置类
|
||||
RedisConfig.class, // 自己的 Redis 配置类
|
||||
RedissonAutoConfiguration.class, // Redisson 自动高配置类
|
||||
})
|
||||
public static class Application {
|
||||
}
|
||||
|
||||
}
|
37
src/test/java/cn/iocoder/dashboard/BaseDbUnitTest.java
Normal file
37
src/test/java/cn/iocoder/dashboard/BaseDbUnitTest.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.dashboard;
|
||||
|
||||
import cn.iocoder.dashboard.framework.datasource.config.DataSourceConfiguration;
|
||||
import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
/**
|
||||
* 依赖内存 DB 的单元测试
|
||||
*
|
||||
* 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class)
|
||||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
||||
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
|
||||
public class BaseDbUnitTest {
|
||||
|
||||
@Import({
|
||||
// DB 配置类
|
||||
DataSourceConfiguration.class, // 自己的 DB 配置类
|
||||
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
|
||||
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
|
||||
// MyBatis 配置类
|
||||
MybatisConfiguration.class, // 自己的 MyBatis 配置类
|
||||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
||||
})
|
||||
public static class Application {
|
||||
}
|
||||
|
||||
}
|
@@ -12,6 +12,7 @@ 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
|
||||
|
@@ -8,12 +8,10 @@ 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) // 禁用懒加载,因为需要保证 Redis Server 必须先启动
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
@AutoConfigureBefore({RedisAutoConfiguration.class, RedissonAutoConfiguration.class}) // 在 Redis 自动配置前,进行初始化
|
||||
public class RedisTestConfiguration {
|
||||
|
@@ -1,16 +0,0 @@
|
||||
package cn.iocoder.dashboard.config;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
|
||||
@Configuration
|
||||
public class SecurityTestConfiguration {
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
return Mockito.mock(AuthenticationManager.class);
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package cn.iocoder.dashboard.modules.infra.service.config;
|
||||
|
||||
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigExportReqVO;
|
||||
@@ -15,6 +15,7 @@ import cn.iocoder.dashboard.util.collection.ArrayUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
@@ -24,8 +25,7 @@ import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.*;
|
||||
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -36,7 +36,8 @@ import static org.mockito.Mockito.verify;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class InfConfigServiceTest extends BaseSpringBootUnitTest {
|
||||
@Import(InfConfigServiceImpl.class)
|
||||
public class InfConfigServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private InfConfigServiceImpl configService;
|
||||
@@ -46,6 +47,120 @@ public class InfConfigServiceTest extends BaseSpringBootUnitTest {
|
||||
@MockBean
|
||||
private InfConfigProducer configProducer;
|
||||
|
||||
@Test
|
||||
public void testCreateConfig_success() {
|
||||
// 准备参数
|
||||
InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
|
||||
|
||||
// 调用
|
||||
Long configId = configService.createConfig(reqVO);
|
||||
// 断言
|
||||
assertNotNull(configId);
|
||||
// 校验记录的属性是否正确
|
||||
InfConfigDO config = configMapper.selectById(configId);
|
||||
assertPojoEquals(reqVO, config);
|
||||
assertEquals(InfConfigTypeEnum.CUSTOM.getType(), config.getType());
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfig_success() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO();
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class, o -> {
|
||||
o.setId(dbConfig.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
configService.updateConfig(reqVO);
|
||||
// 校验是否更新正确
|
||||
InfConfigDO config = configMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, config);
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConfig_success() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO(o -> {
|
||||
o.setType(InfConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型
|
||||
});
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbConfig.getId();
|
||||
|
||||
// 调用
|
||||
configService.deleteConfig(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(configMapper.selectById(id));
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConfig_canNotDeleteSystemType() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO(o -> {
|
||||
o.setType(InfConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除
|
||||
});
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbConfig.getId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConfigExists_success() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfigDO = randomInfConfigDO();
|
||||
configMapper.insert(dbConfigDO);// @Sql: 先插入出一条存在的数据
|
||||
|
||||
// 调用成功
|
||||
configService.checkConfigExists(dbConfigDO.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConfigExist_notExists() {
|
||||
assertServiceException(() -> configService.checkConfigExists(randomLongId()), CONFIG_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConfigKeyUnique_success() {
|
||||
// 调用,成功
|
||||
configService.checkConfigKeyUnique(randomLongId(), randomString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConfigKeyUnique_keyDuplicateForCreate() {
|
||||
// 准备参数
|
||||
String key = randomString();
|
||||
// mock 数据
|
||||
configMapper.insert(randomInfConfigDO(o -> o.setKey(key)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> configService.checkConfigKeyUnique(null, key),
|
||||
CONFIG_KEY_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConfigKeyUnique_keyDuplicateForUpdate() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
String key = randomString();
|
||||
// mock 数据
|
||||
configMapper.insert(randomInfConfigDO(o -> o.setKey(key)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> configService.checkConfigKeyUnique(id, key),
|
||||
CONFIG_KEY_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConfigPage() {
|
||||
// mock 数据
|
||||
@@ -128,105 +243,6 @@ public class InfConfigServiceTest extends BaseSpringBootUnitTest {
|
||||
assertPojoEquals(dbConfig, config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConfig_success() {
|
||||
// 准备参数
|
||||
InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
|
||||
|
||||
// 调用
|
||||
Long configId = configService.createConfig(reqVO);
|
||||
// 断言
|
||||
assertNotNull(configId);
|
||||
// 校验记录的属性是否正确
|
||||
InfConfigDO config = configMapper.selectById(configId);
|
||||
assertPojoEquals(reqVO, config);
|
||||
assertEquals(InfConfigTypeEnum.CUSTOM.getType(), config.getType());
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConfig_keyDuplicate() {
|
||||
// 准备参数
|
||||
InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
|
||||
// mock 数据
|
||||
configMapper.insert(randomInfConfigDO(o -> { // @Sql
|
||||
o.setKey(reqVO.getKey()); // 模拟 key 重复
|
||||
}));
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> configService.createConfig(reqVO), CONFIG_KEY_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfig_success() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO();
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class, o -> {
|
||||
o.setId(dbConfig.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
configService.updateConfig(reqVO);
|
||||
// 校验是否更新正确
|
||||
InfConfigDO config = configMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, config);
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfig_notExists() {
|
||||
// 准备参数
|
||||
InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> configService.updateConfig(reqVO), CONFIG_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConfig_success() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO(o -> {
|
||||
o.setType(InfConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型
|
||||
});
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbConfig.getId();
|
||||
|
||||
// 调用
|
||||
configService.deleteConfig(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(configMapper.selectById(id));
|
||||
// 校验调用
|
||||
verify(configProducer, times(1)).sendConfigRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConfig_canNotDeleteSystemType() {
|
||||
// mock 数据
|
||||
InfConfigDO dbConfig = randomInfConfigDO(o -> {
|
||||
o.setType(InfConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除
|
||||
});
|
||||
configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbConfig.getId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConfig_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> configService.deleteConfig(id), CONFIG_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
|
@@ -1,15 +1,19 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.auth;
|
||||
|
||||
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.impl.SysAuthServiceImpl;
|
||||
import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
|
||||
import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
|
||||
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
|
||||
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
|
||||
import cn.iocoder.dashboard.util.AssertUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -21,7 +25,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SysAuthServiceImplTest extends BaseSpringBootUnitTest {
|
||||
/**
|
||||
* {@link SysAuthServiceImpl} 的单元测试
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import(SysAuthServiceImpl.class)
|
||||
public class SysAuthServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysAuthServiceImpl authService;
|
||||
@@ -30,6 +40,14 @@ public class SysAuthServiceImplTest extends BaseSpringBootUnitTest {
|
||||
private SysUserService userService;
|
||||
@MockBean
|
||||
private SysPermissionService permissionService;
|
||||
@MockBean
|
||||
private AuthenticationManager authenticationManager;
|
||||
@MockBean
|
||||
private SysCaptchaService captchaService;
|
||||
@MockBean
|
||||
private SysLoginLogService loginLogService;
|
||||
@MockBean
|
||||
private SysUserSessionService userSessionService;
|
||||
|
||||
@Test
|
||||
public void testLoadUserByUsername_success() {
|
||||
|
@@ -0,0 +1,78 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.auth;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.iocoder.dashboard.BaseDbAndRedisUnitTest;
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.impl.SysUserSessionServiceImpl;
|
||||
import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl;
|
||||
import cn.iocoder.dashboard.modules.system.service.logger.impl.SysLoginLogServiceImpl;
|
||||
import cn.iocoder.dashboard.modules.system.service.user.SysUserServiceImpl;
|
||||
import cn.iocoder.dashboard.util.AssertUtils;
|
||||
import cn.iocoder.dashboard.util.RandomUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* SysUserSessionServiceImpl Tester.
|
||||
*
|
||||
* @author Lyon
|
||||
* @version 1.0
|
||||
* @since <pre>3月 8, 2021</pre>
|
||||
*/
|
||||
@Import(
|
||||
SysUserSessionServiceImpl.class)
|
||||
public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||
|
||||
@Resource
|
||||
SysUserSessionServiceImpl sysUserSessionService;
|
||||
@Resource
|
||||
SysUserSessionMapper sysUserSessionMapper;
|
||||
@MockBean
|
||||
SecurityProperties securityProperties;
|
||||
@MockBean
|
||||
SysDeptServiceImpl sysDeptService;
|
||||
@MockBean
|
||||
SysUserServiceImpl sysUserService;
|
||||
@MockBean
|
||||
SysLoginLogServiceImpl sysLoginLogService;
|
||||
@MockBean
|
||||
SysLoginUserRedisDAO sysLoginUserRedisDAO;
|
||||
|
||||
@Test
|
||||
public void testClearSessionTimeout_success() throws Exception {
|
||||
// 准备超时数据 120 条, 在线用户 1 条
|
||||
int expectedTimeoutCount = 120, expectedTotal = 1;
|
||||
|
||||
// 准备数据
|
||||
List<SysUserSessionDO> prepareData = Stream
|
||||
.iterate(0, i -> i)
|
||||
.limit(expectedTimeoutCount)
|
||||
.map(i -> RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetSecond(new Date(), -1))))
|
||||
.collect(Collectors.toList());
|
||||
SysUserSessionDO sessionDO = RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetMinute(new Date(), 30)));
|
||||
prepareData.add(sessionDO);
|
||||
prepareData.forEach(sysUserSessionMapper::insert);
|
||||
|
||||
//清空超时数据
|
||||
long actualTimeoutCount = sysUserSessionService.clearSessionTimeout();
|
||||
//校验
|
||||
assertEquals(expectedTimeoutCount, actualTimeoutCount);
|
||||
List<SysUserSessionDO> userSessionDOS = sysUserSessionMapper.selectList();
|
||||
assertEquals(expectedTotal, userSessionDOS.size());
|
||||
AssertUtils.assertPojoEquals(sessionDO, userSessionDOS.get(0), "updateTime");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,274 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.dept;
|
||||
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysDeptMapper;
|
||||
import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl;
|
||||
import cn.iocoder.dashboard.util.collection.ArrayUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* {@link SysDeptServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author niudehua
|
||||
*/
|
||||
@Import(SysDeptServiceImpl.class)
|
||||
class SysDeptServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysDeptServiceImpl deptService;
|
||||
@Resource
|
||||
private SysDeptMapper deptMapper;
|
||||
@MockBean
|
||||
private SysDeptProducer deptProducer;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testInitLocalCache() {
|
||||
// mock 数据
|
||||
SysDeptDO deptDO1 = randomDeptDO();
|
||||
deptMapper.insert(deptDO1);
|
||||
SysDeptDO deptDO2 = randomDeptDO();
|
||||
deptMapper.insert(deptDO2);
|
||||
|
||||
// 调用
|
||||
deptService.initLocalCache();
|
||||
// 断言 deptCache 缓存
|
||||
Map<Long, SysDeptDO> deptCache = (Map<Long, SysDeptDO>) getFieldValue(deptService, "deptCache");
|
||||
assertEquals(2, deptCache.size());
|
||||
assertPojoEquals(deptDO1, deptCache.get(deptDO1.getId()));
|
||||
assertPojoEquals(deptDO2, deptCache.get(deptDO2.getId()));
|
||||
// 断言 parentDeptCache 缓存
|
||||
Multimap<Long, SysDeptDO> parentDeptCache = (Multimap<Long, SysDeptDO>) getFieldValue(deptService, "parentDeptCache");
|
||||
assertEquals(2, parentDeptCache.size());
|
||||
assertPojoEquals(deptDO1, parentDeptCache.get(deptDO1.getParentId()));
|
||||
assertPojoEquals(deptDO2, parentDeptCache.get(deptDO2.getParentId()));
|
||||
// 断言 maxUpdateTime 缓存
|
||||
Date maxUpdateTime = (Date) getFieldValue(deptService, "maxUpdateTime");
|
||||
assertEquals(ObjectUtils.max(deptDO1.getUpdateTime(), deptDO2.getUpdateTime()), maxUpdateTime);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testListDepts() {
|
||||
// mock 数据
|
||||
SysDeptDO dept = randomPojo(SysDeptDO.class, o -> { // 等会查询到
|
||||
o.setName("开发部");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
});
|
||||
deptMapper.insert(dept);
|
||||
// 测试 name 不匹配
|
||||
deptMapper.insert(ObjectUtils.clone(dept, o -> o.setName("发")));
|
||||
// 测试 status 不匹配
|
||||
deptMapper.insert(ObjectUtils.clone(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 准备参数
|
||||
SysDeptListReqVO reqVO = new SysDeptListReqVO();
|
||||
reqVO.setName("开");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
// 调用
|
||||
List<SysDeptDO> sysDeptDOS = deptService.listDepts(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, sysDeptDOS.size());
|
||||
assertPojoEquals(dept, sysDeptDOS.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateDept_success() {
|
||||
// 准备参数
|
||||
SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
|
||||
o -> {
|
||||
o.setParentId(DeptIdEnum.ROOT.getId());
|
||||
o.setStatus(randomCommonStatus());
|
||||
});
|
||||
// 调用
|
||||
Long deptId = deptService.createDept(reqVO);
|
||||
// 断言
|
||||
assertNotNull(deptId);
|
||||
// 校验记录的属性是否正确
|
||||
SysDeptDO deptDO = deptMapper.selectById(deptId);
|
||||
assertPojoEquals(reqVO, deptDO);
|
||||
// 校验调用
|
||||
verify(deptProducer, times(1)).sendDeptRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateDept_success() {
|
||||
// mock 数据
|
||||
SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
|
||||
deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class, o -> {
|
||||
// 设置更新的 ID
|
||||
o.setParentId(DeptIdEnum.ROOT.getId());
|
||||
o.setId(dbDeptDO.getId());
|
||||
o.setStatus(randomCommonStatus());
|
||||
});
|
||||
// 调用
|
||||
deptService.updateDept(reqVO);
|
||||
// 校验是否更新正确
|
||||
SysDeptDO deptDO = deptMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, deptDO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteDept_success() {
|
||||
// mock 数据
|
||||
SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
|
||||
deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbDeptDO.getId();
|
||||
// 调用
|
||||
deptService.deleteDept(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(deptMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_nameDuplicateForUpdate() {
|
||||
// mock 数据
|
||||
SysDeptDO deptDO = randomDeptDO();
|
||||
// 设置根节点部门
|
||||
deptDO.setParentId(DeptIdEnum.ROOT.getId());
|
||||
deptMapper.insert(deptDO);
|
||||
// mock 数据 稍后模拟重复它的 name
|
||||
SysDeptDO nameDeptDO = randomDeptDO();
|
||||
// 设置根节点部门
|
||||
nameDeptDO.setParentId(DeptIdEnum.ROOT.getId());
|
||||
deptMapper.insert(nameDeptDO);
|
||||
// 准备参数
|
||||
SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
|
||||
o -> {
|
||||
// 设置根节点部门
|
||||
o.setParentId(DeptIdEnum.ROOT.getId());
|
||||
// 设置更新的 ID
|
||||
o.setId(deptDO.getId());
|
||||
// 模拟 name 重复
|
||||
o.setName(nameDeptDO.getName());
|
||||
});
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.updateDept(reqVO), DEPT_NAME_DUPLICATE);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_parentNotExitsForCreate() {
|
||||
SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
|
||||
o -> o.setStatus(randomCommonStatus()));
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> deptService.createDept(reqVO), DEPT_PARENT_NOT_EXITS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_notFoundForDelete() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.deleteDept(id), DEPT_NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_exitsChildrenForDelete() {
|
||||
// mock 数据
|
||||
SysDeptDO parentDept = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
|
||||
deptMapper.insert(parentDept);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysDeptDO childrenDeptDO = randomPojo(SysDeptDO.class, o -> {
|
||||
o.setParentId(parentDept.getId());
|
||||
o.setStatus(randomCommonStatus());
|
||||
});
|
||||
// 插入子部门
|
||||
deptMapper.insert(childrenDeptDO);
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.deleteDept(parentDept.getId()), DEPT_EXITS_CHILDREN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_parentErrorForUpdate() {
|
||||
// mock 数据
|
||||
SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
|
||||
deptMapper.insert(dbDeptDO);
|
||||
// 准备参数
|
||||
SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
|
||||
o -> {
|
||||
// 设置自己为父部门
|
||||
o.setParentId(dbDeptDO.getId());
|
||||
// 设置更新的 ID
|
||||
o.setId(dbDeptDO.getId());
|
||||
});
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_notEnableForCreate() {
|
||||
// mock 数据
|
||||
SysDeptDO deptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
|
||||
deptMapper.insert(deptDO);
|
||||
// 准备参数
|
||||
SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
|
||||
o -> {
|
||||
// 设置未启用的部门为副部门
|
||||
o.setParentId(deptDO.getId());
|
||||
});
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.createDept(reqVO), DEPT_NOT_ENABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDept_parentIsChildForUpdate() {
|
||||
// mock 数据
|
||||
SysDeptDO parentDept = randomPojo(SysDeptDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
deptMapper.insert(parentDept);
|
||||
SysDeptDO childDept = randomPojo(SysDeptDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setParentId(parentDept.getId());
|
||||
});
|
||||
deptMapper.insert(childDept);
|
||||
// 初始化本地缓存
|
||||
deptService.initLocalCache();
|
||||
// 准备参数
|
||||
SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
|
||||
o -> {
|
||||
// 设置自己的子部门为父部门
|
||||
o.setParentId(childDept.getId());
|
||||
// 设置更新的 ID
|
||||
o.setId(parentDept.getId());
|
||||
});
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_IS_CHILD);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static SysDeptDO randomDeptDO(Consumer<SysDeptDO>... consumers) {
|
||||
Consumer<SysDeptDO> consumer = (o) -> {
|
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
};
|
||||
return randomPojo(SysDeptDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
}
|
@@ -0,0 +1,200 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.dept;
|
||||
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExportReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysPostDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysPostMapper;
|
||||
import cn.iocoder.dashboard.modules.system.service.dept.impl.SysPostServiceImpl;
|
||||
import cn.iocoder.dashboard.util.collection.ArrayUtils;
|
||||
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.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* {@link SysPostServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author niudehua
|
||||
*/
|
||||
@Import(SysPostServiceImpl.class)
|
||||
class SysPostServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysPostServiceImpl postService;
|
||||
@Resource
|
||||
private SysPostMapper postMapper;
|
||||
|
||||
@Test
|
||||
void testPagePosts() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPojo(SysPostDO.class, o -> {
|
||||
o.setName("码仔");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
});
|
||||
postMapper.insert(postDO);
|
||||
// 测试 name 不匹配
|
||||
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
|
||||
// 测试 status 不匹配
|
||||
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
|
||||
// 准备参数
|
||||
SysPostPageReqVO reqVO = new SysPostPageReqVO();
|
||||
reqVO.setName("码");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
PageResult<SysPostDO> pageResult = postService.pagePosts(reqVO);
|
||||
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(postDO, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testListPosts() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPojo(SysPostDO.class, o -> {
|
||||
o.setName("码仔");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
});
|
||||
postMapper.insert(postDO);
|
||||
// 测试 name 不匹配
|
||||
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
|
||||
// 测试 status 不匹配
|
||||
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 准备参数
|
||||
SysPostExportReqVO reqVO = new SysPostExportReqVO();
|
||||
reqVO.setName("码");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
List<SysPostDO> list = postService.listPosts(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(postDO, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPost() {
|
||||
// mock 数据
|
||||
SysPostDO dbPostDO = randomPostDO();
|
||||
postMapper.insert(dbPostDO);
|
||||
// 准备参数
|
||||
Long id = dbPostDO.getId();
|
||||
// 调用
|
||||
SysPostDO post = postService.getPost(id);
|
||||
// 断言
|
||||
assertNotNull(post);
|
||||
assertPojoEquals(dbPostDO, post);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreatePost_success() {
|
||||
// 准备参数
|
||||
SysPostCreateReqVO reqVO = randomPojo(SysPostCreateReqVO.class,
|
||||
o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()));
|
||||
// 调用
|
||||
Long postId = postService.createPost(reqVO);
|
||||
// 断言
|
||||
assertNotNull(postId);
|
||||
// 校验记录的属性是否正确
|
||||
SysPostDO post = postMapper.selectById(postId);
|
||||
assertPojoEquals(reqVO, post);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdatePost_success() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPostDO();
|
||||
postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysPostUpdateReqVO reqVO = randomPojo(SysPostUpdateReqVO.class,
|
||||
o -> {
|
||||
// 设置更新的 ID
|
||||
o.setId(postDO.getId());
|
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus());
|
||||
});
|
||||
// 调用
|
||||
postService.updatePost(reqVO);
|
||||
// 校验是否更新正确
|
||||
SysPostDO post = postMapper.selectById(reqVO.getId());// 获取最新的
|
||||
assertPojoEquals(reqVO, post);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeletePost_success() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPostDO();
|
||||
postMapper.insert(postDO);
|
||||
// 准备参数
|
||||
Long id = postDO.getId();
|
||||
// 调用
|
||||
postService.deletePost(id);
|
||||
assertNull(postMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckPost_notFoundForDelete() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> postService.deletePost(id), POST_NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckPost_nameDuplicateForCreate() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPostDO();
|
||||
postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysPostCreateReqVO reqVO = randomPojo(SysPostCreateReqVO.class,
|
||||
// 模拟 name 重复
|
||||
o -> o.setName(postDO.getName()));
|
||||
assertServiceException(() -> postService.createPost(reqVO), POST_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckPost_codeDuplicateForUpdate() {
|
||||
// mock 数据
|
||||
SysPostDO postDO = randomPostDO();
|
||||
postMapper.insert(postDO);
|
||||
// mock 数据 稍后模拟重复它的 code
|
||||
SysPostDO codePostDO = randomPostDO();
|
||||
postMapper.insert(codePostDO);
|
||||
// 准备参数
|
||||
SysPostUpdateReqVO reqVO = randomPojo(SysPostUpdateReqVO.class,
|
||||
o -> {
|
||||
// 设置更新的 ID
|
||||
o.setId(postDO.getId());
|
||||
// 模拟 code 重复
|
||||
o.setCode(codePostDO.getCode());
|
||||
});
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> postService.updatePost(reqVO), POST_CODE_DUPLICATE);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static SysPostDO randomPostDO(Consumer<SysPostDO>... consumers) {
|
||||
Consumer<SysPostDO> consumer = (o) -> {
|
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
};
|
||||
return randomPojo(SysPostDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.dict;
|
||||
|
||||
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
|
||||
@@ -12,14 +12,20 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictDataServiceImpl;
|
||||
import cn.iocoder.dashboard.util.collection.ArrayUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.DICT_DATA_NOT_EXISTS;
|
||||
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.*;
|
||||
@@ -32,7 +38,8 @@ import static org.mockito.Mockito.*;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
|
||||
@Import(SysDictDataServiceImpl.class)
|
||||
public class SysDictDataServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysDictDataServiceImpl dictDataService;
|
||||
@@ -44,6 +51,37 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
|
||||
@MockBean
|
||||
private SysDictDataProducer dictDataProducer;
|
||||
|
||||
/**
|
||||
* 测试加载到新的字典数据的情况
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInitLocalCache() {
|
||||
// mock 数据
|
||||
SysDictDataDO dictData01 = randomDictDataDO();
|
||||
dictDataMapper.insert(dictData01);
|
||||
SysDictDataDO dictData02 = randomDictDataDO();
|
||||
dictDataMapper.insert(dictData02);
|
||||
|
||||
// 调用
|
||||
dictDataService.initLocalCache();
|
||||
// 断言 labelDictDataCache 缓存
|
||||
ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
|
||||
(ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "labelDictDataCache");
|
||||
assertEquals(2, labelDictDataCache.size());
|
||||
assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
|
||||
assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
|
||||
// 断言 valueDictDataCache 缓存
|
||||
ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
|
||||
(ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "valueDictDataCache");
|
||||
assertEquals(2, valueDictDataCache.size());
|
||||
assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
|
||||
assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
|
||||
// 断言 maxUpdateTime 缓存
|
||||
Date maxUpdateTime = (Date) getFieldValue(dictDataService, "maxUpdateTime");
|
||||
assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDictDataPage() {
|
||||
// mock 数据
|
||||
@@ -107,8 +145,7 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
|
||||
SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
|
||||
o -> o.setStatus(randomCommonStatus()));
|
||||
// mock 方法
|
||||
when(dictTypeService.getDictType(eq(reqVO.getDictType())))
|
||||
.thenReturn(randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())));
|
||||
when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
|
||||
|
||||
// 调用
|
||||
Long dictDataId = dictDataService.createDictData(reqVO);
|
||||
@@ -124,50 +161,142 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
|
||||
@Test
|
||||
public void testUpdateDictData_success() {
|
||||
// mock 数据
|
||||
SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
|
||||
SysDictDataDO dbDictData = randomDictDataDO();
|
||||
dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
|
||||
o.setId(dbDictData.getId()); // 设置更新的 ID
|
||||
o.setStatus(randomCommonStatus());
|
||||
});
|
||||
// mock 方法,字典类型
|
||||
when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
|
||||
|
||||
// 调用
|
||||
dictDataService.updateDictData(reqVO);
|
||||
// 校验是否更新正确
|
||||
SysDictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, dictData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDictData_notExists() {
|
||||
// 准备参数
|
||||
SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_NOT_EXISTS);
|
||||
// 校验调用
|
||||
verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDictData_success() {
|
||||
// mock 数据
|
||||
SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
|
||||
SysDictDataDO dbDictData = randomDictDataDO();
|
||||
dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbDictData.getId();
|
||||
|
||||
// 调用
|
||||
dictDataService.deleteDictData(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(dictDataMapper.selectById(id));
|
||||
// 校验数据不存在了
|
||||
assertNull(dictDataMapper.selectById(id));
|
||||
// 校验调用
|
||||
verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDictData_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
public void testCheckDictDataExists_success() {
|
||||
// mock 数据
|
||||
SysDictDataDO dbDictData = randomDictDataDO();
|
||||
dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
|
||||
|
||||
// 调用成功
|
||||
dictDataService.checkDictDataExists(dbDictData.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataExists_notExists() {
|
||||
assertServiceException(() -> dictDataService.checkDictDataExists(randomLongId()), DICT_DATA_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeValid_success() {
|
||||
// mock 方法,数据类型被禁用
|
||||
String type = randomString();
|
||||
when(dictTypeService.getDictType(eq(type))).thenReturn(randomDictTypeDO(type));
|
||||
|
||||
// 调用, 成功
|
||||
dictDataService.checkDictTypeValid(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeValid_notExists() {
|
||||
assertServiceException(() -> dictDataService.checkDictTypeValid(randomString()), DICT_TYPE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeValid_notEnable() {
|
||||
// mock 方法,数据类型被禁用
|
||||
String dictType = randomString();
|
||||
when(dictTypeService.getDictType(eq(dictType))).thenReturn(
|
||||
randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictDataService.deleteDictData(id), DICT_DATA_NOT_EXISTS);
|
||||
assertServiceException(() -> dictDataService.checkDictTypeValid(dictType), DICT_TYPE_NOT_ENABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataValueUnique_success() {
|
||||
// 调用,成功
|
||||
dictDataService.checkDictDataValueUnique(randomLongId(), randomString(), randomString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataValueUnique_valueDuplicateForCreate() {
|
||||
// 准备参数
|
||||
String dictType = randomString();
|
||||
String value = randomString();
|
||||
// mock 数据
|
||||
dictDataMapper.insert(randomDictDataDO(o -> {
|
||||
o.setDictType(dictType);
|
||||
o.setValue(value);
|
||||
}));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictDataService.checkDictDataValueUnique(null, dictType, value),
|
||||
DICT_DATA_VALUE_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataValueUnique_valueDuplicateForUpdate() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
String dictType = randomString();
|
||||
String value = randomString();
|
||||
// mock 数据
|
||||
dictDataMapper.insert(randomDictDataDO(o -> {
|
||||
o.setDictType(dictType);
|
||||
o.setValue(value);
|
||||
}));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictDataService.checkDictDataValueUnique(id, dictType, value),
|
||||
DICT_DATA_VALUE_DUPLICATE);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
private static SysDictDataDO randomDictDataDO(Consumer<SysDictDataDO>... consumers) {
|
||||
Consumer<SysDictDataDO> consumer = (o) -> {
|
||||
o.setStatus(randomCommonStatus()); // 保证 status 的范围
|
||||
};
|
||||
return randomPojo(SysDictDataDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一个有效的字典类型
|
||||
*
|
||||
* @param type 字典类型
|
||||
* @return SysDictTypeDO 对象
|
||||
*/
|
||||
private static SysDictTypeDO randomDictTypeDO(String type) {
|
||||
return randomPojo(SysDictTypeDO.class, o -> {
|
||||
o.setType(type);
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 是开启
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.dict;
|
||||
|
||||
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeCreateReqVO;
|
||||
@@ -14,6 +14,7 @@ import cn.iocoder.dashboard.util.collection.ArrayUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
@@ -23,8 +24,7 @@ import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.*;
|
||||
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -35,7 +35,8 @@ import static org.mockito.Mockito.when;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
|
||||
@Import(SysDictTypeServiceImpl.class)
|
||||
public class SysDictTypeServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysDictTypeServiceImpl dictTypeService;
|
||||
@@ -142,32 +143,6 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
|
||||
assertPojoEquals(reqVO, dictType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDictType_nameDuplicate() {
|
||||
// mock 数据
|
||||
SysDictTypeDO dbDictType = randomDictTypeDO();
|
||||
dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
|
||||
o -> o.setName(dbDictType.getName())); // 模拟 name 重复
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDictType_typeDuplicate() {
|
||||
// mock 数据
|
||||
SysDictTypeDO dbDictType = randomDictTypeDO();
|
||||
dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
|
||||
o -> o.setType(dbDictType.getType())); // 模拟 type 重复
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_TYPE_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDictType_success() {
|
||||
// mock 数据
|
||||
@@ -186,33 +161,6 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
|
||||
assertPojoEquals(reqVO, dictType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDictType_notExists() {
|
||||
// 准备参数
|
||||
SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDictType_nameDuplicate() {
|
||||
// mock 数据,稍后更新它
|
||||
SysDictTypeDO dbDictType = randomDictTypeDO();
|
||||
dictTypeMapper.insert(dbDictType);
|
||||
// mock 数据,ks稍后模拟重复它的名字
|
||||
SysDictTypeDO nameDictType = randomDictTypeDO();
|
||||
dictTypeMapper.insert(nameDictType);
|
||||
// 准备参数
|
||||
SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class, o -> {
|
||||
o.setId(dbDictType.getId()); // 设置更新的 ID
|
||||
o.setName(nameDictType.getName()); // 模拟 name 重复
|
||||
});
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDictType_success() {
|
||||
// mock 数据
|
||||
@@ -227,15 +175,6 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
|
||||
assertNull(dictTypeMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDictType_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDictType_hasChildren() {
|
||||
// mock 数据
|
||||
@@ -250,6 +189,83 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
|
||||
assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataExists_success() {
|
||||
// mock 数据
|
||||
SysDictTypeDO dbDictType = randomDictTypeDO();
|
||||
dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
|
||||
|
||||
// 调用成功
|
||||
dictTypeService.checkDictTypeExists(dbDictType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictDataExists_notExists() {
|
||||
assertServiceException(() -> dictTypeService.checkDictTypeExists(randomLongId()), DICT_TYPE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeUnique_success() {
|
||||
// 调用,成功
|
||||
dictTypeService.checkDictTypeUnique(randomLongId(), randomString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeUnique_valueDuplicateForCreate() {
|
||||
// 准备参数
|
||||
String type = randomString();
|
||||
// mock 数据
|
||||
dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictTypeService.checkDictTypeUnique(null, type),
|
||||
DICT_TYPE_TYPE_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeUnique_valueDuplicateForUpdate() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
String type = randomString();
|
||||
// mock 数据
|
||||
dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictTypeService.checkDictTypeUnique(id, type),
|
||||
DICT_TYPE_TYPE_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypNameUnique_success() {
|
||||
// 调用,成功
|
||||
dictTypeService.checkDictTypeNameUnique(randomLongId(), randomString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeNameUnique_nameDuplicateForCreate() {
|
||||
// 准备参数
|
||||
String name = randomString();
|
||||
// mock 数据
|
||||
dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictTypeService.checkDictTypeNameUnique(null, name),
|
||||
DICT_TYPE_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDictTypeNameUnique_nameDuplicateForUpdate() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
String name = randomString();
|
||||
// mock 数据
|
||||
dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name)));
|
||||
|
||||
// 调用,校验异常
|
||||
assertServiceException(() -> dictTypeService.checkDictTypeNameUnique(id, name),
|
||||
DICT_TYPE_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
|
@@ -0,0 +1,164 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.notice;
|
||||
|
||||
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticeCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticePageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticeUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.notice.SysNoticeDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.notice.SysNoticeMapper;
|
||||
import cn.iocoder.dashboard.modules.system.enums.notice.SysNoticeTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.service.notice.impl.SysNoticeServiceImpl;
|
||||
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.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.NOTICE_NOT_FOUND;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@Import(SysNoticeServiceImpl.class)
|
||||
class SysNoticeServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysNoticeServiceImpl sysNoticeService;
|
||||
|
||||
@Resource
|
||||
private SysNoticeMapper sysNoticeMapper;
|
||||
|
||||
@Test
|
||||
public void testPageNotices_success() {
|
||||
// 插入前置数据
|
||||
SysNoticeDO dbNotice = randomPojo(SysNoticeDO.class, o -> {
|
||||
o.setTitle("尼古拉斯赵四来啦!");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setType(randomEle(SysNoticeTypeEnum.values()).getType());
|
||||
});
|
||||
sysNoticeMapper.insert(dbNotice);
|
||||
|
||||
// 测试 title 不匹配
|
||||
sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setTitle("尼古拉斯凯奇也来啦!")));
|
||||
// 测试 status 不匹配
|
||||
sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
|
||||
|
||||
// 查询
|
||||
SysNoticePageReqVO reqVO = new SysNoticePageReqVO();
|
||||
reqVO.setTitle("尼古拉斯赵四来啦!");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
PageResult<SysNoticeDO> pageResult = sysNoticeService.pageNotices(reqVO);
|
||||
|
||||
// 验证查询结果经过筛选
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbNotice, pageResult.getList().get(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotice_success() {
|
||||
// 插入前置数据
|
||||
SysNoticeDO dbNotice = randomSysNoticeDO();
|
||||
sysNoticeMapper.insert(dbNotice);
|
||||
|
||||
// 查询
|
||||
SysNoticeDO notice = sysNoticeService.getNotice(dbNotice.getId());
|
||||
|
||||
// 验证插入与读取对象是否一致
|
||||
assertNotNull(notice);
|
||||
assertPojoEquals(dbNotice, notice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNotice_success() {
|
||||
// 准备参数
|
||||
SysNoticeCreateReqVO reqVO = randomSysNoticeCreateReqVO();
|
||||
|
||||
// 校验插入是否成功
|
||||
Long noticeId = sysNoticeService.createNotice(reqVO);
|
||||
assertNotNull(noticeId);
|
||||
|
||||
// 校验插入属性是否正确
|
||||
SysNoticeDO notice = sysNoticeMapper.selectById(noticeId);
|
||||
assertPojoEquals(reqVO, notice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateNotice_success() {
|
||||
// 插入前置数据
|
||||
SysNoticeDO dbNoticeDO = randomSysNoticeDO();
|
||||
sysNoticeMapper.insert(dbNoticeDO);
|
||||
|
||||
// 准备更新参数
|
||||
SysNoticeUpdateReqVO reqVO = randomSysNoticeUpdateReqVO(o -> o.setId(dbNoticeDO.getId()));
|
||||
|
||||
// 更新
|
||||
sysNoticeService.updateNotice(reqVO);
|
||||
|
||||
// 检验是否更新成功
|
||||
SysNoticeDO notice = sysNoticeMapper.selectById(reqVO.getId());
|
||||
assertPojoEquals(reqVO, notice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteNotice_success() {
|
||||
// 插入前置数据
|
||||
SysNoticeDO dbNotice = randomSysNoticeDO();
|
||||
sysNoticeMapper.insert(dbNotice);
|
||||
|
||||
// 删除
|
||||
sysNoticeService.deleteNotice(dbNotice.getId());
|
||||
|
||||
// 检查是否删除成功
|
||||
assertNull(sysNoticeMapper.selectById(dbNotice.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNoticeExists_success() {
|
||||
// 插入前置数据
|
||||
SysNoticeDO dbNotice = randomSysNoticeDO();
|
||||
sysNoticeMapper.insert(dbNotice);
|
||||
|
||||
// 成功调用
|
||||
sysNoticeService.checkNoticeExists(dbNotice.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNoticeExists_noExists() {
|
||||
assertServiceException(() -> sysNoticeService.checkNoticeExists(randomLongId()), NOTICE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static SysNoticeDO randomSysNoticeDO(Consumer<SysNoticeDO>... consumers) {
|
||||
SysNoticeDO notice = randomPojo(SysNoticeDO.class, consumers);
|
||||
notice.setType(randomEle(SysNoticeTypeEnum.values()).getType());
|
||||
notice.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return notice;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static SysNoticeUpdateReqVO randomSysNoticeUpdateReqVO(Consumer<SysNoticeUpdateReqVO>... consumers) {
|
||||
SysNoticeUpdateReqVO reqVO = randomPojo(SysNoticeUpdateReqVO.class, consumers);
|
||||
reqVO.setType(randomEle(SysNoticeTypeEnum.values()).getType());
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return reqVO;
|
||||
}
|
||||
|
||||
private static SysNoticeCreateReqVO randomSysNoticeCreateReqVO() {
|
||||
SysNoticeCreateReqVO reqVO = randomPojo(SysNoticeCreateReqVO.class);
|
||||
reqVO.setType(randomEle(SysNoticeTypeEnum.values()).getType());
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return reqVO;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -3,21 +3,6 @@ spring:
|
||||
lazy-initialization: true # 开启懒加载,加快速度
|
||||
banner-mode: off # 单元测试,禁用 Banner
|
||||
|
||||
# 去除的自动配置项
|
||||
autoconfigure:
|
||||
exclude:
|
||||
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration # 单元测试,禁用 SpringSecurity
|
||||
- org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration # 单元测试,禁用 SpringSecurity
|
||||
- org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 单元测试,禁用 Quartz
|
||||
- com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration # 单元测试,禁用 Lock4j 分布式锁
|
||||
- org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration # 单元测试,禁用 Scheduler 定时任务
|
||||
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration # 项目没有使用 Spring Data,所以禁用配置类,加速启动
|
||||
|
||||
# Swagger 接口文档的自动配置(单元测试,禁用 Swagger)
|
||||
springfox:
|
||||
documentation:
|
||||
auto-startup: false
|
||||
|
||||
--- #################### 数据库相关配置 ####################
|
||||
|
||||
spring:
|
||||
@@ -29,6 +14,9 @@ spring:
|
||||
username: sa
|
||||
password:
|
||||
schema: classpath:sql/create_tables.sql # MySQL 转 H2 的语句,使用 https://www.jooq.org/translate/ 工具
|
||||
druid:
|
||||
async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
|
||||
initial-size: 1 # 单元测试,配置为 1,提升启动速度
|
||||
|
||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
||||
redis:
|
||||
@@ -36,17 +24,13 @@ spring:
|
||||
port: 16379 # 端口(单元测试,使用 16379 端口)
|
||||
database: 0 # 数据库索引
|
||||
|
||||
mybatis:
|
||||
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
# Quartz 配置项,对应 QuartzProperties 配置类(单元测试,禁用 Quartz)
|
||||
|
||||
--- #################### 配置中心相关配置 ####################
|
||||
|
||||
# Apollo 配置中心
|
||||
apollo:
|
||||
bootstrap:
|
||||
enabled: false # 单元测试,禁用配置中心
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
# Lock4j 配置项(单元测试,禁用 Lock4j)
|
||||
@@ -63,23 +47,6 @@ resilience4j:
|
||||
|
||||
--- #################### 监控相关配置 ####################
|
||||
|
||||
# Actuator 监控端点的配置项
|
||||
management:
|
||||
endpoints:
|
||||
enabled-by-default: false
|
||||
|
||||
# Spring Boot Admin 配置项
|
||||
spring:
|
||||
boot:
|
||||
admin:
|
||||
# Spring Boot Admin Client 客户端的相关配置
|
||||
client:
|
||||
enabled: false
|
||||
# Spring Boot Admin Server 服务端的相关配置
|
||||
context-path: /admin # 配置 Spring
|
||||
|
||||
# 日志文件配置(不需要配置)
|
||||
|
||||
--- #################### 芋道相关配置 ####################
|
||||
|
||||
# 芋道配置项,设置当前项目所有自定义的配置
|
||||
|
@@ -8,6 +8,8 @@ DELETE FROM "sys_role";
|
||||
DELETE FROM "sys_role_menu";
|
||||
DELETE FROM "sys_menu";
|
||||
DELETE FROM "sys_dict_type";
|
||||
DELETE FROM "sys_user_session";
|
||||
DELETE FROM "sys_post";
|
||||
DELETE FROM "sys_login_log";
|
||||
DELETE FROM "sys_operate_log";
|
||||
DELETE FROM "sys_user";
|
||||
|
@@ -9,9 +9,9 @@ CREATE TABLE IF NOT EXISTS "inf_config" (
|
||||
"value" varchar(500) NOT NULL DEFAULT '',
|
||||
"sensitive" bit NOT NULL,
|
||||
"remark" varchar(500) DEFAULT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -28,9 +28,9 @@ CREATE TABLE IF NOT EXISTS "sys_dept" (
|
||||
"phone" varchar(11) DEFAULT NULL,
|
||||
"email" varchar(50) DEFAULT NULL,
|
||||
"status" tinyint NOT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -44,9 +44,9 @@ CREATE TABLE IF NOT EXISTS "sys_dict_data" (
|
||||
"dict_type" varchar(100) NOT NULL DEFAULT '',
|
||||
"status" tinyint NOT NULL DEFAULT '0',
|
||||
"remark" varchar(500) DEFAULT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -62,9 +62,9 @@ CREATE TABLE IF NOT EXISTS "sys_role" (
|
||||
"status" tinyint NOT NULL,
|
||||
"type" tinyint NOT NULL,
|
||||
"remark" varchar(500) DEFAULT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -74,9 +74,9 @@ CREATE TABLE IF NOT EXISTS "sys_role_menu" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"role_id" bigint NOT NULL,
|
||||
"menu_id" bigint NOT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -93,9 +93,9 @@ CREATE TABLE IF NOT EXISTS "sys_menu" (
|
||||
"icon" varchar(100) DEFAULT '#',
|
||||
"component" varchar(255) DEFAULT NULL,
|
||||
"status" tinyint NOT NULL DEFAULT '0',
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
@@ -107,14 +107,61 @@ CREATE TABLE "sys_dict_type" (
|
||||
"type" varchar(100) NOT NULL DEFAULT '',
|
||||
"status" tinyint NOT NULL DEFAULT '0',
|
||||
"remark" varchar(500) DEFAULT NULL,
|
||||
"create_by" varchar(64) DEFAULT '',
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"update_by" varchar(64) DEFAULT '',
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '字典类型表';
|
||||
|
||||
CREATE TABLE `sys_user_session` (
|
||||
`id` varchar(32) NOT NULL,
|
||||
`user_id` bigint DEFAULT NULL,
|
||||
`username` varchar(50) NOT NULL DEFAULT '',
|
||||
`user_ip` varchar(50) DEFAULT NULL,
|
||||
`user_agent` varchar(512) DEFAULT NULL,
|
||||
`session_timeout` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"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 '用户在线 Session';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "sys_post"
|
||||
(
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"code" varchar(64) NOT NULL,
|
||||
"name" varchar(50) NOT NULL,
|
||||
"sort" integer NOT NULL,
|
||||
"status" tinyint NOT NULL,
|
||||
"remark" varchar(500) DEFAULT NULL,
|
||||
"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 '岗位信息表';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "sys_notice" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"title" varchar(50) NOT NULL COMMENT '公告标题',
|
||||
"content" text NOT NULL COMMENT '公告内容',
|
||||
"notice_type" tinyint NOT NULL COMMENT '公告类型(1通知 2公告)',
|
||||
"status" tinyint NOT NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)',
|
||||
"creator" varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
"updater" varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
"deleted" bit NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
PRIMARY KEY("id")
|
||||
) COMMENT '通知公告表';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sys_login_log` (
|
||||
`id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
`log_type` bigint(4) NOT NULL,
|
||||
|
Reference in New Issue
Block a user