目录
1、使用场景
我们实际工作之中,可能针对返回的数据进行分段、批量提交到数据库插入记录(如Excel导入多条记录)。因为我们后端数据库不可能一次性处理以1000条或者更多记录;于是需要针对导入的记录进行分段批量处理。最近我在对接用户中心的时候,有一个通过Excel批量导入用户的功能;但是用户中心提供的接口每次仅仅接收50条记录的处理。于是我需要针对Excel读取的大量记录进行分段分批的处理记录。保证每次提交到用户中心接口的数据是小于等于50条记录的。
2、代码实现
import java.util.ArrayList;
import java.util.List;
/**
* @Classname SegmentedBatchList
* @Description List 的分段处理
* @Date 2020/3/22 11:51
* @Created by jianxiapc
*/
public class ListSegmentedBatch {
public static void main(String[] args) {
List<Integer> dataList = new ArrayList<Integer>();
for(int i = 1; i <=132; i++){
dataList.add(i);
}
//segmentedBatchSubListClearMethod(dataList);
generalSegmentedBatchSubList(dataList);
}
/**
* 使用 subList clear方式删除已经使用使用过的list 元素
* @param dataList
*/
public static void segmentedBatchSubListClearMethod(List<Integer> dataList){
//分批处理
if (dataList.size() > 0) {
//限制条数
int pointsDataLimit = 10;
int size = dataList.size();
//判断是否有必要分批
if (pointsDataLimit < size) {
//分批数
int part = size / pointsDataLimit;
System.out.println("共有 : " + size + "条,!" + " 分为 :" + part + "批");
for (int i = 0; i < part; i++) {
//1000条
List<Integer> listPage = dataList.subList(0, pointsDataLimit);
System.out.println("clearMethod: "+listPage);
//剔除
dataList.subList(0, pointsDataLimit).clear();
}
//此处处理整页后剩余部分
if (!dataList.isEmpty()) {
//表示最后剩下的数据
System.out.println("clearMethod: "+dataList);
}
} else {
System.out.println(dataList);
}
} else {
System.out.println("没有数据!!!");
}
}
/**
* 普通分段处理list方法
* @param dataList
*/
public static void generalSegmentedBatchSubList(List<Integer> dataList){
int perMaxDealCount=10,index=1;
int wholePage=dataList.size()/perMaxDealCount;
int times=dataList.size()%perMaxDealCount==0?(wholePage):(wholePage+1);
do{
List<Integer> pageDealDataList=new ArrayList<Integer>();
// pageDealDataList是分段处理逻辑的参数
int startIndex=(index-1)*perMaxDealCount;
//此处需要注意 list.subList(int fromIndex, int toIndex) 返回list中指定下标的元素组成的list集合,左闭右开
int endIndex=index*perMaxDealCount;
if(index==times){
pageDealDataList=dataList.subList(startIndex, dataList.size());
System.out.println("general: "+pageDealDataList);
}else{
pageDealDataList=dataList.subList(startIndex, endIndex);
System.out.println("general: "+pageDealDataList);
}
index++;
}
while (index<=times);
}
}
3、原理分析及总结
本实现方法使用List的 sublist方法来实现了 数据分段分批处理,注意事项:
(1)、List subList(int fromIndex, int toIndex) 返回list中指定下标的元素组成的list集合,左闭右开
参数:
fromIndex - subList 的低端(包括)
toIndex - subList 的高端(不包括)
(2)、注意点
返回的新的集合指向原有集合,修改新的集合会影响原有集合的内容.
(3)、决解方案
3.1、新建一个新的集合
ArrayList<String> realList = new ArrayList<String>(list.subList( fromIndex, toIndex)); 操作realList不会影响原有list.
3.2、添加到新的集合中
ArrayList<String> newList = new ArrayList<String>();
newList.addAll(list.subList( fromIndex, toIndex));
操作newList不会影响原有list.
(4)、可以每次使用sublist clear 方法清除以前使用过的分段数据
上述代码主要目的是通过一个基本示例;让我们明白如何在实际项目之中实现基本的List 分段批量(SegmentedBatch)操作。
4、实战代码
public Map<String,Object> executeBatchImportUserByExcel(PermissionUser currentUser,String operatorUserKey,
List<PermissionUser> importExcelUserList) {
int perMaxDealCount=50,index=1;
int wholePage=importExcelUserList.size()/perMaxDealCount;
int times=importExcelUserList.size()%perMaxDealCount==0?(wholePage):(wholePage+1);
Map<String,Object> resultMap=new HashMap<String,Object>();
String operatorResult="0";
List<Map<String,String>> batchImportUserStatusList=new ArrayList<Map<String,String>>();
do {
List<PermissionUser> pageDealDataUserList=new ArrayList<PermissionUser>();
// pageDealDataList是分段处理逻辑的参数
int startIndex=(index-1)*perMaxDealCount;
//此处需要注意 list.subList(int fromIndex, int toIndex) 返回list中指定下标的元素组成的list集合,左闭右开
int endIndex=index*perMaxDealCount;
if(index==times){
pageDealDataUserList=importExcelUserList.subList(startIndex, importExcelUserList.size());
}else{
pageDealDataUserList=importExcelUserList.subList(startIndex, endIndex);
}
// 调用用户中心接口 以每50条记录上传数据到 用户中心去
Map<String, Object> paramMap=new HashMap<String,Object>();
//此处处理主要是针对用户中心所需的用户信息 整合为map list进行上传
Map<String, Object> ucUserMap=null;
List<Map<String, Object>> pageDealDataList=new ArrayList<Map<String, Object>>();
for(PermissionUser itemUser:pageDealDataUserList) {
ucUserMap=new HashMap<String,Object>(7);
ucUserMap.put("user_account", itemUser.getLoginName());
ucUserMap.put("password", Constant.USER_PASSWORD);
ucUserMap.put("name",itemUser.getRealName());
ucUserMap.put("sex", itemUser.getSexType()=="0"?1:2);
ucUserMap.put("phone",itemUser.getTelephone());
ucUserMap.put("avatar_url",itemUser.getPhotoUrl());
ucUserMap.put("role", 1);
//设置用户名信息到list
Map<String,String> userLoginNameMap=new HashMap<String,String>(5);
userLoginNameMap.put("loginName", itemUser.getLoginName());
batchImportUserStatusList.add(userLoginNameMap);
pageDealDataList.add(ucUserMap);
}
JSONArray dataJsonArray = (JSONArray)JSON.toJSON(pageDealDataList);
String dataJson=dataJsonArray.toString();
logger.info("批量处理 注册用户的请求:\n"+dataJson);
paramMap.put("userKey", operatorUserKey);
paramMap.put("data", dataJsonArray);
//从json之中获得获得信息
JSONObject responseResultJson=administratorOperateUserService.batchRegister(paramMap);
JSONObject responseBodyJson=responseResultJson.getJSONObject("responseBody");
String userCenterExceptionMsg=responseResultJson.getString("userCenterExceptionMsg");
//此处处理不一样 需要遇见异常直接退出循环
if(!"no".equals(userCenterExceptionMsg)){
logger.info("userLogin==> userCenterExceptionMsg: {}", userCenterExceptionMsg);
resultMap.put("success","-1");
resultMap.put("message",userCenterExceptionMsg);
return resultMap;
}
logger.info("requestResultJson :\n"+responseBodyJson.toJSONString());
String statusNum=responseBodyJson.get("status").toString();
String message=responseBodyJson.get("msg").toString();
if("200".equals(statusNum)) {
//获得注册到用户中心后的 返回的数据给予前端页面提醒
JSONArray batchRegisterResultData =responseBodyJson.getJSONArray("data");
for(int i=0;i<batchRegisterResultData.size();i++){
JSONObject itemJson=batchRegisterResultData.getJSONObject(i);
String registerStatus=itemJson.get("status").toString();
String userAccount=itemJson.get("user_account").toString();
//是否注册过其他app 1 已注册别的app 0 没有
String isRegisterOtherApp=itemJson.get("is_register_other_app").toString();
//设置用户名导入状态到list
Map<String,String> userStatusMap=batchImportUserStatusList.get(i);
if("注册成功".equals(registerStatus)){
userStatusMap.put("registerStatusFlag","0");
}else if("用户名已存在".equals(registerStatus)){
userStatusMap.put("registerStatusFlag","2");
Iterator<PermissionUser> userIterator=pageDealDataUserList.iterator();
while(userIterator.hasNext()){
PermissionUser user= userIterator.next();
String loginName=user.getLoginName();
if(userAccount.equals(loginName)){
userIterator.remove();
}
}
}else if("手机号已存在".equals(registerStatus)){
userStatusMap.put("registerStatusFlag","3");
Iterator<PermissionUser> userIteratorTel=pageDealDataUserList.iterator();
while(userIteratorTel.hasNext()){
PermissionUser user= userIteratorTel.next();
String loginName=user.getLoginName();
if(userAccount.equals(loginName)){
userIteratorTel.remove();
}
}
}else{
userStatusMap.put("registerStatusFlag","1");
}
if("1".equals(isRegisterOtherApp)){
userStatusMap.put("isRegisterOtherAppText","该用户注册过的其他产品,请使用原密码登录");
}else{
userStatusMap.put("isRegisterOtherAppText","该用户为新注册系统用户");
}
userStatusMap.put("isRegisterOtherApp",isRegisterOtherApp);
userStatusMap.put("registerStatus",registerStatus);
}
logger.info("第"+index+" 批次 =====> 批量处理注册用户上传用户中心 成功 ! "+pageDealDataUserList.size()+" 记 录");
operatorResult="0";
resultMap.put("message","第"+index+" 批次 批处理注册用户到用户中心 共计 批处理 "+pageDealDataUserList.size()+" 记 录");
// 然后导入数据到自己有系统之中
permissionUserService.saveAllUser(currentUser,pageDealDataUserList);
//导入完毕后 更新 loginid和status
batchUpdateSyncWdyEduLoginIdAndStatus(responseBodyJson);
}else {
logger.error("第"+index+" 批次 =====> 批量处理注册用户上传用户中心 有部分数据失败!");
operatorResult="-1";
resultMap.put("success",operatorResult);
resultMap.put("message",message);
return resultMap;
}
//遍历当前的值是否正确
//System.out.println("第"+index+"轮:>>"+pageDealDataList.size());
importExcelUserList.removeAll(pageDealDataList);
//System.out.println("当前剩余集合长度:>>"+importExcelUserList.size());
index++;
}
while (index<=times);
resultMap.put("success",operatorResult);
resultMap.put("batchImportUserStatusList",batchImportUserStatusList);
//如果没有任何问题返回最后一个批次结果信息
return resultMap;
}