mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
1、新增 组织贴皮分类名称创建接口、获取组织贴皮分类名称列表接口、导入模板excel分类名称栏自动填入组织分类名称列表能力、导入校验组织分类名称能力;2、完善贴皮管理单元测试;
This commit is contained in:
+6
@@ -7,6 +7,8 @@ import com.cf.imes.framework.common.exception.ErrorCode;
|
||||
* 生产执行服务错误码枚举 使用 1-003-000-000 段
|
||||
*/
|
||||
public class ErrorCodeConstants {
|
||||
private ErrorCodeConstants() {
|
||||
}
|
||||
|
||||
// ========== 生产单开料排单
|
||||
public static final ErrorCode PLAN_NOT_EXISTS = new ErrorCode(1_003_107_000, "生产单开料排单不存在");
|
||||
@@ -177,4 +179,8 @@ public class ErrorCodeConstants {
|
||||
public static final ErrorCode VENEER_IMPORT_DIGITAL_TYPE_ERROR = new ErrorCode(1_003_009_004, "veneer.import.digital.type.error");
|
||||
public static final ErrorCode VENEER_IMPORT_POSITIVE_NUMBER_ERROR = new ErrorCode(1_003_009_005, "veneer.import.positive.number.error");
|
||||
public static final ErrorCode VENEER_IMPORT_NUMBER_LENGTH_ERROR = new ErrorCode(1_003_009_006, "veneer.import.number.length.error");
|
||||
public static final ErrorCode VENEER_IMPORT_TEMPLATE_DOWNLOAD_ERROR = new ErrorCode(1_003_009_007, "veneer.import.template.download.error");
|
||||
public static final ErrorCode VENEER_IMPORT_ORG_CLASSIFICATION_NAME_NOT_EXIST = new ErrorCode(1_003_009_008, "veneer.import.org.classification.name.not.exist");
|
||||
public static final ErrorCode VENEER_ORG_CLASSIFICATION_NAME_EXIST = new ErrorCode(1_003_009_009, "veneer.org.classification.name.exist");
|
||||
public static final ErrorCode VENEER_ORG_CLASSIFICATION_NAME_EMPTY = new ErrorCode(1_003_009_010, "veneer.org.classification.name.empty");
|
||||
}
|
||||
|
||||
+15
-5
@@ -6,7 +6,8 @@ import com.cf.imes.framework.common.pojo.PageParam;
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.excel.core.util.ExcelUtils;
|
||||
import com.cf.imes.framework.operatelog.core.annotations.OperateLog;
|
||||
import com.cf.imes.module.executor.constants.file.TemplateFilePathConstants;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDefectSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerImportExcelVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPageReqVO;
|
||||
@@ -14,13 +15,11 @@ import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerSaveReqVO;
|
||||
import com.cf.imes.module.executor.service.veneer.VeneerExcelListener;
|
||||
import com.cf.imes.module.executor.service.veneer.VeneerService;
|
||||
import com.cf.imes.module.executor.util.file.FileHelperUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -77,8 +76,7 @@ public class VeneerController {
|
||||
@Operation(summary = "下载贴皮导入模版")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void getVeneerImportTemplate(HttpServletResponse response) {
|
||||
String veneerImportTemplatePath = TemplateFilePathConstants.getVeneerImportTemplatePath(LocaleContextHolder.getLocale().getLanguage());
|
||||
FileHelperUtil.getFirstFile(veneerImportTemplatePath, response);
|
||||
veneerService.importTemplateDownload(response);
|
||||
}
|
||||
|
||||
@PostMapping("/import")
|
||||
@@ -128,4 +126,16 @@ public class VeneerController {
|
||||
veneerService.saveDefect(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/classificationName")
|
||||
@Operation(summary = "创建分类名称")
|
||||
public CommonResult<Long> createClassificationName(@Valid @RequestBody VeneerClassificationNameSaveReqVO saveReqVO) {
|
||||
return success(veneerService.addClassificationName(saveReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/org/classificationName")
|
||||
@Operation(summary = "获取分类名称列表")
|
||||
public CommonResult<List<VeneerClassificationNameRespVO>> getOrgVeneerClassificationNameList() {
|
||||
return success(veneerService.getOrgVeneerClassificationNameList());
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.cf.imes.module.executor.controller.admin.veneer.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2026/1/22 17:21
|
||||
*/
|
||||
@Schema(description = "生产管理 - 贴皮分类名称列表 Response VO")
|
||||
@Data
|
||||
public class VeneerClassificationNameRespVO {
|
||||
@Schema(description = "分类名称id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "分类名称")
|
||||
private String name;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.cf.imes.module.executor.controller.admin.veneer.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2026/1/23 10:56
|
||||
*/
|
||||
@Data
|
||||
public class VeneerClassificationNameSaveReqVO {
|
||||
@Schema(description = "分类名称")
|
||||
@NotNull(message = "{veneer.classification.name.save.name.not.null}")
|
||||
@Length(max = 64, message = "{veneer.classification.name.save.name.length.max}")
|
||||
private String name;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.cf.imes.module.executor.dal.dataobject.veneer;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 贴皮 veneers_classification_name_{N} DO
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2026/1/22 17:07
|
||||
*/
|
||||
@TableName("veneers_classification_name")
|
||||
@KeySequence("veneers_classification_name_n_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class VeneerClassificationNameDO extends BaseDO {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
private Long organId;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.cf.imes.module.executor.dal.mysql.veneer;
|
||||
|
||||
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerClassificationNameDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 贴皮分类管理 Mapper
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2026/1/22 17:12
|
||||
*/
|
||||
@Mapper
|
||||
public interface VeneerClassificationNameMapper extends BaseMapperX<VeneerClassificationNameDO> {
|
||||
}
|
||||
+40
-30
@@ -10,6 +10,7 @@ import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
|
||||
import com.alibaba.excel.util.ListUtils;
|
||||
import com.cf.imes.framework.common.exception.ServiceException;
|
||||
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerImportExcelVO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
|
||||
import com.cf.imes.module.executor.enums.veneer.VeneerStatusEnum;
|
||||
@@ -19,10 +20,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_DIGITAL_TYPE_ERROR;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_LENGTH_ERROR;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_NUMBER_LENGTH_ERROR;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_ORG_CLASSIFICATION_NAME_NOT_EXIST;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_POSITIVE_NUMBER_ERROR;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_REQUIRED_LACK;
|
||||
|
||||
@@ -33,7 +37,7 @@ import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT
|
||||
* @since 2026/1/5 18:18
|
||||
*/
|
||||
@Slf4j
|
||||
public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportExcelVO> {
|
||||
public class VeneerExcelListener extends AnalysisEventListener<VeneerImportExcelVO> {
|
||||
/**
|
||||
* 每500条操作入库一次
|
||||
*/
|
||||
@@ -48,6 +52,8 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
|
||||
private Map<Integer, String> headMap;
|
||||
|
||||
private Set<String> orgClassificationNameSet;
|
||||
|
||||
private Long organId;
|
||||
|
||||
public VeneerExcelListener(VeneerService veneerService) {
|
||||
@@ -55,6 +61,10 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
// 查询机构下所有的贴皮编号
|
||||
orgVeneerNoMap = veneerService.getOrgVeneerNo();
|
||||
organId = SecurityFrameworkUtils.getUserOrganId();
|
||||
List<VeneerClassificationNameRespVO> orgVeneerClassificationNameList = veneerService.getOrgVeneerClassificationNameList();
|
||||
if (CollUtil.isNotEmpty(orgVeneerClassificationNameList)) {
|
||||
orgClassificationNameSet = orgVeneerClassificationNameList.stream().map(VeneerClassificationNameRespVO::getName).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,22 +84,10 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
throw new ServiceException(VENEER_IMPORT_REQUIRED_LACK, rowIndex);
|
||||
}
|
||||
|
||||
// 校验贴皮是新增还是更新
|
||||
String veneerNo = data.getVeneerNo();
|
||||
Long existId = orgVeneerNoMap.get(veneerNo);
|
||||
if (ObjectUtil.isNotNull(existId)) {
|
||||
data.setId(existId);
|
||||
// 累计更新列表
|
||||
cachedUpdateDataList.add(data);
|
||||
|
||||
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
|
||||
if (cachedUpdateDataList.size() >= BATCH_COUNT) {
|
||||
updateData();
|
||||
// 存储完成清理 list
|
||||
cachedUpdateDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 校验分类名称组织内是否存在
|
||||
validClassificationName(data.getClassificationName(), rowIndex);
|
||||
|
||||
// 校验属性长度
|
||||
validFieldLength(headMap.get(0), veneerNo, 32, rowIndex);
|
||||
@@ -108,6 +106,22 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
validPositiveFloatNumberSize(headMap.get(9), data.getThickness(), Double.class, 5, 3, rowIndex);
|
||||
validPositiveNumber(headMap.get(13), data.getNum(), rowIndex);
|
||||
|
||||
// 校验贴皮是新增还是更新
|
||||
Long existId = orgVeneerNoMap.get(veneerNo);
|
||||
if (ObjectUtil.isNotNull(existId)) {
|
||||
data.setId(existId);
|
||||
// 累计更新列表
|
||||
cachedUpdateDataList.add(data);
|
||||
|
||||
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
|
||||
if (cachedUpdateDataList.size() >= BATCH_COUNT) {
|
||||
updateData();
|
||||
// 存储完成清理 list
|
||||
cachedUpdateDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 累计新增列表
|
||||
cachedInsertDataList.add(data);
|
||||
|
||||
@@ -119,11 +133,6 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extra(CellExtra extra, AnalysisContext context) {
|
||||
super.extra(extra, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
|
||||
@@ -132,11 +141,6 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
log.debug("所有数据解析完成!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext(AnalysisContext context) {
|
||||
return super.hasNext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
|
||||
this.headMap = headMap;
|
||||
@@ -172,6 +176,16 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
log.debug("excel导入贴皮数据保存成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验组织内分类名称是否存在
|
||||
* @param classificationName
|
||||
*/
|
||||
private void validClassificationName(String classificationName, int rowIndex) {
|
||||
if (!orgClassificationNameSet.contains(classificationName)) {
|
||||
throw new ServiceException(VENEER_IMPORT_ORG_CLASSIFICATION_NAME_NOT_EXIST, rowIndex, classificationName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验长度
|
||||
*
|
||||
@@ -240,11 +254,7 @@ public class VeneerExcelListener<T> extends AnalysisEventListener<VeneerImportEx
|
||||
try {
|
||||
double number = Double.parseDouble(numberStr);
|
||||
// 进行正负判断
|
||||
if (number > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return number > 0;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.cf.imes.module.executor.service.veneer;
|
||||
|
||||
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||
import org.apache.poi.ss.usermodel.DataValidation;
|
||||
import org.apache.poi.ss.usermodel.DataValidationConstraint;
|
||||
import org.apache.poi.ss.usermodel.DataValidationHelper;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
|
||||
/**
|
||||
* 贴皮excel模版分类名称填充处理器
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2026/1/22 18:50
|
||||
*/
|
||||
public class VeneerExcelTemplateClassificationNameWriteHandler implements SheetWriteHandler {
|
||||
private final int columnIndex; // 0-based,C 列 = 2
|
||||
private final String[] options;
|
||||
private final int firstRow;
|
||||
private final int lastRow;
|
||||
|
||||
public VeneerExcelTemplateClassificationNameWriteHandler(int columnIndex,
|
||||
String[] options,
|
||||
int firstRow,
|
||||
int lastRow) {
|
||||
this.columnIndex = columnIndex;
|
||||
this.options = options;
|
||||
this.firstRow = firstRow;
|
||||
this.lastRow = lastRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSheetCreate(WriteWorkbookHolder workbookHolder,
|
||||
WriteSheetHolder sheetHolder) {
|
||||
|
||||
Sheet sheet = sheetHolder.getSheet();
|
||||
|
||||
DataValidationHelper helper = sheet.getDataValidationHelper();
|
||||
DataValidationConstraint constraint =
|
||||
helper.createExplicitListConstraint(options);
|
||||
|
||||
CellRangeAddressList addressList =
|
||||
new CellRangeAddressList(firstRow, lastRow, columnIndex, columnIndex);
|
||||
|
||||
DataValidation validation =
|
||||
helper.createValidation(constraint, addressList);
|
||||
|
||||
validation.setShowErrorBox(true);
|
||||
validation.setSuppressDropDownArrow(true);
|
||||
|
||||
sheet.addValidationData(validation);
|
||||
}
|
||||
}
|
||||
+25
@@ -1,11 +1,14 @@
|
||||
package com.cf.imes.module.executor.service.veneer;
|
||||
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDefectSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPageReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerSaveReqVO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -52,6 +55,13 @@ public interface VeneerService {
|
||||
*/
|
||||
Long uploadPic(MultipartFile file) throws IOException;
|
||||
|
||||
/**
|
||||
* 贴皮导入模版下载
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void importTemplateDownload(HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 分页查询贴皮
|
||||
*
|
||||
@@ -96,4 +106,19 @@ public interface VeneerService {
|
||||
* @return
|
||||
*/
|
||||
void saveDefect(VeneerDefectSaveReqVO defectSaveReqVO);
|
||||
|
||||
/**
|
||||
* 新增分类名称
|
||||
*
|
||||
* @param saveReqVO 名称
|
||||
* @return
|
||||
*/
|
||||
Long addClassificationName(VeneerClassificationNameSaveReqVO saveReqVO);
|
||||
|
||||
/**
|
||||
* 获取组织分类名称列表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<VeneerClassificationNameRespVO> getOrgVeneerClassificationNameList();
|
||||
}
|
||||
|
||||
+81
@@ -1,8 +1,11 @@
|
||||
package com.cf.imes.module.executor.service.veneer;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.cf.imes.framework.common.exception.ServiceException;
|
||||
@@ -11,23 +14,33 @@ import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.cf.imes.module.executor.constants.file.TemplateFilePathConstants;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDefectSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPageReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerSaveReqVO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerClassificationNameDO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerBatchMapper;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerClassificationNameMapper;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerMapper;
|
||||
import com.cf.imes.module.executor.util.file.FileHelperUtil;
|
||||
import com.cf.imes.module.infra.api.file.FileApi;
|
||||
import com.cf.imes.module.system.api.organ.OrganApi;
|
||||
import com.cf.imes.module.system.api.organ.dto.OrganizationDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -35,8 +48,11 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.hutool.core.date.DatePattern.PURE_DATETIME_PATTERN;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_TEMPLATE_DOWNLOAD_ERROR;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NOT_EXIST;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NO_EXIST;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_ORG_CLASSIFICATION_NAME_EMPTY;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_ORG_CLASSIFICATION_NAME_EXIST;
|
||||
|
||||
/**
|
||||
* 贴皮管理ServiceImpl 实现类
|
||||
@@ -58,6 +74,9 @@ public class VeneerServiceImpl implements VeneerService {
|
||||
@Resource
|
||||
private VeneerBatchMapper veneerBatchMapper;
|
||||
|
||||
@Resource
|
||||
private VeneerClassificationNameMapper veneerClassificationNameMapper;
|
||||
|
||||
@Override
|
||||
public Long create(VeneerSaveReqVO reqVO) {
|
||||
// 1、校验贴皮编号
|
||||
@@ -120,6 +139,39 @@ public class VeneerServiceImpl implements VeneerService {
|
||||
return fileApi.createFileAndReturnId(file.getBytes(), String.format("%s-veneer-pic-file-%s.%s", organizationDTO.getName(), LocalDateTimeUtil.format(LocalDateTime.now(), PURE_DATETIME_PATTERN), getFileExtension(file.getOriginalFilename())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importTemplateDownload(HttpServletResponse response) {
|
||||
try {
|
||||
// 根据语种获取模版的路径
|
||||
String veneerImportTemplatePath = TemplateFilePathConstants.getVeneerImportTemplatePath(LocaleContextHolder.getLocale().getLanguage());
|
||||
|
||||
// 获取文件
|
||||
File templateFile = FileHelperUtil.getFirstFile(veneerImportTemplatePath);
|
||||
|
||||
// 获取组织分类名称列表
|
||||
List<VeneerClassificationNameRespVO> orgVeneerClassificationNameList = getOrgVeneerClassificationNameList();
|
||||
if (CollUtil.isEmpty(orgVeneerClassificationNameList)) {
|
||||
throw new ServiceException(VENEER_ORG_CLASSIFICATION_NAME_EMPTY);
|
||||
}
|
||||
|
||||
String[] options = orgVeneerClassificationNameList.stream().map(VeneerClassificationNameRespVO::getName).toArray(String[]::new);
|
||||
|
||||
// 从第2行开始, 到200行写入数据源
|
||||
EasyExcelFactory.write(response.getOutputStream())
|
||||
.withTemplate(FileUtil.getInputStream(templateFile))
|
||||
.registerWriteHandler(new VeneerExcelTemplateClassificationNameWriteHandler(
|
||||
2,
|
||||
options,
|
||||
1,
|
||||
200
|
||||
))
|
||||
.sheet(0)
|
||||
.doWrite(Collections.emptyList());
|
||||
} catch (IOException ie) {
|
||||
throw new ServiceException(VENEER_IMPORT_TEMPLATE_DOWNLOAD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<VeneerRespVO> getPage(VeneerPageReqVO pageReqVO) {
|
||||
PageResult<VeneerDO> veneerDOPageResult = veneerMapper.selectPage(pageReqVO);
|
||||
@@ -217,4 +269,33 @@ public class VeneerServiceImpl implements VeneerService {
|
||||
.map(ext -> ext.toLowerCase(Locale.ROOT))
|
||||
.orElse(".jpg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long addClassificationName(VeneerClassificationNameSaveReqVO saveReqVO) {
|
||||
String classificationName = saveReqVO.getName();
|
||||
// 校验组织下分类名称唯一
|
||||
validOrgClassificationName(classificationName);
|
||||
|
||||
VeneerClassificationNameDO veneerClassificationNameDO = new VeneerClassificationNameDO();
|
||||
veneerClassificationNameDO.setName(classificationName);
|
||||
veneerClassificationNameMapper.insert(veneerClassificationNameDO);
|
||||
return veneerClassificationNameDO.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验组织下分类名称唯一
|
||||
*
|
||||
* @param classificationName
|
||||
*/
|
||||
private void validOrgClassificationName(String classificationName) {
|
||||
if (veneerClassificationNameMapper.selectCount(new LambdaQueryWrapper<VeneerClassificationNameDO>()
|
||||
.eq(VeneerClassificationNameDO::getName, classificationName)) > 0) {
|
||||
throw new ServiceException(VENEER_ORG_CLASSIFICATION_NAME_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VeneerClassificationNameRespVO> getOrgVeneerClassificationNameList() {
|
||||
return BeanUtil.copyToList(veneerClassificationNameMapper.selectList(), VeneerClassificationNameRespVO.class);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-25
@@ -32,7 +32,6 @@ public class FileHelperUtil {
|
||||
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
|
||||
byte[] buffer = new byte[fis.available()];
|
||||
fis.read(buffer);
|
||||
fis.close();
|
||||
|
||||
response.reset();
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
@@ -67,12 +66,11 @@ public class FileHelperUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载目录下第一个文件
|
||||
* 获取目录下第一个文件
|
||||
*
|
||||
* @param dirPath
|
||||
* @param response
|
||||
*/
|
||||
public static void getFirstFile(String dirPath, HttpServletResponse response) {
|
||||
public static File getFirstFile(String dirPath) {
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new ServiceException(FILE_NOT_EXISTS);
|
||||
@@ -83,26 +81,6 @@ public class FileHelperUtil {
|
||||
throw new ServiceException(FILE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
File file = files[0];
|
||||
// 获取文件名
|
||||
String filename = file.getName();
|
||||
// 将文件写入输入流
|
||||
try (FileInputStream fis = new FileInputStream(file);
|
||||
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
|
||||
byte[] buffer = new byte[fis.available()];
|
||||
fis.read(buffer);
|
||||
fis.close();
|
||||
|
||||
response.reset();
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, CharsetUtil.UTF_8));
|
||||
response.addHeader("Content-Length", "" + file.length());
|
||||
|
||||
response.setContentType("application/octet-stream");
|
||||
outputStream.write(buffer);
|
||||
outputStream.flush();
|
||||
} catch (IOException ex) {
|
||||
throw new ServiceException(FILE_NOT_EXISTS);
|
||||
}
|
||||
return files[0];
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -15,4 +15,6 @@ veneer.save.veneerNo.not.null=贴皮编号不能为空
|
||||
veneer.save.width.not.null=宽度不能为空
|
||||
veneer.save.veneerName.not.null=贴皮名称不能为空
|
||||
veneer.save.veneerName.length.max=贴皮名称不能超过64个字符
|
||||
veneer.defect.save.id.not.null=贴皮ID不能为空
|
||||
veneer.defect.save.id.not.null=贴皮ID不能为空
|
||||
veneer.classification.name.save.name.not.null=分类名称不能为空
|
||||
veneer.classification.name.save.name.length.max=分类名称长度不能超过64
|
||||
+4
-2
@@ -14,5 +14,7 @@ veneer.save.veneerNo.length.max=貼皮編號不能超過32個字元
|
||||
veneer.save.veneerNo.not.null=貼皮編號不能為空
|
||||
veneer.save.width.not.null=寬度不能為空
|
||||
veneer.save.veneerName.not.null=貼皮名稱不能為空
|
||||
veneer.save.veneerName.length.max=貼皮名稱不能超过64个字符
|
||||
veneer.defect.save.id.not.null=貼皮ID不能為空
|
||||
veneer.save.veneerName.length.max=貼皮名稱不能超过64个字元
|
||||
veneer.defect.save.id.not.null=貼皮ID不能為空
|
||||
veneer.classification.name.save.name.not.null=分類名稱不能為空
|
||||
veneer.classification.name.save.name.length.max=分類名稱不能超過64個字元
|
||||
+3
-1
@@ -15,4 +15,6 @@ veneer.save.veneerNo.not.null=veener no cannot be empty
|
||||
veneer.save.width.not.null=width cannot be empty
|
||||
veneer.save.veneerName.not.null=veneer name cannot be empty
|
||||
veneer.save.veneerName.length.max=veneer name length cannot exceed 64 characters
|
||||
veneer.defect.save.id.not.null=veneer id cannot be empty
|
||||
veneer.defect.save.id.not.null=veneer id cannot be empty
|
||||
veneer.classification.name.save.name.not.null=classification name cannot be empty
|
||||
veneer.classification.name.save.name.length.max=classification name length cannot exceed 64 characters
|
||||
+5
-1
@@ -20,4 +20,8 @@ veneer.import.required.lack=第{0}行存在带*必填项为空,请检查文件
|
||||
veneer.import.length.error=第{0}行{1}长度不能超过{2}个字符,请检查文件
|
||||
veneer.import.digital.type.error=第{0}行{1}只能输入数字,请检查文件
|
||||
veneer.import.positive.number.error=第{0}行{1}必须大于0,请检查文件
|
||||
veneer.import.number.length.error=第{0}行{1}长度不能超过整数{2}位、小数{3}位,请检查文件
|
||||
veneer.import.number.length.error=第{0}行{1}长度不能超过整数{2}位、小数{3}位,请检查文件
|
||||
veneer.org.classification.name.exist=组织下分类名称已存在,请检查
|
||||
veneer.org.classification.name.empty=组织下分类名称不存在,请前往 [新增] 窗口维护分类名称
|
||||
veneer.import.template.download.error=导入模版下载失败
|
||||
veneer.import.org.classification.name.not.exist=第{0}行分类名称{1}不存在,请前往 [新增] 窗口维护分类名称
|
||||
+5
-1
@@ -20,4 +20,8 @@ veneer.import.required.lack=第{0}行存在帶*必填項為空,請檢查檔案
|
||||
veneer.import.length.error=第{0}行{1}長度不能超過{2}個字元,請檢查檔案
|
||||
veneer.import.digital.type.error=第{0}行{1}只能輸入數位,請檢查檔案
|
||||
veneer.import.positive.number.error=第{0}行{1}必須大於0,請檢查檔案
|
||||
veneer.import.number.length.error=第{0}行{1}長度不能超過整數{2}位、小數{3}位,請檢查檔案
|
||||
veneer.import.number.length.error=第{0}行{1}長度不能超過整數{2}位、小數{3}位,請檢查檔案
|
||||
veneer.org.classification.name.exist=組織下分類名稱已存在,請檢查
|
||||
veneer.org.classification.name.empty=組織下分類名稱不存在,請前往 [新增] 視窗維護分類名稱
|
||||
veneer.import.template.download.error=導入模版下載失敗
|
||||
veneer.import.org.classification.name.not.exist=第{0}行分類名稱{1}不存在,請前往[新增]視窗維護分類名稱
|
||||
+5
-1
@@ -20,4 +20,8 @@ veneer.import.required.lack=The required field is empty in line {0}, please chec
|
||||
veneer.import.length.error=The length of the field cannot exceed {0} characters in line {1}, please check the file
|
||||
veneer.import.digital.type.error=The field can only be filled in with numbers in line {0}, please check the file
|
||||
veneer.import.positive.number.error=The field must be greater than 0 in line {0}, please check the file
|
||||
veneer.import.number.length.error=The length of the field cannot exceed integer {0} digits and decimal {1} digits in line {2}, please check the file
|
||||
veneer.import.number.length.error=The length of the field cannot exceed integer {0} digits and decimal {1} digits in line {2}, please check the file
|
||||
veneer.org.classification.name.exist=The classification name already exists under the organization, please check
|
||||
veneer.org.classification.name.empty=The classification name does not exist under the organization, Please go to the [Add] window to maintain the classification name
|
||||
veneer.import.template.download.error=Import template download failed
|
||||
veneer.import.org.classification.name.not.exist=The classification name {1} does not exist in line {0}, please go to the [Add] window to maintain the classification name
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+95
-19
@@ -1,17 +1,23 @@
|
||||
package com.cf.imes.module.executor.controller.admin.veneer;
|
||||
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
|
||||
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.security.test.WithMockLoginUser;
|
||||
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDefectSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerImportExcelVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerSaveReqVO;
|
||||
import com.cf.imes.module.executor.enums.veneer.VeneerProductLevelEnum;
|
||||
import com.cf.imes.module.executor.service.veneer.VeneerExcelListener;
|
||||
import com.cf.imes.module.executor.service.veneer.VeneerService;
|
||||
import com.cf.imes.module.executor.util.file.FileHelperUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedConstruction;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -22,11 +28,14 @@ import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
@@ -161,32 +170,55 @@ class VeneerControllerTest extends BaseWebUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockLoginUser
|
||||
void importExcel_success() throws Exception {
|
||||
MockMultipartFile file = new MockMultipartFile(
|
||||
"file", "test.xlsx",
|
||||
"application/vnd.ms-excel",
|
||||
new byte[]{1, 2, 3}
|
||||
"file",
|
||||
"veneer.xlsx",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"dummy excel content".getBytes()
|
||||
);
|
||||
|
||||
mockMvc.perform(multipart("/executor/veneer/import").file(file))
|
||||
.andExpect(status().isOk());
|
||||
try (
|
||||
MockedStatic<EasyExcelFactory> excelMock =
|
||||
Mockito.mockStatic(EasyExcelFactory.class);
|
||||
MockedConstruction<VeneerExcelListener> listenerMock =
|
||||
Mockito.mockConstruction(VeneerExcelListener.class)
|
||||
) {
|
||||
|
||||
ExcelReaderBuilder readerBuilder = Mockito.mock(ExcelReaderBuilder.class);
|
||||
ExcelReaderSheetBuilder sheetBuilder = Mockito.mock(ExcelReaderSheetBuilder.class);
|
||||
|
||||
excelMock.when(() ->
|
||||
EasyExcelFactory.read(
|
||||
any(InputStream.class),
|
||||
eq(VeneerImportExcelVO.class),
|
||||
any()
|
||||
)
|
||||
).thenReturn(readerBuilder);
|
||||
|
||||
Mockito.when(readerBuilder.headRowNumber(anyInt()))
|
||||
.thenReturn(readerBuilder);
|
||||
Mockito.when(readerBuilder.sheet())
|
||||
.thenReturn(sheetBuilder);
|
||||
Mockito.doNothing().when(sheetBuilder).doRead();
|
||||
|
||||
mockMvc.perform(
|
||||
multipart("/executor/veneer/import").file(file)
|
||||
).andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getVeneerImportTemplate_success() throws Exception {
|
||||
try (MockedStatic<FileHelperUtil> mocked =
|
||||
Mockito.mockStatic(FileHelperUtil.class)) {
|
||||
Mockito.doNothing()
|
||||
.when(veneerService)
|
||||
.importTemplateDownload(any(HttpServletResponse.class));
|
||||
|
||||
mocked.when(() ->
|
||||
FileHelperUtil.getFirstFile(
|
||||
anyString(),
|
||||
any(HttpServletResponse.class))
|
||||
).thenAnswer(invocation -> null);
|
||||
mockMvc.perform(get("/executor/veneer/import/template"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mockMvc.perform(get("/executor/veneer/import/template"))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
Mockito.verify(veneerService)
|
||||
.importTemplateDownload(any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -203,4 +235,48 @@ class VeneerControllerTest extends BaseWebUnitTest {
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createClassificationName_success() throws Exception {
|
||||
|
||||
VeneerClassificationNameSaveReqVO reqVO = new VeneerClassificationNameSaveReqVO();
|
||||
reqVO.setName("测试分类");
|
||||
|
||||
Mockito.when(veneerService.addClassificationName(any()))
|
||||
.thenReturn(1L);
|
||||
|
||||
mockMvc.perform(
|
||||
post("/executor/veneer/classificationName")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(reqVO))
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data").value(1L));
|
||||
|
||||
Mockito.verify(veneerService)
|
||||
.addClassificationName(any(VeneerClassificationNameSaveReqVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOrgVeneerClassificationNameList_success() throws Exception {
|
||||
|
||||
VeneerClassificationNameRespVO respVO = new VeneerClassificationNameRespVO();
|
||||
respVO.setId(1L);
|
||||
respVO.setName("测试分类");
|
||||
|
||||
Mockito.when(veneerService.getOrgVeneerClassificationNameList())
|
||||
.thenReturn(List.of(respVO));
|
||||
|
||||
mockMvc.perform(
|
||||
get("/executor/veneer/org/classificationName")
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data[0].id").value(1L))
|
||||
.andExpect(jsonPath("$.data[0].name").value("测试分类"));
|
||||
|
||||
Mockito.verify(veneerService)
|
||||
.getOrgVeneerClassificationNameList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+232
@@ -1,6 +1,10 @@
|
||||
package com.cf.imes.module.executor.service.veneer;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
|
||||
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
@@ -11,25 +15,41 @@ import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
import com.cf.imes.framework.security.test.WithMockLoginUser;
|
||||
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import com.cf.imes.module.executor.common.WithMockLoginUserExtension;
|
||||
import com.cf.imes.module.executor.constants.file.TemplateFilePathConstants;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerClassificationNameSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDefectSaveReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPageReqVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerRespVO;
|
||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerSaveReqVO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerClassificationNameDO;
|
||||
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerBatchMapper;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerClassificationNameMapper;
|
||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerMapper;
|
||||
import com.cf.imes.module.executor.enums.veneer.VeneerProductLevelEnum;
|
||||
import com.cf.imes.module.executor.util.file.FileHelperUtil;
|
||||
import com.cf.imes.module.infra.api.file.FileApi;
|
||||
import com.cf.imes.module.system.api.organ.OrganApi;
|
||||
import com.cf.imes.module.system.api.organ.dto.OrganizationDTO;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -39,6 +59,7 @@ import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceExce
|
||||
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NOT_EXIST;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NO_EXIST;
|
||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_ORG_CLASSIFICATION_NAME_EXIST;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -46,10 +67,13 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -78,6 +102,12 @@ class VeneerServiceImplTest extends BaseMockitoUnitTest {
|
||||
@Mock
|
||||
private VeneerBatchMapper veneerBatchMapper;
|
||||
|
||||
@Mock
|
||||
private VeneerClassificationNameMapper veneerClassificationNameMapper;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse response;
|
||||
|
||||
@BeforeAll
|
||||
static void init(){
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), VeneerDO.class);
|
||||
@@ -481,6 +511,208 @@ class VeneerServiceImplTest extends BaseMockitoUnitTest {
|
||||
verify(veneerMapper, never()).update(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addClassificationName_success() {
|
||||
|
||||
// given
|
||||
VeneerClassificationNameSaveReqVO reqVO =
|
||||
new VeneerClassificationNameSaveReqVO();
|
||||
reqVO.setName("测试分类");
|
||||
|
||||
// 唯一校验通过
|
||||
Mockito.when(veneerClassificationNameMapper.selectCount(any()))
|
||||
.thenReturn(0L);
|
||||
|
||||
// mock insert 时给 id
|
||||
Mockito.doAnswer(invocation -> {
|
||||
VeneerClassificationNameDO entity = invocation.getArgument(0);
|
||||
entity.setId(1L);
|
||||
return 1;
|
||||
}).when(veneerClassificationNameMapper).insert(any(VeneerClassificationNameDO.class));
|
||||
|
||||
// when
|
||||
Long id = veneerService.addClassificationName(reqVO);
|
||||
|
||||
// then
|
||||
assertEquals(1L, id);
|
||||
|
||||
Mockito.verify(veneerClassificationNameMapper)
|
||||
.selectCount(any());
|
||||
Mockito.verify(veneerClassificationNameMapper)
|
||||
.insert(any(VeneerClassificationNameDO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addClassificationName_exist_throwException() {
|
||||
|
||||
VeneerClassificationNameSaveReqVO reqVO =
|
||||
new VeneerClassificationNameSaveReqVO();
|
||||
reqVO.setName("重复分类");
|
||||
|
||||
// 已存在
|
||||
Mockito.when(veneerClassificationNameMapper.selectCount(any()))
|
||||
.thenReturn(1L);
|
||||
|
||||
assertServiceException(() -> veneerService.addClassificationName(reqVO),
|
||||
VENEER_ORG_CLASSIFICATION_NAME_EXIST);
|
||||
|
||||
// insert 一定不会被调用
|
||||
Mockito.verify(veneerClassificationNameMapper, Mockito.never())
|
||||
.insert(any(VeneerClassificationNameDO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOrgVeneerClassificationNameList_success() {
|
||||
|
||||
VeneerClassificationNameDO entity = new VeneerClassificationNameDO();
|
||||
entity.setId(1L);
|
||||
entity.setName("分类A");
|
||||
|
||||
Mockito.when(veneerClassificationNameMapper.selectList())
|
||||
.thenReturn(List.of(entity));
|
||||
|
||||
List<VeneerClassificationNameRespVO> result =
|
||||
veneerService.getOrgVeneerClassificationNameList();
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("分类A", result.get(0).getName());
|
||||
|
||||
Mockito.verify(veneerClassificationNameMapper)
|
||||
.selectList();
|
||||
}
|
||||
|
||||
@Test
|
||||
void importTemplateDownload_success() throws IOException {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
|
||||
try (
|
||||
MockedStatic<TemplateFilePathConstants> pathMock =
|
||||
Mockito.mockStatic(TemplateFilePathConstants.class);
|
||||
MockedStatic<FileUtil> fileUtilMock =
|
||||
Mockito.mockStatic(FileUtil.class);
|
||||
MockedStatic<FileHelperUtil> fileMock =
|
||||
Mockito.mockStatic(FileHelperUtil.class);
|
||||
MockedStatic<EasyExcelFactory> excelMock =
|
||||
Mockito.mockStatic(EasyExcelFactory.class)
|
||||
) {
|
||||
|
||||
VeneerClassificationNameDO veneerClassificationNameDO = new VeneerClassificationNameDO();
|
||||
veneerClassificationNameDO.setName("分类名称");
|
||||
when(veneerClassificationNameMapper.selectList()).thenReturn(List.of(veneerClassificationNameDO));
|
||||
|
||||
pathMock.when(() ->
|
||||
TemplateFilePathConstants.getVeneerImportTemplatePath(any())
|
||||
).thenReturn("/mock/path");
|
||||
|
||||
fileMock.when(() ->
|
||||
FileHelperUtil.getFirstFile(anyString())
|
||||
).thenReturn(mockFile);
|
||||
|
||||
// ⭐ 关键 1:mock 模板流(不碰文件)
|
||||
fileUtilMock.when(() -> FileUtil.getInputStream(any(File.class)))
|
||||
.thenReturn(new BufferedInputStream(new ByteArrayInputStream(new byte[]{1})));
|
||||
|
||||
// mock response OutputStream
|
||||
ServletOutputStream outputStream = Mockito.mock(ServletOutputStream.class);
|
||||
Mockito.when(response.getOutputStream())
|
||||
.thenReturn(outputStream);
|
||||
|
||||
// mock EasyExcel 写链
|
||||
ExcelWriterBuilder writerBuilder = Mockito.mock(ExcelWriterBuilder.class);
|
||||
ExcelWriterSheetBuilder sheetBuilder = Mockito.mock(ExcelWriterSheetBuilder.class);
|
||||
|
||||
excelMock.when(() -> EasyExcelFactory.write(any(OutputStream.class)))
|
||||
.thenReturn(writerBuilder);
|
||||
|
||||
when(writerBuilder.withTemplate(
|
||||
any(InputStream.class)))
|
||||
.thenReturn(writerBuilder);
|
||||
|
||||
when(writerBuilder.registerWriteHandler(any()))
|
||||
.thenReturn(writerBuilder);
|
||||
|
||||
when(writerBuilder.sheet(anyInt()))
|
||||
.thenReturn(sheetBuilder);
|
||||
doNothing().when(sheetBuilder).doWrite(anyList());
|
||||
|
||||
// 执行
|
||||
assertDoesNotThrow(() ->
|
||||
veneerService.importTemplateDownload(response));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void importTemplateDownload_fail_when_org_classification_name_list_is_empty() {
|
||||
// 1️⃣ mock 模板路径 & 文件
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
|
||||
try (
|
||||
MockedStatic<TemplateFilePathConstants> pathMock =
|
||||
Mockito.mockStatic(TemplateFilePathConstants.class);
|
||||
MockedStatic<FileHelperUtil> fileMock =
|
||||
Mockito.mockStatic(FileHelperUtil.class)
|
||||
) {
|
||||
|
||||
pathMock.when(() ->
|
||||
TemplateFilePathConstants.getVeneerImportTemplatePath(any())
|
||||
).thenReturn("/mock/path");
|
||||
|
||||
fileMock.when(() ->
|
||||
FileHelperUtil.getFirstFile(anyString())
|
||||
).thenReturn(mockFile);
|
||||
|
||||
// 2️⃣ mock 分类名称列表为空
|
||||
Mockito.when(veneerClassificationNameMapper.selectList())
|
||||
.thenReturn(new ArrayList<>());
|
||||
|
||||
// 3️⃣ 验证抛出异常
|
||||
assertServiceException(() -> veneerService.importTemplateDownload(response),
|
||||
com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_ORG_CLASSIFICATION_NAME_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importTemplateDownload_fail_when_io_exception_occurs() throws Exception {
|
||||
// 1️⃣ mock 模板路径 & 文件
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
|
||||
try (
|
||||
MockedStatic<TemplateFilePathConstants> pathMock =
|
||||
Mockito.mockStatic(TemplateFilePathConstants.class);
|
||||
MockedStatic<FileHelperUtil> fileMock =
|
||||
Mockito.mockStatic(FileHelperUtil.class);
|
||||
MockedStatic<EasyExcelFactory> excelMock =
|
||||
Mockito.mockStatic(EasyExcelFactory.class)
|
||||
) {
|
||||
|
||||
pathMock.when(() ->
|
||||
TemplateFilePathConstants.getVeneerImportTemplatePath(any())
|
||||
).thenReturn("/mock/path");
|
||||
|
||||
fileMock.when(() ->
|
||||
FileHelperUtil.getFirstFile(anyString())
|
||||
).thenReturn(mockFile);
|
||||
|
||||
// 2️⃣ mock 分类名称列表
|
||||
VeneerClassificationNameDO entity = new VeneerClassificationNameDO();
|
||||
entity.setName("分类A");
|
||||
|
||||
Mockito.when(veneerClassificationNameMapper.selectList())
|
||||
.thenReturn(List.of(entity));
|
||||
|
||||
// 3️⃣ mock response OutputStream 并抛出IOException
|
||||
Mockito.when(response.getOutputStream())
|
||||
.thenThrow(new java.io.IOException("IO Error"));
|
||||
|
||||
// 4️⃣ 验证抛出异常
|
||||
assertServiceException(() -> veneerService.importTemplateDownload(response),
|
||||
com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_IMPORT_TEMPLATE_DOWNLOAD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
void getFileExtension_whenEmpty() {
|
||||
assertEquals(".jpg", veneerService.getFileExtension("file."));
|
||||
|
||||
Reference in New Issue
Block a user