最近一个党建项目(某房管局,其实项目又分党建、人事、OA三个子系统,2019年底就已经开发完成党建、人事系统,疫情原因而且公司又在武汉所有现在还在开发)中开发了一个批量初始化数据的功能。
功能需求简述一下:
根据excel数据批量生成用户、用户角色关联、党员、党支委班子、单位员工、干部六张表记录,同时将导入失败记录的原因返回。
下面就是功能开发过程啦:
1.使用Map作为临时缓冲对象,先查询已有数据以备后面大量的数据校验。
2.循环进行数据校验并将符合的数据存入List中保存以及入库
3.手动开启事务并提交或者回滚,保证每一条excel生成的六条表记录操作处于同一个事务。
Map临时缓冲对象
private Map<String,AuthRoleDto> partyRoleMap;
private Map<String,AuthRoleDto> personnelRoleMap;
private Map<String,AuthRoleDto> oaMap;
private Map<String,AuthUserDtoSimple> userMap;
private Map<String,PartyOrgmanageOrgDtoSimple> orgMap;
private Map<String,PersonnelUnitDtoSimple> unitMap;
private Map<String,Integer> sexMap;
private Map<String,Integer> booleanMap;
private Map<String,Boolean> booleanMap2;
private Map<String,Integer> nationMap;
private String LEADER = "领导";
private String STAFF = "员工";
private Map<String,Integer> dutyTypeMap;
private Map<String,Integer> eduBackMap;
private Map<String,Integer> degressMap;
部分Map临时缓冲对象数据获取
public Map<String,AuthRoleDto> roleMap(Integer type){
List<AuthRoleDto> roles = getRoleByType(type);
Map<String,AuthRoleDto> roleMap = new ConcurrentHashMap<>();
roles.forEach(role -> {
roleMap.put(role.getName(),role);
});
return roleMap;
}
public Map<String,AuthUserDtoSimple> userMap(){
AuthUserParam param = new AuthUserParam();
List<AuthUserDtoSimple> users = authUserMapper.queryDtoSimple(param);
Map<String,AuthUserDtoSimple> userMap = new ConcurrentHashMap<>();
users.forEach(user -> {
userMap.put(user.getPhone(),user);
});
return userMap;
}
非数据库数据初始化
@PostConstruct
public void init(){
sexMap = new ConcurrentHashMap<>();
sexMap.put("男",1);
sexMap.put("女",2);
nationMap = new ConcurrentHashMap<>();
nationMap.put("汉族",1);
nationMap.put("蒙古族",2);
,,,,,,
nationMap.put("珞巴族",55);
nationMap.put("基诺族",56);
eduBackMap = new ConcurrentHashMap<>();
eduBackMap.put("未设置",0);
eduBackMap.put("小学",1);
,,,
}
数据对象,用户校验通过的数据储存,后面根据每一条入库数据需要直接取数据
/**
* 初始化用户数据
*/
@Data
public class AuthExcelModel {
// 党建角色
private Integer partyRoleId;
// OA角色
private Integer oaRoleId;
// 人事角色
private Integer personnelRoleId;
,,,,,,
// 直系亲属
private String kinsfolk;
// 亲属联系方式
private String kinsfolkLink;
}
失败记录对象
@Data
@ApiModel(value = "excel初始化数据失败对象")
public class AuthExcelResult {
@ApiModelProperty(value = "姓名")
private String name;
@ApiModelProperty(value = "电话")
private String phone;
@ApiModelProperty(value = "失败原因")
private String msg;
}
下面就是部分的数据校验了,因为excel表一共有38列数据,所有这快的校验代码非常多,就不赘述了
// 电话号码
Cell cell = row.getCell(7);
if (cell != null){
cell.setCellType(CellType.STRING);
String phone = cell.getStringCellValue();
model.setPhone(phone);
result.setPhone(phone);
if(ExcelUtil.checkFail(!RegexUtil.checkPhone(phone),result,resultList,"第"+currentRowNum+"行号码格式不正确")){
continue;
}else{
AuthUserDtoSimple userDtoSimple = userMap.get(phone);
if (ExcelUtil.checkFail(userDtoSimple != null,result,resultList,"第"+currentRowNum+"行手机账号已存在")){
continue;
}
}
}else{
result.setMsg("第"+currentRowNum+"行号码不允许为空");
resultList.add(result);
continue;
}
最后的入库操作
modelList.forEach(model -> {
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
try {
/*
用户数据
*/
AuthUser user = new AuthUser();
// 初始密码
String salt = CharUtil.generateString(6);
user.setSalt(salt);
user.setPassword(CodecUtil.generateEncryptPassword("123456",salt,true));
// 职位
user.setPosition(model.getPosition());
user.setCreateTime(new Date());
user.setDeleteFlag(DeleteFlagEnum.NotDeleted.getCode());
add(user);
/*
用户-三个子系统角色关联数据
*/
List<AuthUserRole> userRoles = new ArrayList<>();
if (model.getPartyRoleId() != null){
AuthUserRole partyRole = new AuthUserRole();
partyRole.setUserId(user.getId());
partyRole.setRoleId(model.getPartyRoleId());
userRoles.add(partyRole);
}
if (userRoles.size() > 0){
authService.batchAddUserRole(userRoles);
}
// 事务提交
dataSourceTransactionManager.commit(transactionStatus);
}catch (Exception e){
// 当前这条数据添加失败,事务回滚
dataSourceTransactionManager.rollback(transactionStatus);
AuthExcelResult result = new AuthExcelResult();
result.setPhone(model.getPhone());
result.setName(model.getName());
result.setMsg("存入数据库异常");
resultList.add(result);
}
});
下面是导入失败的结果展示
成功的数据就正常入库了。
这个功能的注意事项就是:
1.excel导入对Cell设置下Type防止Number类型与String类型混淆,如果有时间的是直接只用POI中的getDateCellValue()方法
2.创建临时缓冲对象避免多次查询数据库进行校验
3.手动事务提交保证每一条excel数据处于同一个事务
4.做好导入失败记录、原因的保存,有问题不可怕,重要的是找出问题在哪。