From 113e34b2791ec9b54f5c2cd915890057454d92ed Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Mar 2021 22:36:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20dict=20data=20=E7=9A=84?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/mysql/dict/SysDictDataMapper.java | 4 +- .../dict/impl/SysDictDataServiceImpl.java | 22 +-- .../dashboard/util/collection/ArrayUtils.java | 6 +- .../service/dict/SysDictDataServiceTest.java | 140 +++++++++++++++++- 4 files changed, 150 insertions(+), 22 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java index a9a4a1d55..f135a6f8c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java @@ -15,9 +15,9 @@ import java.util.List; @Mapper public interface SysDictDataMapper extends BaseMapperX { - default SysDictDataDO selectByDictTypeAndLabel(String dictType, String label) { + default SysDictDataDO selectByDictTypeAndLabel(String dictType, String value) { return selectOne(new QueryWrapper().eq("dict_type", dictType) - .eq("label", label)); + .eq("value", value)); } default int selectCountByDictType(String dictType) { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java index e8ebb82dc..029e10d27 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -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,9 +9,9 @@ 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; @@ -28,6 +27,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 +156,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 +168,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,13 +191,13 @@ 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) { @@ -207,10 +207,10 @@ public class SysDictDataServiceImpl implements SysDictDataService { } // 如果 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); } } @@ -220,17 +220,17 @@ public class SysDictDataServiceImpl implements SysDictDataService { } 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) { 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); } } diff --git a/src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java b/src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java index 7dc9fb654..e40442732 100644 --- a/src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java @@ -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[] append(T object, T... newElements) { + public static Consumer[] append(Consumer object, Consumer... newElements) { if (object == null) { return newElements; } - T[] result = ArrayUtil.newArray(object.getClass(), 1 + newElements.length); + Consumer[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length); result[0] = object; System.arraycopy(newElements, 0, result, 1, newElements.length); return result; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java index 318a4afca..8d976c31f 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java @@ -12,14 +12,16 @@ 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 org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import javax.annotation.Resource; 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.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.*; @@ -107,8 +109,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); @@ -121,21 +122,66 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest { verify(dictDataProducer, times(1)).sendDictDataRefreshMessage(); } + @Test + public void testCreateDictData_dictTypeNotExists() { + // 准备参数 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class, + o -> o.setStatus(randomCommonStatus())); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_EXISTS); + } + + @Test + public void testCreateDictData_dictTypeNotEnable() { + // 准备参数 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class, + o -> o.setStatus(randomCommonStatus())); + // mock 方法,数据类型被禁用 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn( + randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_ENABLE); + } + + @Test + public void testCreateDictData_dictDataValueDuplicate() { + // 准备参数 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class, + o -> o.setStatus(randomCommonStatus())); + // mock 方法,字典类型 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType())); + // mock dictData 重复 value 重复 + dictDataMapper.insert(randomDictDataDO(o -> { + o.setDictType(reqVO.getDictType()); + o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复 + })); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_DATA_VALUE_DUPLICATE); + } + @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); + // 校验调用 + verify(dictDataProducer, times(1)).sendDictDataRefreshMessage(); } @Test @@ -147,18 +193,75 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest { assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_NOT_EXISTS); } + @Test + public void testUpdateDictData_dictTypeNotExists() { + // mock 数据 + SysDictDataDO dbDictData = randomDictDataDO(); + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> { + o.setId(dbDictData.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_EXISTS); + } + + @Test + public void testUpdateDictData_dictTypeNotEnable() { + // mock 数据 + 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( + randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_ENABLE); + } + + @Test + public void testUpdateDictData_dictDataValueDuplicate() { + // mock 数据 + 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())); + // mock dictData 重复 value 重复 + dictDataMapper.insert(randomDictDataDO(o -> { + o.setDictType(reqVO.getDictType()); + o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复 + })); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_VALUE_DUPLICATE); + } + @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 @@ -170,4 +273,27 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest { assertServiceException(() -> dictDataService.deleteDictData(id), DICT_DATA_NOT_EXISTS); } + // ========== 随机对象 ========== + + @SafeVarargs + private static SysDictDataDO randomDictDataDO(Consumer... consumers) { + Consumer 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 是开启 + }); + } + }