Merge branch 'master' into feature/mall_product

pull/4/head
tangqian 2023-05-30 15:44:45 +08:00
commit af701360b7
6 changed files with 220 additions and 20 deletions

View File

@ -12,9 +12,11 @@ import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
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 javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -83,4 +85,11 @@ public class DeptController {
return success(DeptConvert.INSTANCE.convert(deptService.getDept(id))); return success(DeptConvert.INSTANCE.convert(deptService.getDept(id)));
} }
@Operation(summary = "批量组织架构导入")
@PostMapping(value = "/batch/import", name = "批量组织架构导入")
public CommonResult<Boolean> batchImport(@RequestParam("file") MultipartFile file) throws IOException {
deptService.batchImport(file);
return success(true);
}
} }

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* @Title:BatchImportVO
* @Description: TODO
* @author: tangqian
* @date: 2023/5/30 11:11
* @version: V1.0.0
*/
@Data
public class BatchImportVO implements Serializable {
private static final long serialVersionUID = -1235962811424997478L;
@ExcelProperty("名称")
private String depName;
@ExcelProperty("层级")
private String hierarchy;
@ExcelProperty("关系")
private String relation;
@ExcelProperty("标识(唯一)")
private String characteristic;
}

View File

@ -71,4 +71,6 @@ public class DeptDO extends TenantBaseDO {
*/ */
private String parentOrganizationName; private String parentOrganizationName;
private String characteristic;
} }

View File

@ -7,7 +7,9 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateRe
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -115,4 +117,5 @@ public interface DeptService {
*/ */
void validateDeptList(Collection<Long> ids); void validateDeptList(Collection<Long> ids);
void batchImport(MultipartFile file) throws IOException;
} }

View File

@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.system.service.dept;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.BatchImportVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
@ -13,6 +15,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum; import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum;
import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer; import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer;
import cn.iocoder.yudao.module.system.util.TransactionalService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -20,12 +27,18 @@ import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@ -43,7 +56,7 @@ public class DeptServiceImpl implements DeptService {
/** /**
* *
* key {@link DeptDO#getId()} * key {@link DeptDO#getId()}
* * <p>
* volatile * volatile
*/ */
@Getter @Getter
@ -52,7 +65,7 @@ public class DeptServiceImpl implements DeptService {
* *
* key {@link DeptDO#getParentId()} * key {@link DeptDO#getParentId()}
* value: * value:
* * <p>
* volatile * volatile
*/ */
@Getter @Getter
@ -63,6 +76,8 @@ public class DeptServiceImpl implements DeptService {
@Resource @Resource
private DeptProducer deptProducer; private DeptProducer deptProducer;
@Resource
private TransactionalService transactionalService;
/** /**
* {@link #parentDeptCache} {@link #deptCache} * {@link #parentDeptCache} {@link #deptCache}
@ -98,13 +113,13 @@ public class DeptServiceImpl implements DeptService {
// 插入部门 // 插入部门
DeptDO dept = DeptConvert.INSTANCE.convert(reqVO); DeptDO dept = DeptConvert.INSTANCE.convert(reqVO);
dept.setId(IdWorker.getId()); dept.setId(IdWorker.getId());
if(DeptIdEnum.ROOT.getId().equals(dept.getParentId())){ if (DeptIdEnum.ROOT.getId().equals(dept.getParentId())) {
dept.setParentOrganizationIds(dept.getId()+""); dept.setParentOrganizationIds(dept.getId() + "");
dept.setParentOrganizationName(dept.getName()); dept.setParentOrganizationName(dept.getName());
}else{ } else {
DeptDO parent = deptMapper.selectById(reqVO.getParentId()); DeptDO parent = deptMapper.selectById(reqVO.getParentId());
dept.setParentOrganizationIds(parent.getParentOrganizationIds()+","+dept.getId()); dept.setParentOrganizationIds(parent.getParentOrganizationIds() + "," + dept.getId());
dept.setParentOrganizationName(parent.getParentOrganizationName()+">"+dept.getName()); dept.setParentOrganizationName(parent.getParentOrganizationName() + ">" + dept.getName());
} }
deptMapper.insert(dept); deptMapper.insert(dept);
@ -122,13 +137,13 @@ public class DeptServiceImpl implements DeptService {
validateForCreateOrUpdate(reqVO.getId(), reqVO.getParentId(), reqVO.getName()); validateForCreateOrUpdate(reqVO.getId(), reqVO.getParentId(), reqVO.getName());
// 更新部门 // 更新部门
DeptDO updateObj = DeptConvert.INSTANCE.convert(reqVO); DeptDO updateObj = DeptConvert.INSTANCE.convert(reqVO);
if(DeptIdEnum.ROOT.getId().equals(updateObj.getParentId())){ if (DeptIdEnum.ROOT.getId().equals(updateObj.getParentId())) {
updateObj.setParentOrganizationIds(updateObj.getId()+""); updateObj.setParentOrganizationIds(updateObj.getId() + "");
updateObj.setParentOrganizationName(updateObj.getName()); updateObj.setParentOrganizationName(updateObj.getName());
}else{ } else {
DeptDO parent = deptMapper.selectById(reqVO.getParentId()); DeptDO parent = deptMapper.selectById(reqVO.getParentId());
updateObj.setParentOrganizationIds(parent.getParentOrganizationIds()+","+updateObj.getId()); updateObj.setParentOrganizationIds(parent.getParentOrganizationIds() + "," + updateObj.getId());
updateObj.setParentOrganizationName(parent.getParentOrganizationName()+">"+updateObj.getName()); updateObj.setParentOrganizationName(parent.getParentOrganizationName() + ">" + updateObj.getName());
} }
deptMapper.updateById(updateObj); deptMapper.updateById(updateObj);
// 发送刷新消息 // 发送刷新消息
@ -167,8 +182,8 @@ public class DeptServiceImpl implements DeptService {
*/ */
@Override @Override
public DeptDO findParentDept(Long tenantId) { public DeptDO findParentDept(Long tenantId) {
List<DeptDO> deptDOs = deptMapper.selectList(Wrappers.lambdaQuery(DeptDO.class).eq(DeptDO::getParentId,DeptIdEnum.ROOT.getId()).eq(DeptDO::getTenantId,tenantId)); List<DeptDO> deptDOs = deptMapper.selectList(Wrappers.lambdaQuery(DeptDO.class).eq(DeptDO::getParentId, DeptIdEnum.ROOT.getId()).eq(DeptDO::getTenantId, tenantId));
if(deptDOs!=null && deptDOs.size() > 0){ if (deptDOs != null && deptDOs.size() > 0) {
return deptDOs.get(0); return deptDOs.get(0);
} }
return null; return null;
@ -305,4 +320,99 @@ public class DeptServiceImpl implements DeptService {
}); });
} }
private static List<DeptDO> deptDOS2 = new ArrayList<>();
private static List<DeptDO> deptDOS3 = new ArrayList<>();
private static List<DeptDO> deptDOS4 = new ArrayList<>();
@Override
public void batchImport(MultipartFile file) throws IOException {
List<BatchImportVO> list = ExcelUtils.read(file, BatchImportVO.class);
try {
EasyExcel.read(file.getInputStream(), BatchImportVO.class, new AnalysisEventListener<BatchImportVO>() {
private final List<BatchImportVO> deptList = new ArrayList<>(10000);
@Override
public void invoke(BatchImportVO o, AnalysisContext analysisContext) {
deptList.add(o);
if (deptList.size() % 15 == 0) {
batchInsert();
deptList.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
if (CollectionUtils.isNotEmpty(deptList)) {
batchInsert();
}
}
private void batchInsert() {
Map<String, List<BatchImportVO>> collect = deptList.stream().collect(Collectors.groupingBy(BatchImportVO::getHierarchy));
List<BatchImportVO> batchImportVOS1 = collect.get("1");
List<BatchImportVO> batchImportVOS2 = collect.get("2");
List<BatchImportVO> batchImportVOS3 = collect.get("3");
List<BatchImportVO> batchImportVOS4 = collect.get("4");
transactionalService.run(() -> {
// 装入层级1
BatchImportVO batchImportVO1 = batchImportVOS1.get(0);
DeptDO deptDO1 = new DeptDO();
deptDO1.setParentId(0L);
deptDO1.setName(batchImportVO1.getDepName());
deptDO1.setParentOrganizationName(batchImportVO1.getDepName());
deptDO1.setCharacteristic(batchImportVO1.getCharacteristic());
deptMapper.insert(deptDO1);
deptDO1.setParentOrganizationIds(deptDO1.getId().toString());
deptMapper.updateById(deptDO1);
// 装入层级2
for (BatchImportVO batchImportVO : batchImportVOS2) {
DeptDO deptDO2 = new DeptDO();
deptDO2.setName(batchImportVO.getDepName());
deptDO2.setParentId(deptDO1.getId());
deptDO2.setParentOrganizationName(deptDO1.getName() + "," + batchImportVO.getDepName());
deptDO2.setCharacteristic(batchImportVO.getCharacteristic());
deptMapper.insert(deptDO2);
deptDO2.setParentOrganizationIds(deptDO1.getId() + "," + deptDO2.getId());
deptMapper.updateById(deptDO2);
deptDOS2.add(deptDO2);
}
// 装入层级3
for (BatchImportVO batchImportVO : batchImportVOS3) {
DeptDO deptDO3 = new DeptDO();
deptDO3.setName(batchImportVO.getDepName());
List<DeptDO> collect1 = deptDOS2.stream().filter(e -> e.getCharacteristic().equals(batchImportVO.getCharacteristic())).collect(Collectors.toList());
DeptDO deptDO = collect1.get(0);
deptDO3.setParentId(deptDO.getId());
deptDO3.setParentOrganizationName(deptDO.getName() + "," + batchImportVO.getDepName());
deptMapper.insert(deptDO3);
deptDO3.setParentOrganizationIds(deptDO.getId() + "," + deptDO3.getId());
deptMapper.updateById(deptDO3);
deptDOS3.add(deptDO3);
}
// 装入层级4
for (BatchImportVO batchImportVO : batchImportVOS4) {
DeptDO deptDO4 = new DeptDO();
deptDO4.setName(batchImportVO.getDepName());
List<DeptDO> collect1 = deptDOS3.stream().filter(e -> e.getCharacteristic().equals(batchImportVO.getCharacteristic())).collect(Collectors.toList());
DeptDO deptDO = collect1.get(0);
deptDO4.setParentId(deptDO.getId());
deptDO4.setParentOrganizationName(deptDO.getName() + "," + batchImportVO.getDepName());
deptMapper.insert(deptDO4);
deptDO4.setParentOrganizationIds(deptDO.getId() + "," + deptDO4.getId());
deptMapper.updateById(deptDO4);
deptDOS3.add(deptDO4);
}
});
}
}).sheet().headRowNumber(1).doRead();
} catch (IOException e) {
log.error("导入组织架构失败!", e);
} finally {
deptDOS2.removeAll(deptDOS2);
deptDOS3.removeAll(deptDOS3);
deptDOS4.removeAll(deptDOS4);
}
}
} }

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.system.util;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import java.util.concurrent.Callable;
/**
* <p>Title: TransactionalService</p>
* <p>Description: </p>
* <p>Package: com.cmx.activity.service</p>
* <p>Date: 20230112 21:10</p>
*
* @author wanglong [atva725@qq.com]
* @version V1.0.0
*/
@Component
@RequiredArgsConstructor
public class TransactionalService {
private final TransactionDefinition transactionDefinition;
private final PlatformTransactionManager platformTransactionManager;
public void run(Runnable runnable) {
final TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
try {
runnable.run();
platformTransactionManager.commit(transaction);
} catch (Exception e) {
platformTransactionManager.rollback(transaction);
throw new RuntimeException(e);
}
}
public <R> R run(Callable<R> callable) {
R rev;
final TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
try {
rev = callable.call();
platformTransactionManager.commit(transaction);
} catch (Exception e) {
platformTransactionManager.rollback(transaction);
throw new RuntimeException(e);
}
return rev;
}
}