[update]user server模块新增测试,修改部分接口规范问题

This commit is contained in:
宋天 2021-10-24 22:33:32 +08:00
parent 5193de7c56
commit f4a5a139b5
21 changed files with 279 additions and 45 deletions

View File

@ -2,7 +2,7 @@ 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.coreservice.modules.infra.controller.file.vo.InfFilePageReqVO;
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.framework.common.pojo.CommonResult;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo;
package cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;

View File

@ -0,0 +1,24 @@
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 org.apache.ibatis.annotations.Mapper;
/**
* admin 文件操作 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface InfFileMapper extends BaseMapperX<InfFileDO> {
default PageResult<InfFileDO> selectPage(InfFilePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<InfFileDO>()
.likeIfPresent("id", reqVO.getId())
.likeIfPresent("type", reqVO.getType())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("create_time"));
}
}

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.infra.service.file;
import cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo.InfFilePageReqVO;
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;

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.infra.service.file.impl;
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.coreservice.modules.infra.controller.file.vo.InfFilePageReqVO;
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.dal.mysql.file.InfFileCoreMapper;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;
@ -17,8 +17,9 @@ import javax.annotation.Resource;
*/
@Service
public class InfFileServiceImpl implements InfFileService {
@Resource
private InfFileCoreMapper fileCoreMapper;
private InfFileMapper fileMapper;
@Resource
private InfFileCoreService fileCoreService;
@ -40,7 +41,7 @@ public class InfFileServiceImpl implements InfFileService {
@Override
public PageResult<InfFileDO> getFilePage(InfFilePageReqVO pageReqVO) {
return fileCoreMapper.selectPage(pageReqVO);
return fileMapper.selectPage(pageReqVO);
}
}

View File

@ -2,7 +2,7 @@ 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.controller.file.vo.InfFilePageReqVO;
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.dal.mysql.file.InfFileCoreMapper;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.impl.InfFileCoreServiceImpl;

View File

@ -1,10 +1,7 @@
package cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file;
import cn.iocoder.yudao.coreservice.modules.infra.controller.file.vo.InfFilePageReqVO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@ -12,13 +9,4 @@ public interface InfFileCoreMapper extends BaseMapperX<InfFileDO> {
default Integer selectCountById(String id) {
return selectCount("id", id);
}
default PageResult<InfFileDO> selectPage(InfFilePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<InfFileDO>()
.likeIfPresent("id", reqVO.getId())
.likeIfPresent("type", reqVO.getType())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("create_time"));
}
}

View File

@ -14,7 +14,7 @@ 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, "文件不存在");
}

View File

@ -3,9 +3,9 @@ GET {{userServerUrl}}/system/user/profile/get
Authorization: Bearer test245
### 请求 /system/user/profile/revise-nickname 接口 成功
PUT http://localhost:28080/api/system/user/profile/update-nickname?nickName=yunai222
PUT {{userServerUrl}}/system/user/profile/update-nickname?nickName=yunai222
Authorization: Bearer test245
### 请求 /system/user/profile/get-user-info 接口 成功
GET http://localhost:28080/api/system/user/profile/get-user-info?id=245
GET {{userServerUrl}}/system/user/profile/get-user-info?id=245
Authorization: Bearer test245

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.userserver.modules.member.controller.user;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.SysUserInfoRespVO;
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;
@ -30,13 +30,6 @@ public class SysUserProfileController {
@Resource
private MbrUserService userService;
@GetMapping("/get")
@ApiOperation("获得登录用户信息")
@PreAuthenticated
public CommonResult<Boolean> profile() {
return null;
}
@PutMapping("/update-nickname")
@ApiOperation("修改用户昵称")
@PreAuthenticated
@ -45,21 +38,21 @@ public class SysUserProfileController {
return success(true);
}
@PutMapping("/revise-avatar")
@PutMapping("/update-avatar")
@ApiOperation("修改用户头像")
@PreAuthenticated
public CommonResult<String> reviseAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException {
public CommonResult<String> updateAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException {
if (file.isEmpty()) {
throw ServiceExceptionUtil.exception(FILE_IS_EMPTY);
}
String avatar = userService.reviseAvatar(getLoginUserId(), file.getInputStream());
String avatar = userService.updateAvatar(getLoginUserId(), file.getInputStream());
return success(avatar);
}
@GetMapping("/get-user-info")
@ApiOperation("获取用户头像与昵称")
@PreAuthenticated
public CommonResult<SysUserInfoRespVO> getUserInfo() {
public CommonResult<MbrUserInfoRespVO> getUserInfo() {
return success(userService.getUserInfo(getLoginUserId()));
}
}

View File

@ -10,7 +10,7 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysUserInfoRespVO {
public class MbrUserInfoRespVO {
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String nickName;

View File

@ -9,9 +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, "文件为空");
}

View File

@ -1,7 +1,7 @@
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.SysUserInfoRespVO;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import java.io.InputStream;
@ -60,13 +60,13 @@ public interface MbrUserService {
* @param inputStream 头像文件
* @return 头像url
*/
String reviseAvatar(Long userId, InputStream inputStream);
String updateAvatar(Long userId, InputStream inputStream);
/**
* 根据用户id获取用户头像与昵称
* @param userId 用户id
* @return 用户响应实体类
*/
SysUserInfoRespVO getUserInfo(Long userId);
MbrUserInfoRespVO getUserInfo(Long userId);
}

View File

@ -4,7 +4,7 @@ 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.SysUserInfoRespVO;
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;
@ -93,7 +93,7 @@ public class MbrUserServiceImpl implements MbrUserService {
}
@Override
public String reviseAvatar(Long userId, InputStream avatarFile) {
public String updateAvatar(Long userId, InputStream avatarFile) {
this.checkUserExists(userId);
// 创建文件
String avatar = fileCoreService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile));
@ -107,9 +107,9 @@ public class MbrUserServiceImpl implements MbrUserService {
}
@Override
public SysUserInfoRespVO getUserInfo(Long userId) {
public MbrUserInfoRespVO getUserInfo(Long userId) {
MbrUserDO user = this.checkUserExists(userId);
SysUserInfoRespVO userResp = new SysUserInfoRespVO();
MbrUserInfoRespVO userResp = new MbrUserInfoRespVO();
userResp.setNickName(user.getNickname());
userResp.setAvatar(user.getAvatar());
return userResp;

View File

@ -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 {
}
}

View File

@ -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<MbrUserDO>... consumers) {
Consumer<MbrUserDO> consumer = (o) -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
};
return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers));
}
}

View File

@ -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 配置项
--- #################### 监控相关配置 ####################
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,4 @@
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
</configuration>

View File

@ -0,0 +1,2 @@
-- mbr 开头的 DB
DELETE FROM "mbr_user";

View File

@ -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 '文件表';