feat(系统设置): 用户导入功能开发

This commit is contained in:
song-tianyang 2023-07-03 14:44:37 +08:00 committed by 刘瑞斌
parent dc804ba46f
commit 599270efcb
24 changed files with 452 additions and 14 deletions

View File

@ -3,6 +3,7 @@ package io.metersphere.sdk.dto;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
@ -21,6 +22,7 @@ public class BasePageRequest {
private int current; private int current;
@Min(value = 5, message = "每页显示条数必须不小于5") @Min(value = 5, message = "每页显示条数必须不小于5")
@Max(value = 100, message = "每页显示条数不能大于100")
@Schema(title = "每页显示条数") @Schema(title = "每页显示条数")
private int pageSize; private int pageSize;

View File

@ -0,0 +1,25 @@
package io.metersphere.sdk.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
@Data
public class ExcelParseDTO<T> {
private List<T> dataList = new ArrayList<>();
private TreeMap<Integer, T> errRowData = new TreeMap<>();
public void addRowData(T t) {
dataList.add(t);
}
public void addErrorRowData(Integer index, T t) {
errRowData.put(index, t);
}
public void addErrorRowDataAll(TreeMap<Integer, T> errRowData) {
this.errRowData.putAll(errRowData);
}
}

View File

@ -1,3 +1,4 @@
excel.parse.error=Excel parse error
role.not.global.system=Role is not global system role role.not.global.system=Role is not global system role
role.not.contains.member=Role not contains member role.not.contains.member=Role not contains member
user.not.login=User not login user.not.login=User not login

View File

@ -1,3 +1,4 @@
excel.parse.error=Excel解析失败
role.not.global.system=角色不是全局系统角色 role.not.global.system=角色不是全局系统角色
role.not.contains.member=角色不包含系统成员角色 role.not.contains.member=角色不包含系统成员角色
user.not.login=未获取到登录用户 user.not.login=未获取到登录用户

View File

@ -1,3 +1,4 @@
excel.parse.error=Excel解析失敗
role.not.global.system=角色不是為全局系統角色 role.not.global.system=角色不是為全局系統角色
role.not.contains.member=角色不包含系統成員角色 role.not.contains.member=角色不包含系統成員角色
user.not.login=未獲取到登錄用戶 user.not.login=未獲取到登錄用戶

View File

@ -14,9 +14,10 @@ import io.metersphere.sdk.util.PageUtils;
import io.metersphere.sdk.util.Pager; import io.metersphere.sdk.util.Pager;
import io.metersphere.sdk.util.SessionUtils; import io.metersphere.sdk.util.SessionUtils;
import io.metersphere.system.dto.UserBatchCreateDTO; import io.metersphere.system.dto.UserBatchCreateDTO;
import io.metersphere.system.dto.UserEditEnableRequest;
import io.metersphere.system.dto.UserEditRequest;
import io.metersphere.system.dto.UserRoleOption; import io.metersphere.system.dto.UserRoleOption;
import io.metersphere.system.dto.request.UserEditEnableRequest;
import io.metersphere.system.dto.request.UserEditRequest;
import io.metersphere.system.dto.response.UserImportResponse;
import io.metersphere.system.dto.response.UserTableResponse; import io.metersphere.system.dto.response.UserTableResponse;
import io.metersphere.system.service.GlobalUserRoleService; import io.metersphere.system.service.GlobalUserRoleService;
import io.metersphere.system.service.UserService; import io.metersphere.system.service.UserService;
@ -27,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@ -53,7 +55,7 @@ public class UserController {
@PostMapping("/add") @PostMapping("/add")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD) @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD)
public UserBatchCreateDTO addUser(@Validated({Created.class}) @RequestBody UserBatchCreateDTO userCreateDTO) { public UserBatchCreateDTO addUser(@Validated({Created.class}) @RequestBody UserBatchCreateDTO userCreateDTO) {
return userService.addBatch(userCreateDTO, UserSourceEnum.LOCAL.name(), SessionUtils.getUserId()); return userService.addUser(userCreateDTO, UserSourceEnum.LOCAL.name(), SessionUtils.getUserId());
} }
@PostMapping("/update") @PostMapping("/update")
@ -77,4 +79,10 @@ public class UserController {
public UserEditEnableRequest updateUserEnable(@Validated @RequestBody UserEditEnableRequest request) { public UserEditEnableRequest updateUserEnable(@Validated @RequestBody UserEditEnableRequest request) {
return userService.updateUserEnable(request, SessionUtils.getSessionId()); return userService.updateUserEnable(request, SessionUtils.getSessionId());
} }
@PostMapping(value = "/import", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_IMPORT)
public UserImportResponse importUser(@RequestPart(value = "file", required = false) MultipartFile excelFile) {
return userService.importByExcel(excelFile, UserSourceEnum.LOCAL.name(), SessionUtils.getSessionId());
}
} }

View File

@ -0,0 +1,44 @@
package io.metersphere.system.dto.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import jakarta.validation.groups.Default;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Set;
@Component
public class ExcelValidateHelper {
private static ExcelValidateHelper excelValidateHelper;
@Resource
Validator validator;
public static <T> String validateEntity(T obj) throws NoSuchFieldException {
StringBuilder result = new StringBuilder();
Set<ConstraintViolation<T>> set = excelValidateHelper.validator.validate(obj, Default.class);
if (set != null && !set.isEmpty()) {
for (ConstraintViolation<T> cv : set) {
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
//拼接错误信息包含当前出错数据的标题名字+错误信息
result.append(annotation.value()[0] + cv.getMessage()).append("; ");
}
}
return result.toString();
}
/**
* 在静态方法中调用
*/
@PostConstruct
public void initialize() {
excelValidateHelper = this;
excelValidateHelper.validator = this.validator;
}
}

View File

@ -0,0 +1,27 @@
package io.metersphere.system.dto.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class UserExcel {
@NotBlank(message = "{user.name.not_blank}")
@Size(min = 1, max = 255, message = "{user.name.length_range}")
@ExcelProperty("name*")
private String name;
@NotBlank(message = "{cannot_be_null}")
@Size(min = 1, max = 64, message = "{user.email.length_range}")
@Email(message = "{user.email.invalid}")
@ExcelProperty("email*")
private String email;
@ExcelProperty("phone")
private String phone;
@ExcelProperty("workspace")
private String workspaceName;
}

View File

@ -0,0 +1,10 @@
package io.metersphere.system.dto.excel;
import lombok.Data;
@Data
public class UserExcelRowDTO extends UserExcel {
public int dataIndex;
public String errorMessage;
public String userRoleId;
}

View File

@ -1,4 +1,4 @@
package io.metersphere.system.dto; package io.metersphere.system.dto.request;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;

View File

@ -1,5 +1,6 @@
package io.metersphere.system.dto; package io.metersphere.system.dto.request;
import io.metersphere.system.dto.UserCreateInfo;
import io.metersphere.validation.groups.Created; import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated; import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -0,0 +1,31 @@
package io.metersphere.system.dto.response;
import io.metersphere.sdk.dto.ExcelParseDTO;
import io.metersphere.system.dto.excel.UserExcelRowDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.MapUtils;
import java.util.TreeMap;
@Getter
@Setter
public class UserImportResponse {
@Schema(title = "导入数量")
private int importCount;
@Schema(title = "成功数量")
private int successCount;
@Schema(title = "报错信息")
private TreeMap<Integer, String> errorMessages = new TreeMap<>();
public void generateResponse(ExcelParseDTO<UserExcelRowDTO> excelParseDTO) {
successCount = excelParseDTO.getDataList().size();
if (MapUtils.isNotEmpty(excelParseDTO.getErrRowData())) {
excelParseDTO.getErrRowData().forEach((k, v) -> {
errorMessages.put(k, v.getErrorMessage());
});
}
importCount = errorMessages.size() + successCount;
}
}

View File

@ -1,6 +1,8 @@
package io.metersphere.system.service; package io.metersphere.system.service;
import com.alibaba.excel.EasyExcelFactory;
import io.metersphere.sdk.dto.BasePageRequest; import io.metersphere.sdk.dto.BasePageRequest;
import io.metersphere.sdk.dto.ExcelParseDTO;
import io.metersphere.sdk.dto.UserDTO; import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.log.constants.OperationLogModule; import io.metersphere.sdk.log.constants.OperationLogModule;
@ -9,22 +11,30 @@ import io.metersphere.sdk.log.service.OperationLogService;
import io.metersphere.sdk.mapper.BaseUserMapper; import io.metersphere.sdk.mapper.BaseUserMapper;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CodingUtil; import io.metersphere.sdk.util.CodingUtil;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.OperationLog; import io.metersphere.system.domain.OperationLog;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserExample; import io.metersphere.system.domain.UserExample;
import io.metersphere.system.dto.UserBatchCreateDTO; import io.metersphere.system.dto.UserBatchCreateDTO;
import io.metersphere.system.dto.UserCreateInfo; import io.metersphere.system.dto.UserCreateInfo;
import io.metersphere.system.dto.UserEditEnableRequest; import io.metersphere.system.dto.excel.UserExcel;
import io.metersphere.system.dto.UserEditRequest; import io.metersphere.system.dto.excel.UserExcelRowDTO;
import io.metersphere.system.dto.request.UserEditEnableRequest;
import io.metersphere.system.dto.request.UserEditRequest;
import io.metersphere.system.dto.response.UserImportResponse;
import io.metersphere.system.dto.response.UserTableResponse; import io.metersphere.system.dto.response.UserTableResponse;
import io.metersphere.system.mapper.UserMapper; import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.utils.UserImportEventListener;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -91,9 +101,13 @@ public class UserService {
} }
} }
public UserBatchCreateDTO addBatch(UserBatchCreateDTO userCreateDTO, String source, String operator) { public UserBatchCreateDTO addUser(UserBatchCreateDTO userCreateDTO, String source, String operator) {
this.validateUserInfo(userCreateDTO.getUserInfoList()); this.validateUserInfo(userCreateDTO.getUserInfoList());
globalUserRoleService.checkRoleIsGlobalAndHaveMember(userCreateDTO.getUserRoleIdList(), true); globalUserRoleService.checkRoleIsGlobalAndHaveMember(userCreateDTO.getUserRoleIdList(), true);
return this.saveUserAndRole(userCreateDTO, source, operator);
}
private UserBatchCreateDTO saveUserAndRole(UserBatchCreateDTO userCreateDTO, String source, String operator) {
long createTime = System.currentTimeMillis(); long createTime = System.currentTimeMillis();
List<User> saveUserList = new ArrayList<>(); List<User> saveUserList = new ArrayList<>();
//添加用户 //添加用户
@ -110,9 +124,7 @@ public class UserService {
userMapper.insertSelective(user); userMapper.insertSelective(user);
saveUserList.add(user); saveUserList.add(user);
} }
userRoleRelationService.batchSave(userCreateDTO.getUserRoleIdList(), saveUserList); userRoleRelationService.batchSave(userCreateDTO.getUserRoleIdList(), saveUserList);
//写入操作日志 //写入操作日志
operationLogService.batchAdd(this.getBatchAddLogs(saveUserList)); operationLogService.batchAdd(this.getBatchAddLogs(saveUserList));
return userCreateDTO; return userCreateDTO;
@ -184,4 +196,66 @@ public class UserService {
throw new MSException(Translator.get("user.not.exist")); throw new MSException(Translator.get("user.not.exist"));
} }
} }
public UserImportResponse importByExcel(MultipartFile excelFile, String source, String sessionId) {
UserImportResponse importResponse = new UserImportResponse();
try {
ExcelParseDTO<UserExcelRowDTO> excelParseDTO = this.getUserExcelParseDTO(excelFile);
if (CollectionUtils.isNotEmpty(excelParseDTO.getDataList())) {
this.saveUserByExcelData(excelParseDTO.getDataList(), source, sessionId);
}
importResponse.generateResponse(excelParseDTO);
} catch (Exception e) {
LogUtils.info("import user error", e);
}
return importResponse;
}
public ExcelParseDTO<UserExcelRowDTO> getUserExcelParseDTO(MultipartFile excelFile) throws Exception {
UserImportEventListener userImportEventListener = new UserImportEventListener();
EasyExcelFactory.read(excelFile.getInputStream(), UserExcel.class, userImportEventListener).sheet().doRead();
ExcelParseDTO<UserExcelRowDTO> excelParseDTO = this.validateExcelUserInfo(userImportEventListener.getExcelParseDTO());
return excelParseDTO;
}
/**
* 校验excel导入的数据是否与数据库中的数据冲突
*
* @param excelParseDTO
* @return
*/
private ExcelParseDTO<UserExcelRowDTO> validateExcelUserInfo(@Valid @NotNull ExcelParseDTO<UserExcelRowDTO> excelParseDTO) {
List<UserExcelRowDTO> prepareSaveList = excelParseDTO.getDataList();
if (CollectionUtils.isNotEmpty(prepareSaveList)) {
var userInDbMap = baseUserMapper.selectUserIdByEmailList(
prepareSaveList.stream().map(UserExcelRowDTO::getEmail).collect(Collectors.toList()))
.stream().collect(Collectors.toMap(User::getEmail, User::getId));
for (UserExcelRowDTO userExcelRow : prepareSaveList) {
//判断邮箱是否已存在数据库中
if (userInDbMap.containsKey(userExcelRow.getEmail())) {
userExcelRow.setErrorMessage(Translator.get("user.email.repeat") + ": " + userExcelRow.getEmail());
excelParseDTO.addErrorRowData(userExcelRow.getDataIndex(), userExcelRow);
}
}
excelParseDTO.getDataList().removeAll(excelParseDTO.getErrRowData().values());
}
return excelParseDTO;
}
private void saveUserByExcelData(@Valid @NotEmpty List<UserExcelRowDTO> dataList, @Valid @NotEmpty String source, @Valid @NotBlank String sessionId) {
UserBatchCreateDTO userBatchCreateDTO = new UserBatchCreateDTO();
userBatchCreateDTO.setUserRoleIdList(new ArrayList<>() {{
add("member");
}});
List<UserCreateInfo> userCreateInfoList = new ArrayList<>();
dataList.forEach(userExcelRowDTO -> {
UserCreateInfo userCreateInfo = new UserCreateInfo();
BeanUtils.copyBean(userCreateInfo, userExcelRowDTO);
userCreateInfoList.add(userCreateInfo);
});
userBatchCreateDTO.setUserInfoList(userCreateInfoList);
this.saveUserAndRole(userBatchCreateDTO, source, sessionId);
}
} }

View File

@ -0,0 +1,66 @@
package io.metersphere.system.utils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import io.metersphere.sdk.dto.ExcelParseDTO;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.excel.ExcelValidateHelper;
import io.metersphere.system.dto.excel.UserExcel;
import io.metersphere.system.dto.excel.UserExcelRowDTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
public class UserImportEventListener extends AnalysisEventListener<UserExcel> {
private ExcelParseDTO<UserExcelRowDTO> excelParseDTO;
public UserImportEventListener() {
excelParseDTO = new ExcelParseDTO<>();
}
@Override
public void invoke(UserExcel data, AnalysisContext analysisContext) {
String errMsg;
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
try {
//使用javax.validation校验excel数据
errMsg = ExcelValidateHelper.validateEntity(data);
if (StringUtils.isEmpty(errMsg)) {
errMsg = businessValidate(data);
}
} catch (NoSuchFieldException e) {
errMsg = Translator.get("excel.parse.error");
LogUtils.error(e.getMessage(), e);
}
UserExcelRowDTO userExcelRowDTO = new UserExcelRowDTO();
BeanUtils.copyBean(userExcelRowDTO, data);
userExcelRowDTO.setDataIndex(rowIndex);
if (StringUtils.isEmpty(errMsg)) {
excelParseDTO.addRowData(userExcelRowDTO);
} else {
userExcelRowDTO.setErrorMessage(errMsg);
excelParseDTO.addErrorRowData(rowIndex, userExcelRowDTO);
}
}
private String businessValidate(UserExcel rowData) {
if (CollectionUtils.isNotEmpty(excelParseDTO.getDataList())) {
for (UserExcelRowDTO userExcelRowDTO : excelParseDTO.getDataList()) {
if (StringUtils.equalsIgnoreCase(userExcelRowDTO.getEmail(), rowData.getEmail())) {
return Translator.get("user.email.repeat") + ":" + rowData.getEmail();
}
}
}
return null;
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
public ExcelParseDTO<UserExcelRowDTO> getExcelParseDTO() {
return excelParseDTO;
}
}

View File

@ -4,8 +4,8 @@ import com.jayway.jsonpath.JsonPath;
import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.dto.UserCreateInfo; import io.metersphere.system.dto.UserCreateInfo;
import io.metersphere.system.dto.UserEditEnableRequest;
import io.metersphere.system.dto.UserRoleOption; import io.metersphere.system.dto.UserRoleOption;
import io.metersphere.system.dto.request.UserEditEnableRequest;
import io.metersphere.system.utils.UserTestUtils; import io.metersphere.system.utils.UserTestUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;

View File

@ -4,12 +4,20 @@ import base.BaseTest;
import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.controller.handler.ResultHolder; import io.metersphere.sdk.controller.handler.ResultHolder;
import io.metersphere.sdk.dto.BasePageRequest; import io.metersphere.sdk.dto.BasePageRequest;
import io.metersphere.sdk.dto.ExcelParseDTO;
import io.metersphere.sdk.dto.UserDTO; import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Pager; import io.metersphere.sdk.util.Pager;
import io.metersphere.system.dto.*; import io.metersphere.system.dto.UserBatchCreateDTO;
import io.metersphere.system.dto.UserCreateInfo;
import io.metersphere.system.dto.UserRoleOption;
import io.metersphere.system.dto.excel.UserExcelRowDTO;
import io.metersphere.system.dto.request.UserEditEnableRequest;
import io.metersphere.system.dto.request.UserEditRequest;
import io.metersphere.system.dto.response.UserImportResponse;
import io.metersphere.system.dto.response.UserTableResponse; import io.metersphere.system.dto.response.UserTableResponse;
import io.metersphere.system.service.UserService;
import io.metersphere.system.utils.UserTestUtils; import io.metersphere.system.utils.UserTestUtils;
import io.metersphere.utils.JsonUtils; import io.metersphere.utils.JsonUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -19,6 +27,7 @@ import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
@ -44,6 +53,9 @@ public class UserControllerTests extends BaseTest {
@Resource @Resource
private MockMvc mockMvc; private MockMvc mockMvc;
@Resource
private UserService userService;
//失败请求返回编码 //失败请求返回编码
private static final ResultMatcher BAD_REQUEST_MATCHER = status().isBadRequest(); private static final ResultMatcher BAD_REQUEST_MATCHER = status().isBadRequest();
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError(); private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
@ -103,6 +115,17 @@ public class UserControllerTests extends BaseTest {
.andReturn(); .andReturn();
} }
private MvcResult responseFile(String url, MockMultipartFile file) throws Exception {
return mockMvc.perform(MockMvcRequestBuilders.multipart(url)
.file(file)
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
}
private MvcResult responseGet(String url) throws Exception { private MvcResult responseGet(String url) throws Exception {
return mockMvc.perform(MockMvcRequestBuilders.get(url) return mockMvc.perform(MockMvcRequestBuilders.get(url)
.header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.HEADER_TOKEN, sessionId)
@ -355,6 +378,10 @@ public class UserControllerTests extends BaseTest {
BasePageRequest basePageRequest = new BasePageRequest(); BasePageRequest basePageRequest = new BasePageRequest();
basePageRequest.setPageSize(5); basePageRequest.setPageSize(5);
this.requestPost(UserTestUtils.URL_USER_PAGE, basePageRequest, BAD_REQUEST_MATCHER); this.requestPost(UserTestUtils.URL_USER_PAGE, basePageRequest, BAD_REQUEST_MATCHER);
//pageSize超过100
basePageRequest = UserTestUtils.getDefaultPageRequest();
basePageRequest.setPageSize(250);
this.requestPost(UserTestUtils.URL_USER_PAGE, basePageRequest, BAD_REQUEST_MATCHER);
//当前页数不大于5 //当前页数不大于5
basePageRequest = new BasePageRequest(); basePageRequest = new BasePageRequest();
basePageRequest.setCurrent(1); basePageRequest.setCurrent(1);
@ -489,4 +516,83 @@ public class UserControllerTests extends BaseTest {
}}); }});
this.requestPost(UserTestUtils.URL_USER_UPDATE_ENABLE, userChangeEnableRequest, ERROR_REQUEST_MATCHER); this.requestPost(UserTestUtils.URL_USER_UPDATE_ENABLE, userChangeEnableRequest, ERROR_REQUEST_MATCHER);
} }
@Test
@Order(6)
public void testUserImportSuccess() throws Exception {
this.checkUserList();
//测试用户数据导入 每个导入文件都有10条数据不同文件出错的数据不同
int importSuccessData = 10;//应该导入成功的数据数量
int[] errorDataIndex = {};//出错数据的行数
UserImportResponse response;//导入返回值
//导入正常文件
String filePath = this.getClass().getClassLoader().getResource("file/user_import_success.xlsx").getPath();
MockMultipartFile file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
ExcelParseDTO<UserExcelRowDTO> userImportReportDTOByFile = userService.getUserExcelParseDTO(file);
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);//检查返回值
this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库
//导入空文件
filePath = this.getClass().getClassLoader().getResource("file/user_import_success_empty.xlsx").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 0;
errorDataIndex = new int[]{};
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);
//文件内没有一条合格数据
filePath = this.getClass().getClassLoader().getResource("file/user_import_error_all.xlsx").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 0;
errorDataIndex = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);
//邮箱和数据库里的重复
filePath = this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_db.xlsx").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
userImportReportDTOByFile = userService.getUserExcelParseDTO(file);
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 8;
errorDataIndex = new int[]{1, 7};
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);
this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库
//文件内邮箱重复
filePath = this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_in_file.xlsx").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
userImportReportDTOByFile = userService.getUserExcelParseDTO(file);
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 8;
errorDataIndex = new int[]{9, 10};
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);
this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库
//文件不符合规范
filePath = this.getClass().getClassLoader().getResource("file/abcde.gif").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 0;
errorDataIndex = new int[]{};
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);
//测试03版excel正常导入
filePath = this.getClass().getClassLoader().getResource("file/user_import_success_03.xls").getPath();
file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath));
userImportReportDTOByFile = userService.getUserExcelParseDTO(file);
response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class);
importSuccessData = 10;//应该导入成功的数据数量
errorDataIndex = new int[]{};//出错数据的行数
UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);//检查返回值
this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库
}
public void checkImportUserInDb(ExcelParseDTO<UserExcelRowDTO> userImportReportDTOByFile) throws Exception {
for (UserExcelRowDTO item : userImportReportDTOByFile.getDataList()) {
Assertions.assertNotNull(this.getUserByEmail(item.getEmail()));
}
}
} }

View File

@ -8,14 +8,17 @@ import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.UserRole; import io.metersphere.system.domain.UserRole;
import io.metersphere.system.dto.UserBatchCreateDTO; import io.metersphere.system.dto.UserBatchCreateDTO;
import io.metersphere.system.dto.UserCreateInfo; import io.metersphere.system.dto.UserCreateInfo;
import io.metersphere.system.dto.UserEditRequest;
import io.metersphere.system.dto.UserRoleOption; import io.metersphere.system.dto.UserRoleOption;
import io.metersphere.system.dto.request.UserEditRequest;
import io.metersphere.system.dto.response.UserImportResponse;
import io.metersphere.utils.JsonUtils; import io.metersphere.utils.JsonUtils;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -29,6 +32,7 @@ public class UserTestUtils {
public static final String URL_USER_PAGE = "/system/user/page"; public static final String URL_USER_PAGE = "/system/user/page";
public static final String URL_GET_GLOBAL_SYSTEM = "/system/user/get/global/system/role"; public static final String URL_GET_GLOBAL_SYSTEM = "/system/user/get/global/system/role";
public static final String URL_USER_UPDATE_ENABLE = "/system/user/update/enable"; public static final String URL_USER_UPDATE_ENABLE = "/system/user/update/enable";
public static final String URL_USER_IMPORT = "/system/user/import";
public static <T> T parseObjectFromMvcResult(MvcResult mvcResult, Class<T> parseClass) { public static <T> T parseObjectFromMvcResult(MvcResult mvcResult, Class<T> parseClass) {
@ -75,6 +79,30 @@ public class UserTestUtils {
}}; }};
} }
public static byte[] getFileBytes(String filePath) {
File file = new File(filePath);
byte[] buffer = new byte[0];
FileInputStream fi = null;
try {
fi = new FileInputStream(file);
buffer = new byte[(int) file.length()];
int offset = 0;
int numRead = 0;
while (offset < buffer.length
&& (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
offset += numRead;
}
} catch (Exception ignore) {
} finally {
try {
fi.close();
} catch (Exception ignore) {
}
}
return buffer;
}
public static void compareUserDTO(UserEditRequest editRequest, UserDTO selectUserDTO) { public static void compareUserDTO(UserEditRequest editRequest, UserDTO selectUserDTO) {
Assertions.assertNotNull(editRequest); Assertions.assertNotNull(editRequest);
Assertions.assertNotNull(selectUserDTO); Assertions.assertNotNull(selectUserDTO);
@ -96,4 +124,17 @@ public class UserTestUtils {
editRequest.getUserRoleIdList().containsAll(selectUserSystemRoleId) editRequest.getUserRoleIdList().containsAll(selectUserSystemRoleId)
&& selectUserSystemRoleId.containsAll(editRequest.getUserRoleIdList())); && selectUserSystemRoleId.containsAll(editRequest.getUserRoleIdList()));
} }
public static void checkImportResponse(UserImportResponse responsePost, int successCount, int[] errorDataIndex) {
//导入总数据是否一致
Assertions.assertTrue(responsePost.getImportCount() == successCount + errorDataIndex.length);
//导入成功数据是否一致
Assertions.assertTrue(responsePost.getSuccessCount() == successCount);
//报错数据数量是否一致
Assertions.assertTrue(responsePost.getErrorMessages().size() == errorDataIndex.length);
//报错数据行编码是否一致
for (int index : errorDataIndex) {
Assertions.assertTrue(responsePost.getErrorMessages().containsKey(index));
}
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB