feat(系统设置): 用户导入功能开发
This commit is contained in:
parent
dc804ba46f
commit
599270efcb
|
@ -3,6 +3,7 @@ package io.metersphere.sdk.dto;
|
|||
import com.google.common.base.CaseFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
@ -21,6 +22,7 @@ public class BasePageRequest {
|
|||
private int current;
|
||||
|
||||
@Min(value = 5, message = "每页显示条数必须不小于5")
|
||||
@Max(value = 100, message = "每页显示条数不能大于100")
|
||||
@Schema(title = "每页显示条数")
|
||||
private int pageSize;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
excel.parse.error=Excel parse error
|
||||
role.not.global.system=Role is not global system role
|
||||
role.not.contains.member=Role not contains member
|
||||
user.not.login=User not login
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
excel.parse.error=Excel解析失败
|
||||
role.not.global.system=角色不是全局系统角色
|
||||
role.not.contains.member=角色不包含系统成员角色
|
||||
user.not.login=未获取到登录用户
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
excel.parse.error=Excel解析失敗
|
||||
role.not.global.system=角色不是為全局系統角色
|
||||
role.not.contains.member=角色不包含系統成員角色
|
||||
user.not.login=未獲取到登錄用戶
|
||||
|
|
|
@ -14,9 +14,10 @@ import io.metersphere.sdk.util.PageUtils;
|
|||
import io.metersphere.sdk.util.Pager;
|
||||
import io.metersphere.sdk.util.SessionUtils;
|
||||
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.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.service.GlobalUserRoleService;
|
||||
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.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -53,7 +55,7 @@ public class UserController {
|
|||
@PostMapping("/add")
|
||||
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD)
|
||||
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")
|
||||
|
@ -77,4 +79,10 @@ public class UserController {
|
|||
public UserEditEnableRequest updateUserEnable(@Validated @RequestBody UserEditEnableRequest request) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.system.dto;
|
||||
package io.metersphere.system.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
@ -11,6 +11,6 @@ public class UserEditEnableRequest {
|
|||
@Schema(title = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "{user.not.empty}")
|
||||
List<String> userIdList;
|
||||
|
||||
|
||||
boolean enable;
|
||||
}
|
|
@ -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.Updated;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package io.metersphere.system.service;
|
||||
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import io.metersphere.sdk.dto.BasePageRequest;
|
||||
import io.metersphere.sdk.dto.ExcelParseDTO;
|
||||
import io.metersphere.sdk.dto.UserDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
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.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.CodingUtil;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.OperationLog;
|
||||
import io.metersphere.system.domain.User;
|
||||
import io.metersphere.system.domain.UserExample;
|
||||
import io.metersphere.system.dto.UserBatchCreateDTO;
|
||||
import io.metersphere.system.dto.UserCreateInfo;
|
||||
import io.metersphere.system.dto.UserEditEnableRequest;
|
||||
import io.metersphere.system.dto.UserEditRequest;
|
||||
import io.metersphere.system.dto.excel.UserExcel;
|
||||
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.mapper.UserMapper;
|
||||
import io.metersphere.system.utils.UserImportEventListener;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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());
|
||||
globalUserRoleService.checkRoleIsGlobalAndHaveMember(userCreateDTO.getUserRoleIdList(), true);
|
||||
return this.saveUserAndRole(userCreateDTO, source, operator);
|
||||
}
|
||||
|
||||
private UserBatchCreateDTO saveUserAndRole(UserBatchCreateDTO userCreateDTO, String source, String operator) {
|
||||
long createTime = System.currentTimeMillis();
|
||||
List<User> saveUserList = new ArrayList<>();
|
||||
//添加用户
|
||||
|
@ -110,9 +124,7 @@ public class UserService {
|
|||
userMapper.insertSelective(user);
|
||||
saveUserList.add(user);
|
||||
}
|
||||
|
||||
userRoleRelationService.batchSave(userCreateDTO.getUserRoleIdList(), saveUserList);
|
||||
|
||||
//写入操作日志
|
||||
operationLogService.batchAdd(this.getBatchAddLogs(saveUserList));
|
||||
return userCreateDTO;
|
||||
|
@ -184,4 +196,66 @@ public class UserService {
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ import com.jayway.jsonpath.JsonPath;
|
|||
import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.dto.UserCreateInfo;
|
||||
import io.metersphere.system.dto.UserEditEnableRequest;
|
||||
import io.metersphere.system.dto.UserRoleOption;
|
||||
import io.metersphere.system.dto.request.UserEditEnableRequest;
|
||||
import io.metersphere.system.utils.UserTestUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
|
|
@ -4,12 +4,20 @@ import base.BaseTest;
|
|||
import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.controller.handler.ResultHolder;
|
||||
import io.metersphere.sdk.dto.BasePageRequest;
|
||||
import io.metersphere.sdk.dto.ExcelParseDTO;
|
||||
import io.metersphere.sdk.dto.UserDTO;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
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.service.UserService;
|
||||
import io.metersphere.system.utils.UserTestUtils;
|
||||
import io.metersphere.utils.JsonUtils;
|
||||
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.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
@ -44,6 +53,9 @@ public class UserControllerTests extends BaseTest {
|
|||
@Resource
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
//失败请求返回编码
|
||||
private static final ResultMatcher BAD_REQUEST_MATCHER = status().isBadRequest();
|
||||
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
||||
|
@ -103,6 +115,17 @@ public class UserControllerTests extends BaseTest {
|
|||
.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 {
|
||||
return mockMvc.perform(MockMvcRequestBuilders.get(url)
|
||||
.header(SessionConstants.HEADER_TOKEN, sessionId)
|
||||
|
@ -355,6 +378,10 @@ public class UserControllerTests extends BaseTest {
|
|||
BasePageRequest basePageRequest = new BasePageRequest();
|
||||
basePageRequest.setPageSize(5);
|
||||
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
|
||||
basePageRequest = new BasePageRequest();
|
||||
basePageRequest.setCurrent(1);
|
||||
|
@ -489,4 +516,83 @@ public class UserControllerTests extends BaseTest {
|
|||
}});
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,17 @@ import io.metersphere.sdk.util.JSON;
|
|||
import io.metersphere.system.domain.UserRole;
|
||||
import io.metersphere.system.dto.UserBatchCreateDTO;
|
||||
import io.metersphere.system.dto.UserCreateInfo;
|
||||
import io.metersphere.system.dto.UserEditRequest;
|
||||
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 org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
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_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_IMPORT = "/system/user/import";
|
||||
|
||||
|
||||
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) {
|
||||
Assertions.assertNotNull(editRequest);
|
||||
Assertions.assertNotNull(selectUserDTO);
|
||||
|
@ -96,4 +124,17 @@ public class UserTestUtils {
|
|||
editRequest.getUserRoleIdList().containsAll(selectUserSystemRoleId)
|
||||
&& 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 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue