diff --git a/pom.xml b/pom.xml index 1ca158c9f..b6290c1d6 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 1.1.0-snapshot + 1.2.0-snapshot 1.8 ${java.version} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/InfFileController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/InfFileController.java index 6b2c743ca..ede2a68bb 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/InfFileController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/InfFileController.java @@ -1,13 +1,14 @@ package cn.iocoder.yudao.adminserver.modules.infra.controller.file; import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService; +import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; +import cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo.InfFileRespVO; import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFileRespVO; import cn.iocoder.yudao.adminserver.modules.infra.convert.file.InfFileConvert; -import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -36,6 +37,8 @@ public class InfFileController { @Resource private InfFileService fileService; + @Resource + private InfFileCoreService fileCoreService; @PostMapping("/upload") @ApiOperation("上传文件") @@ -45,7 +48,7 @@ public class InfFileController { }) public CommonResult uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws IOException { - return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream()))); + return success(fileCoreService.createFile(path, IoUtil.readBytes(file.getInputStream()))); } @DeleteMapping("/delete") @@ -53,7 +56,7 @@ public class InfFileController { @ApiImplicitParam(name = "id", value = "编号", required = true) @PreAuthorize("@ss.hasPermission('infra:file:delete')") public CommonResult deleteFile(@RequestParam("id") String id) { - fileService.deleteFile(id); + fileCoreService.deleteFile(id); return success(true); } @@ -61,7 +64,7 @@ public class InfFileController { @ApiOperation("下载文件") @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class) public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException { - InfFileDO file = fileService.getFile(path); + InfFileDO file = fileCoreService.getFile(path); if (file == null) { log.warn("[getFile][path({}) 文件不存在]", path); response.setStatus(HttpStatus.NOT_FOUND.value()); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/file/InfFileConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/file/InfFileConvert.java index d39452ffe..aedad94d9 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/file/InfFileConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/file/InfFileConvert.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.adminserver.modules.infra.convert.file; +import cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo.InfFileRespVO; import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFileRespVO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/mysql/file/InfFileMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/mysql/file/InfFileMapper.java index 022f90acb..d3dfcccbb 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/mysql/file/InfFileMapper.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/mysql/file/InfFileMapper.java @@ -1,19 +1,19 @@ package cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file; +import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; import org.apache.ibatis.annotations.Mapper; +/** + * admin 文件操作 Mapper + * + * @author 芋道源码 + */ @Mapper public interface InfFileMapper extends BaseMapperX { - - default Integer selectCountById(String id) { - return selectCount("id", id); - } - default PageResult selectPage(InfFilePageReqVO reqVO) { return selectPage(reqVO, new QueryWrapperX() .likeIfPresent("id", reqVO.getId()) @@ -21,5 +21,4 @@ public interface InfFileMapper extends BaseMapperX { .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc("create_time")); } - } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/InfErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/InfErrorCodeConstants.java index b53ff8c1d..98155e723 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/InfErrorCodeConstants.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/InfErrorCodeConstants.java @@ -27,7 +27,4 @@ public interface InfErrorCodeConstants { ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1001002000, "API 错误日志不存在"); ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1001002001, "API 错误日志已处理"); - // ========== 文件 1001003000 ========== - ErrorCode FILE_NOT_EXISTS = new ErrorCode(1001003000, "文件不存在"); - } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileService.java index e19e3ecab..1c8311b29 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileService.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.adminserver.modules.infra.service.file; +import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; /** * 文件 Service 接口 @@ -11,30 +11,6 @@ import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePage */ public interface InfFileService { - /** - * 保存文件,并返回文件的访问路径 - * - * @param path 文件路径 - * @param content 文件内容 - * @return 文件路径 - */ - String createFile(String path, byte[] content); - - /** - * 删除文件 - * - * @param id 编号 - */ - void deleteFile(String id); - - /** - * 获得文件 - * - * @param path 文件路径 - * @return 文件 - */ - InfFileDO getFile(String path); - /** * 获得文件分页 * diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/impl/InfFileServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/impl/InfFileServiceImpl.java index 0436b804f..b8967c638 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/impl/InfFileServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/impl/InfFileServiceImpl.java @@ -1,20 +1,14 @@ package cn.iocoder.yudao.adminserver.modules.infra.service.file.impl; -import cn.hutool.core.io.FileTypeUtil; -import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.adminserver.modules.infra.framework.file.config.FileProperties; -import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file.InfFileMapper; import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService; +import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; +import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.io.ByteArrayInputStream; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants.FILE_NOT_EXISTS; -import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS; /** * 文件 Service 实现类 @@ -27,43 +21,6 @@ public class InfFileServiceImpl implements InfFileService { @Resource private InfFileMapper fileMapper; - @Resource - private FileProperties fileProperties; - - @Override - public String createFile(String path, byte[] content) { - if (fileMapper.selectCountById(path) > 0) { - throw exception(FILE_PATH_EXISTS); - } - // 保存到数据库 - InfFileDO file = new InfFileDO(); - file.setId(path); - file.setType(FileTypeUtil.getType(new ByteArrayInputStream(content))); - file.setContent(content); - fileMapper.insert(file); - // 拼接路径返回 - return fileProperties.getBasePath() + path; - } - - @Override - public void deleteFile(String id) { - // 校验存在 - this.validateFileExists(id); - // 更新 - fileMapper.deleteById(id); - } - - private void validateFileExists(String id) { - if (fileMapper.selectById(id) == null) { - throw exception(FILE_NOT_EXISTS); - } - } - - @Override - public InfFileDO getFile(String path) { - return fileMapper.selectById(path); - } - @Override public PageResult getFilePage(InfFilePageReqVO pageReqVO) { return fileMapper.selectPage(pageReqVO); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java index 3b4051d20..7da1f4239 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.system.enums; import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import javafx.beans.binding.MapExpression; /** * System 错误码枚举类 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java index af7705b63..8901ca022 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.*; @@ -16,6 +15,7 @@ import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.ServiceException; @@ -59,7 +59,7 @@ public class SysUserServiceImpl implements SysUserService { @Resource private PasswordEncoder passwordEncoder; @Resource - private InfFileService fileService; + private InfFileCoreService fileService; @Override public Long createUser(SysUserCreateReqVO reqVO) { diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileServiceTest.java index 4849d49cd..6a41c9420 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileServiceTest.java @@ -1,13 +1,12 @@ package cn.iocoder.yudao.adminserver.modules.infra.service.file; -import cn.hutool.core.io.resource.ResourceUtil; import cn.iocoder.yudao.adminserver.BaseDbUnitTest; -import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.adminserver.modules.infra.framework.file.config.FileProperties; import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO; -import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file.InfFileMapper; -import cn.iocoder.yudao.adminserver.modules.infra.service.file.impl.InfFileServiceImpl; +import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; +import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file.InfFileCoreMapper; +import cn.iocoder.yudao.coreservice.modules.infra.framework.file.config.FileProperties; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.impl.InfFileCoreServiceImpl; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; @@ -15,79 +14,22 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants.FILE_NOT_EXISTS; -import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; -import static org.junit.jupiter.api.Assertions.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; -@Import({InfFileServiceImpl.class, FileProperties.class}) +@Import({InfFileCoreServiceImpl.class, FileProperties.class}) public class InfFileServiceTest extends BaseDbUnitTest { @Resource - private InfFileServiceImpl fileService; + private InfFileService fileService; @MockBean private FileProperties fileProperties; @Resource - private InfFileMapper fileMapper; - - @Test - public void testCreateFile_success() { - // 准备参数 - String path = randomString(); - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - - // 调用 - String url = fileService.createFile(path, content); - // 断言 - assertEquals(fileProperties.getBasePath() + path, url); - // 校验数据 - InfFileDO file = fileMapper.selectById(path); - assertEquals(path, file.getId()); - assertEquals("jpg", file.getType()); - assertArrayEquals(content, file.getContent()); - } - - @Test - public void testCreateFile_exists() { - // mock 数据 - InfFileDO dbFile = randomPojo(InfFileDO.class); - fileMapper.insert(dbFile); - // 准备参数 - String path = dbFile.getId(); // 模拟已存在 - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - - // 调用,并断言异常 - assertServiceException(() -> fileService.createFile(path, content), FILE_PATH_EXISTS); - } - - @Test - public void testDeleteFile_success() { - // mock 数据 - InfFileDO dbFile = randomPojo(InfFileDO.class); - fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 - // 准备参数 - String id = dbFile.getId(); - - // 调用 - fileService.deleteFile(id); - // 校验数据不存在了 - assertNull(fileMapper.selectById(id)); - } - - @Test - public void testDeleteFile_notExists() { - // 准备参数 - String id = randomString(); - - // 调用, 并断言异常 - assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS); - } + private InfFileCoreMapper fileMapper; @Test public void testGetFilePage() { diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java index e20e72793..70751eeac 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.adminserver.modules.system.service.user; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.adminserver.BaseDbUnitTest; -import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.*; @@ -14,6 +13,7 @@ import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; import cn.iocoder.yudao.adminserver.modules.system.service.user.impl.SysUserServiceImpl; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.yudao.coreservice.modules.system.enums.common.SysSexEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -69,7 +69,7 @@ public class SysUserServiceImplTest extends BaseDbUnitTest { @MockBean private PasswordEncoder passwordEncoder; @MockBean - private InfFileService fileService; + private InfFileCoreService fileService; @Test public void testCreatUser_success() { diff --git a/yudao-core-service/pom.xml b/yudao-core-service/pom.xml index 42a7d9627..d1102ae22 100644 --- a/yudao-core-service/pom.xml +++ b/yudao-core-service/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - yudao cn.iocoder.boot - 1.1.0-snapshot + yudao + ${revision} 4.0.0 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/vo/InfFileRespVO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/controller/file/vo/InfFileRespVO.java similarity index 90% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/vo/InfFileRespVO.java rename to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/controller/file/vo/InfFileRespVO.java index 2388d7f3d..e264a3fd2 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/file/vo/InfFileRespVO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/controller/file/vo/InfFileRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo; +package cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/file/InfFileCoreMapper.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/file/InfFileCoreMapper.java index 180dc2d79..88266caae 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/file/InfFileCoreMapper.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/file/InfFileCoreMapper.java @@ -6,5 +6,7 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface InfFileCoreMapper extends BaseMapperX { - + default Integer selectCountById(String id) { + return selectCount("id", id); + } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileConfiguration.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileConfiguration.java similarity index 81% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileConfiguration.java rename to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileConfiguration.java index e71377e3f..a10c7a7af 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileConfiguration.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.adminserver.modules.infra.framework.file.config; +package cn.iocoder.yudao.coreservice.modules.infra.framework.file.config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileProperties.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileProperties.java similarity index 88% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileProperties.java rename to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileProperties.java index db1a6b71f..0d8ed7cda 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/config/FileProperties.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.adminserver.modules.infra.framework.file.config; +package cn.iocoder.yudao.coreservice.modules.infra.framework.file.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/package-info.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/package-info.java similarity index 92% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/package-info.java rename to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/package-info.java index a69b53eb5..2c2798ee6 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/file/package-info.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/package-info.java @@ -13,4 +13,4 @@ * 综合考虑,暂时使用方案 3 的方式,比较适合这样一个 all in one 的项目。 * 随着文件的量级大了之后,还是推荐采用云服务。 */ -package cn.iocoder.yudao.adminserver.modules.infra.framework.file; +package cn.iocoder.yudao.coreservice.modules.infra.framework.file; diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java new file mode 100644 index 000000000..a594bcef4 --- /dev/null +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.coreservice.modules.infra.service.file; + +import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; + +/** + * core service 文件接口 + * + * @author 宋天 + */ +public interface InfFileCoreService { + + + /** + * 保存文件,并返回文件的访问路径 + * + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + String createFile(String path, byte[] content); + + /** + * 删除文件 + * + * @param id 编号 + */ + void deleteFile(String id); + + /** + * 获得文件 + * + * @param path 文件路径 + * @return 文件 + */ + InfFileDO getFile(String path); +} diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/impl/InfFileCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/impl/InfFileCoreServiceImpl.java new file mode 100644 index 000000000..2f0fb2865 --- /dev/null +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/impl/InfFileCoreServiceImpl.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.coreservice.modules.infra.service.file.impl; + +import cn.hutool.core.io.FileTypeUtil; +import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; +import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file.InfFileCoreMapper; +import cn.iocoder.yudao.coreservice.modules.infra.framework.file.config.FileProperties; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; + +import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * core service 文件实现类 + * + * @author 宋天 + */ +@Service +public class InfFileCoreServiceImpl implements InfFileCoreService { + + @Resource + private InfFileCoreMapper fileMapper; + + @Resource + private FileProperties fileProperties; + + @Override + public String createFile(String path, byte[] content) { + if (fileMapper.selectCountById(path) > 0) { + throw exception(FILE_PATH_EXISTS); + } + // 保存到数据库 + InfFileDO file = new InfFileDO(); + file.setId(path); + file.setType(FileTypeUtil.getType(new ByteArrayInputStream(content))); + file.setContent(content); + fileMapper.insert(file); + // 拼接路径返回 + return fileProperties.getBasePath() + path; + } + + @Override + public void deleteFile(String id) { + // 校验存在 + this.validateFileExists(id); + // 更新 + fileMapper.deleteById(id); + } + + private void validateFileExists(String id) { + if (fileMapper.selectById(id) == null) { + throw exception(FILE_NOT_EXISTS); + } + } + + @Override + public InfFileDO getFile(String path) { + return fileMapper.selectById(path); + } + +} diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/SysErrorCodeConstants.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/SysErrorCodeConstants.java index a7231f421..173287e52 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/SysErrorCodeConstants.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/SysErrorCodeConstants.java @@ -14,9 +14,12 @@ public interface SysErrorCodeConstants { ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1006000001, "模板参数({})缺失"); ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1006000000, "短信模板不存在"); + // ========= 文件相关 1006001000================= + ErrorCode FILE_PATH_EXISTS = new ErrorCode(1006001000, "文件路径已存在"); + ErrorCode FILE_NOT_EXISTS = new ErrorCode(1006001002, "文件不存在"); - // ========== 社交模块 1006001000 ========== - ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1006001000, "社交授权失败,原因是:{}"); - ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1006001001, "社交解绑失败,非当前用户绑定"); + // ========== 社交模块 1006002000 ========== + ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1006002000, "社交授权失败,原因是:{}"); + ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1006002001, "社交解绑失败,非当前用户绑定"); } diff --git a/yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreServiceTest.java b/yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreServiceTest.java new file mode 100644 index 000000000..ce3d69395 --- /dev/null +++ b/yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreServiceTest.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.coreservice.modules.infra.service.file; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.iocoder.yudao.coreservice.BaseDbUnitTest; +import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; +import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file.InfFileCoreMapper; +import cn.iocoder.yudao.coreservice.modules.infra.framework.file.config.FileProperties; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.impl.InfFileCoreServiceImpl; +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 static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_NOT_EXISTS; +import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.junit.jupiter.api.Assertions.*; + +@Import({InfFileCoreServiceImpl.class, FileProperties.class}) +public class InfFileCoreServiceTest extends BaseDbUnitTest { + + @Resource + private InfFileCoreService fileCoreService; + + @MockBean + private FileProperties fileProperties; + + @Resource + private InfFileCoreMapper fileMapper; + + @Test + public void testCreateFile_success() { + // 准备参数 + String path = randomString(); + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + + // 调用 + String url = fileCoreService.createFile(path, content); + // 断言 + assertEquals(fileProperties.getBasePath() + path, url); + // 校验数据 + InfFileDO file = fileMapper.selectById(path); + assertEquals(path, file.getId()); + assertEquals("jpg", file.getType()); + assertArrayEquals(content, file.getContent()); + } + + @Test + public void testCreateFile_exists() { + // mock 数据 + InfFileDO dbFile = randomPojo(InfFileDO.class); + fileMapper.insert(dbFile); + // 准备参数 + String path = dbFile.getId(); // 模拟已存在 + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + + // 调用,并断言异常 + assertServiceException(() -> fileCoreService.createFile(path, content), FILE_PATH_EXISTS); + } + + @Test + public void testDeleteFile_success() { + // mock 数据 + InfFileDO dbFile = randomPojo(InfFileDO.class); + fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 + // 准备参数 + String id = dbFile.getId(); + + // 调用 + fileCoreService.deleteFile(id); + // 校验数据不存在了 + assertNull(fileMapper.selectById(id)); + } + + @Test + public void testDeleteFile_notExists() { + // 准备参数 + String id = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> fileCoreService.deleteFile(id), FILE_NOT_EXISTS); + } + +} diff --git a/yudao-admin-server/src/test/resources/file/erweima.jpg b/yudao-core-service/src/test/resources/file/erweima.jpg similarity index 100% rename from yudao-admin-server/src/test/resources/file/erweima.jpg rename to yudao-core-service/src/test/resources/file/erweima.jpg diff --git a/yudao-core-service/src/test/resources/sql/clean.sql b/yudao-core-service/src/test/resources/sql/clean.sql index 855ccf7eb..e92bf3e43 100644 --- a/yudao-core-service/src/test/resources/sql/clean.sql +++ b/yudao-core-service/src/test/resources/sql/clean.sql @@ -1,5 +1,6 @@ -- inf 开头的 DB DELETE FROM "inf_api_access_log"; +DELETE FROM "inf_file"; DELETE FROM "inf_api_error_log"; -- sys 开头的 DB diff --git a/yudao-core-service/src/test/resources/sql/create_tables.sql b/yudao-core-service/src/test/resources/sql/create_tables.sql index 2076e0c5d..d78e9e7fe 100644 --- a/yudao-core-service/src/test/resources/sql/create_tables.sql +++ b/yudao-core-service/src/test/resources/sql/create_tables.sql @@ -1,5 +1,17 @@ -- inf 开头的 DB +CREATE TABLE IF NOT EXISTS "inf_file" ( + "id" varchar(188) NOT NULL, + "type" varchar(63) DEFAULT NULL, + "content" blob NOT 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 '文件表'; + -- sys 开头的 DB CREATE TABLE IF NOT EXISTS `sys_user_session` ( diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 125d3bdaf..723ea0c6a 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -14,7 +14,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 1.1.0-snapshot + 1.2.0-snapshot 2.4.5 diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.http b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.http index 72cf861b8..1ce9eea62 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.http +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.http @@ -1,3 +1,11 @@ ### 请求 /system/user/profile/get 接口 => 没有权限 GET {{userServerUrl}}/system/user/profile/get Authorization: Bearer test245 + +### 请求 /system/user/profile/revise-nickname 接口 成功 +PUT {{userServerUrl}}/system/user/profile/update-nickname?nickName=yunai222 +Authorization: Bearer test245 + +### 请求 /system/user/profile/get-user-info 接口 成功 +GET {{userServerUrl}}/system/user/profile/get-user-info?id=245 +Authorization: Bearer test245 \ No newline at end of file diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java index 4b66b4e18..870d33718 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java @@ -1,14 +1,24 @@ package cn.iocoder.yudao.userserver.modules.member.controller.user; +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +import java.io.IOException; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY; @Api(tags = "用户个人中心") @RestController @@ -17,11 +27,34 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class SysUserProfileController { - @GetMapping("/get") - @ApiOperation("获得登录用户信息") + @Resource + private MbrUserService userService; + + @PutMapping("/update-nickname") + @ApiOperation("修改用户昵称") @PreAuthenticated - public CommonResult profile() { - return null; + public CommonResult updateNickname(@RequestParam("nickName") String nickName) { + userService.updateNickname(getLoginUserId(), nickName); + return success(true); + } + + @PutMapping("/update-avatar") + @ApiOperation("修改用户头像") + @PreAuthenticated + public CommonResult updateAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException { + if (file.isEmpty()) { + throw ServiceExceptionUtil.exception(FILE_IS_EMPTY); + } + String avatar = userService.updateAvatar(getLoginUserId(), file.getInputStream()); + return success(avatar); + } + + @GetMapping("/get-user-info") + @ApiOperation("获取用户头像与昵称") + @PreAuthenticated + public CommonResult getUserInfo() { + return success(userService.getUserInfo(getLoginUserId())); } } + diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserInfoRespVO.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserInfoRespVO.java new file mode 100644 index 000000000..e46bd410f --- /dev/null +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserInfoRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.userserver.modules.member.controller.user.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel("用户个人信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MbrUserInfoRespVO { + + @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") + private String nickName; + + @ApiModelProperty(value = "用户头像", required = true, example = "/infra/file/get/35a12e57-4297-4faa-bf7d-7ed2f211c952") + private String avatar; +} diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java index 265d1d485..3794eb09d 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java @@ -9,4 +9,9 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface MbrErrorCodeConstants { + // ==========用户相关 1004001000============ + ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); + + // ==========文件相关 1004002000 =========== + ErrorCode FILE_IS_EMPTY = new ErrorCode(1004002000, "文件为空"); } diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java index 2d5466865..6b6a36a8e 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.userserver.modules.member.service.user; import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; import cn.iocoder.yudao.framework.common.validation.Mobile; +import java.io.InputStream; + /** * 前台用户 Service 接口 * @@ -44,4 +47,26 @@ public interface MbrUserService { */ MbrUserDO getUser(Long id); + /** + * 修改用户昵称 + * @param userId 用户id + * @param nickName 用户新昵称 + */ + void updateNickname(Long userId, String nickName); + + /** + * 修改用户头像 + * @param userId 用户id + * @param inputStream 头像文件 + * @return 头像url + */ + String updateAvatar(Long userId, InputStream inputStream); + + /** + * 根据用户id,获取用户头像与昵称 + * @param userId 用户id + * @return 用户响应实体类 + */ + MbrUserInfoRespVO getUserInfo(Long userId); + } diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java index 71fb9dd88..f340c5fe9 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java @@ -1,18 +1,26 @@ package cn.iocoder.yudao.userserver.modules.member.service.user.impl; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; +import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.validation.Valid; +import java.io.InputStream; import java.util.Date; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.USER_NOT_EXISTS; + /** * User Service 实现类 * @@ -26,6 +34,9 @@ public class MbrUserServiceImpl implements MbrUserService { @Resource private MbrUserMapper userMapper; + @Resource + private InfFileCoreService fileCoreService; + @Resource private PasswordEncoder passwordEncoder; @@ -68,4 +79,53 @@ public class MbrUserServiceImpl implements MbrUserService { return userMapper.selectById(id); } + @Override + public void updateNickname(Long userId, String nickName) { + MbrUserDO user = this.checkUserExists(userId); + // 仅当新昵称不等于旧昵称时进行修改 + if (nickName.equals(user.getNickname())){ + return; + } + MbrUserDO userDO = new MbrUserDO(); + userDO.setId(user.getId()); + userDO.setNickname(nickName); + userMapper.updateById(userDO); + } + + @Override + public String updateAvatar(Long userId, InputStream avatarFile) { + this.checkUserExists(userId); + // 创建文件 + String avatar = fileCoreService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile)); + // 更新头像路径 + MbrUserDO userDO = MbrUserDO.builder() + .id(userId) + .avatar(avatar) + .build(); + userMapper.updateById(userDO); + return avatar; + } + + @Override + public MbrUserInfoRespVO getUserInfo(Long userId) { + MbrUserDO user = this.checkUserExists(userId); + // 拼接返回结果 + MbrUserInfoRespVO userResp = new MbrUserInfoRespVO(); + userResp.setNickName(user.getNickname()); + userResp.setAvatar(user.getAvatar()); + return userResp; + } + + @VisibleForTesting + public MbrUserDO checkUserExists(Long id) { + if (id == null) { + return null; + } + MbrUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + }else{ + return user; + } + } } diff --git a/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbUnitTest.java b/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbUnitTest.java new file mode 100644 index 000000000..af8d71a0c --- /dev/null +++ b/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbUnitTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.userserver; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +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.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +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 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + }) + public static class Application { + } + +} diff --git a/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java b/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java new file mode 100644 index 000000000..3639c25db --- /dev/null +++ b/yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.userserver.modules.member.service; + +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; +import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.userserver.BaseDbUnitTest; +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; +import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; +import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import java.io.*; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomBytes; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.mockito.Mockito.*; +/** + * {@link MbrUserServiceImpl} 的单元测试类 + * + * @author 宋天 + */ +@Import(MbrUserServiceImpl.class) +public class MbrUserServiceImplTest extends BaseDbUnitTest { + + @Resource + private MbrUserServiceImpl mbrUserService; + + @Resource + private MbrUserMapper userMapper; + + @MockBean + private InfFileCoreService fileCoreService; + + @MockBean + private PasswordEncoder passwordEncoder; + + @Test + public void testUpdateNickName_success(){ + // mock 数据 + MbrUserDO userDO = randomMbrUserDO(); + userMapper.insert(userDO); + + // 随机昵称 + String newNickName = randomString(); + + // 调用接口修改昵称 + mbrUserService.updateNickname(userDO.getId(),newNickName); + // 查询新修改后的昵称 + String nickname = mbrUserService.getUser(userDO.getId()).getNickname(); + // 断言 + assertEquals(newNickName,nickname); + } + + @Test + public void testGetUserInfo_success(){ + // mock 数据 + MbrUserDO userDO = randomMbrUserDO(); + userMapper.insert(userDO); + + // 查询用户昵称与头像 + MbrUserInfoRespVO userInfo = mbrUserService.getUserInfo(userDO.getId()); + System.out.println(userInfo); + } + + @Test + public void testUpdateAvatar_success(){ + // mock 数据 + MbrUserDO dbUser = randomMbrUserDO(); + userMapper.insert(dbUser); + + // 准备参数 + Long userId = dbUser.getId(); + byte[] avatarFileBytes = randomBytes(10); + ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); + // mock 方法 + String avatar = randomString(); + when(fileCoreService.createFile(anyString(), eq(avatarFileBytes))).thenReturn(avatar); + // 调用 + String str = mbrUserService.updateAvatar(userId, avatarFile); + // 断言 + assertEquals(avatar, str); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static MbrUserDO randomMbrUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + }; + return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/yudao-user-server/src/test/resources/application-unit-test.yaml b/yudao-user-server/src/test/resources/application-unit-test.yaml new file mode 100644 index 000000000..d306a7af4 --- /dev/null +++ b/yudao-user-server/src/test/resources/application-unit-test.yaml @@ -0,0 +1,44 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + 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: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +# Resilience4j 配置项 + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 diff --git a/yudao-user-server/src/test/resources/file/erweima.jpg b/yudao-user-server/src/test/resources/file/erweima.jpg new file mode 100644 index 000000000..1447283cd Binary files /dev/null and b/yudao-user-server/src/test/resources/file/erweima.jpg differ diff --git a/yudao-user-server/src/test/resources/logback-spring.xml b/yudao-user-server/src/test/resources/logback-spring.xml new file mode 100644 index 000000000..daf756bff --- /dev/null +++ b/yudao-user-server/src/test/resources/logback-spring.xml @@ -0,0 +1,4 @@ + + + + diff --git a/yudao-user-server/src/test/resources/sql/clean.sql b/yudao-user-server/src/test/resources/sql/clean.sql new file mode 100644 index 000000000..bedf8d008 --- /dev/null +++ b/yudao-user-server/src/test/resources/sql/clean.sql @@ -0,0 +1,2 @@ +-- mbr 开头的 DB +DELETE FROM "mbr_user"; \ No newline at end of file diff --git a/yudao-user-server/src/test/resources/sql/create_tables.sql b/yudao-user-server/src/test/resources/sql/create_tables.sql new file mode 100644 index 000000000..306900101 --- /dev/null +++ b/yudao-user-server/src/test/resources/sql/create_tables.sql @@ -0,0 +1,32 @@ +-- mbr 开头的 DB +CREATE TABLE IF NOT EXISTS "mbr_user" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', + "nickname" varchar(30) NOT NULL DEFAULT '' COMMENT '用户昵称', + "avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '头像', + "status" tinyint NOT NULL COMMENT '状态', + "mobile" varchar(11) NOT NULL COMMENT '手机号', + "password" varchar(100) NOT NULL DEFAULT '' COMMENT '密码', + "register_ip" varchar(32) NOT NULL COMMENT '注册 IP', + "login_ip" varchar(50) NULL DEFAULT '' COMMENT '最后登录IP', + "login_date" datetime NULL DEFAULT NULL COMMENT '最后登录时间', + "creator" varchar(64) NULL DEFAULT '' COMMENT '创建者', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + "updater" varchar(64) NULL DEFAULT '' COMMENT '更新者', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + "deleted" bit(1) NOT NULL DEFAULT '0' COMMENT '是否删除', + PRIMARY KEY ("id") +) COMMENT '会员表'; + +-- inf 开头的 DB +CREATE TABLE IF NOT EXISTS "inf_file" ( + "id" varchar(188) NOT NULL, + "type" varchar(63) DEFAULT NULL, + "content" blob NOT 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 '文件表'; + diff --git a/更新日志.md b/更新日志.md index 206599b25..6d5ea6f95 100644 --- a/更新日志.md +++ b/更新日志.md @@ -3,16 +3,20 @@ * 邮件 * 钉钉、飞书等通知 -## [v1.2.0] 待定 +## [v1.3.0] 待定 * 工作流 -## [v1.1.1] 待定 +## [v1.2.0] 进行中 + +* 新增用户前台的昵称、头像的修改 + +TODO * 支付 * 用户前台的社交登陆 -## [v1.1.0] 进行中 +## [v1.1.0] 2021.10.25 * 新增管理后台的企业微信、钉钉等社交登录 * 新增用户前台(例如说,用户使用的小程序)的后端项目 `yudao-user-server`