@ -25,6 +25,7 @@ import com.epmet.commons.tools.redis.RedisUtils;
import com.epmet.commons.tools.redis.common.CustomerStaffRedis ;
import com.epmet.commons.tools.utils.ConvertUtils ;
import com.epmet.commons.tools.utils.EpmetRequestHolder ;
import com.epmet.commons.tools.utils.FileUtils ;
import com.epmet.commons.tools.utils.Result ;
import com.epmet.constants.ImportTaskConstants ;
import com.epmet.dao.IcResiUserDao ;
@ -75,10 +76,17 @@ import java.util.stream.Collectors;
@Service
public class IcResiUserImportServiceImpl implements IcResiUserImportService , ResultDataResolver {
public static final List < String > controlGroup1 = Arrays . asList ( "input" , "textarea" , "datepicker" , "daterange" ) ;
public static final List < String > controlGroup2 = Arrays . asList ( "select" , "radio" ) ;
/ * *
* 身份证号列序号
* /
public static final Integer ID_CARD_COLUMN_NO = 9 ;
/ * *
* 姓名列序号
* /
public static final Integer ID_NAME_COLUMN_NO = 6 ;
// 错误和跳过excel行暂存
public static final ThreadLocal < Map < String , List < ErrorRow > > > errorRows = new ThreadLocal < > ( ) ;
@ -163,9 +171,9 @@ public class IcResiUserImportServiceImpl implements IcResiUserImportService, Res
private Integer required ;
private List < Integer > colIndex ;
//private List<String> colContents;
// 单元格内容
// 单元格内容。多选框没有该列,因为多选框对应着excel的多列
private String cellContent ;
// 数据库中列的 值
// 单元格内容对应的 数据库中值
private String colValue ;
// key:label,value:value
@ -425,11 +433,10 @@ public class IcResiUserImportServiceImpl implements IcResiUserImportService, Res
try {
convertColumnWrappers2Map4Persist ( itemIdAndColumnWrapper , row , currUserAgencyId , checkBoxOptionColumnIdxAndLabel , columnAndValues , true ) ;
String idCard = columnAndValues . get ( "ID_CARD" ) ;
// 执行指定的检查
specifiedCheck ( columnAndValues ) ;
String idCard = columnAndValues . get ( "ID_CARD" ) ;
Map < String , String > existingResiMap = icResiUserDao . selectResiInfoMap ( idCard , null ) ;
if ( existingResiMap = = null ) {
@ -596,7 +603,7 @@ public class IcResiUserImportServiceImpl implements IcResiUserImportService, Res
if ( resiName = = null ) {
resiName = "" ;
}
throw new RenException ( EpmetErrorCode . IDCARDNO_ERROR . getCode ( ) , String . format ( "用户 【%s】身份证号未填写或格式错误" , resiName ) ) ;
throw new RenException ( EpmetErrorCode . IDCARDNO_ERROR . getCode ( ) , String . format ( "居民 【%s】身份证号未填写或格式错误" , resiName ) ) ;
}
// 检查用户是否存在
@ -719,111 +726,195 @@ public class IcResiUserImportServiceImpl implements IcResiUserImportService, Res
/ * *
* 将当前行数据转化成LinkedHashMap , 供后续插入
* @param i temIdAndColumnWrappers 当前行的ColumnWrapper , 每一个ColumnWrapper元素都是当前行中的一个列 , key : itemId
* @param dbMetadataI temIdAndColumnWrappers 当前行的ColumnWrapper , 每一条都是数据库中的一个列的源数据 , 对应到excel中可能是多个列 ( 多选 ) 。 每一个ColumnWrapper元素都是当前行中的一个列 , key : itemId
* @param row 当前行数据
* @param currUserAgencyId 当前用户所属机构ID
* @param checkBoxOptionColumnIdxAndLabel 复选框options列表 。 key : 列号 , value : 复选框中文
* @param target 要将数据放到哪个对象中
* @param target2Insert 要用来insert到db的数据
* @param isPrimaryTable 是否是主表
* /
private void convertColumnWrappers2Map4Persist ( Map < String , ColumnWrapper > i temIdAndColumnWrappers, Map < Integer , String > row ,
private void convertColumnWrappers2Map4Persist ( Map < String , ColumnWrapper > dbMetadataI temIdAndColumnWrappers, Map < Integer , String > row ,
String currUserAgencyId , Map < Integer , String > checkBoxOptionColumnIdxAndLabel ,
LinkedHashMap < String , String > target , boolean isPrimaryTable ) {
LinkedHashMap < String , String > target2Insert , boolean isPrimaryTable ) {
boolean interupt = false ;
// 本行中是否有必填但未填,或者填了但填错了系统中找不到的列,那后面的数据可能就没办法通过前面填写的值去关联查询,因此只做必填检查,提示出来就行了,仁至义尽
boolean hasError = false ;
List < String > errorColumnNames = new LinkedList < > ( ) ;
String notFoundColumnName = null ;
List < String > emptyColumnNames = new ArrayList < > ( ) ;
for ( Map . Entry < String , ColumnWrapper > itemIdAndColumnWrapper : itemIdAndColumnWrappers . entrySet ( ) ) {
// 这两列要提前放进去,因为有的列未填写的话,会抛异常出去,需要用这两列来做描述
target2Insert . put ( "ID_CARD" , row . get ( ID_CARD_COLUMN_NO ) ) ;
target2Insert . put ( "NAME" , row . get ( ID_NAME_COLUMN_NO ) ) ;
String itemId = itemIdAndColumnWrapper . getKey ( ) ;
ColumnWrapper columnWrapper = itemIdAndColumnWrapper . getValue ( ) ;
for ( Map . Entry < String , ColumnWrapper > dbColumnMetadata : dbMetadataItemIdAndColumnWrappers . entrySet ( ) ) {
if ( "input" . equals ( columnWrapper . getItemType ( ) )
| | "textarea" . equals ( columnWrapper . getItemType ( ) )
| | "datepicker" . equals ( columnWrapper . getItemType ( ) )
| | "daterange" . equals ( columnWrapper . getItemType ( ) )
) {
String currentItemId = dbColumnMetadata . getKey ( ) ;
ColumnWrapper columnWrapper = dbColumnMetadata . getValue ( ) ;
// "input", "textarea", "datepicker", "daterange"
if ( controlGroup1 . contains ( columnWrapper . getItemType ( ) ) ) {
// 输入的控件,不会横跨多个单元格,所以只取一列就可以了
String cellContent = row . get ( columnWrapper . getColIndex ( ) . get ( 0 ) ) ;
columnWrapper . setCellContent ( cellContent ) ;
columnWrapper . setColValue ( cellContent ) ;
} else if ( "select" . equals ( columnWrapper . getItemType ( ) )
| | "radio" . equals ( columnWrapper . getItemType ( ) ) ) {
// 必填检查
boolean hasEmptyError = requiredButEmptyCheck ( isPrimaryTable , columnWrapper ) ;
if ( hasEmptyError ) {
emptyColumnNames . add ( columnWrapper . combinedLabel ) ;
hasError = true ;
continue ;
}
if ( hasError ) {
continue ;
}
// "select", "radio"
} else if ( controlGroup2 . contains ( columnWrapper . getItemType ( ) ) ) {
String optionSourceType = columnWrapper . getOptionSourceType ( ) ;
// 取单元格的内容
String cellContent = row . get ( columnWrapper . getColIndex ( ) . get ( 0 ) ) ;
columnWrapper . setCellContent ( cellContent ) ;
if ( "local" . equals ( optionSourceType ) ) {
// 必填检查
boolean hasEmptyError = requiredButEmptyCheck ( isPrimaryTable , columnWrapper ) ;
if ( hasEmptyError ) {
emptyColumnNames . add ( columnWrapper . combinedLabel ) ;
hasError = true ;
continue ;
}
if ( hasError ) {
continue ;
}
if ( "local" . equals ( columnWrapper . getOptionSourceType ( ) ) ) {
// 根据单元格内容,取到指定的option
Map < String , String > options = columnWrapper . getOptions ( ) ;
String colValue = options . get ( cellContent ) ;
Map < String , String > itemO ptions = columnWrapper . getOptions ( ) ;
String colValue = itemO ptions. get ( cellContent ) ;
columnWrapper . setColValue ( colValue ) ;
} else {
// remote类型。优先从缓存取
String fullUri = columnWrapper . getOptionSourceValue ( ) ;
String [ ] uriParts = splitOptionSourceUrl ( fullUri ) ;
String pureUri = uriParts [ 0 ] ;
String superItemId = uriParts [ 1 ] ;
String superColumValue ;
String superColumn Value ;
// 获取父item的值
if ( StringUtils . isNotBlank ( superItemId ) ) {
superColumValue = i temIdAndColumnWrappers. get ( superItemId ) . getColValue ( ) ;
superColumn Value = dbMetadataI temIdAndColumnWrappers. get ( superItemId ) . getColValue ( ) ;
} else {
superColumValue = "-" ;
superColumn Value = "-" ;
}
Map < String , Map < String , String > > superOptions = itemIdAndOptionsCache . getIfPresent ( itemId ) ;
// 通过接口调用,计算出colValue,放到columnWrapper中
Map < String , Map < String , String > > superOptions = itemIdAndOptionsCache . getIfPresent ( currentItemId ) ;
if ( superOptions ! = null & & superOptions . size ( ) > 0 ) {
Map < String , String > options = superOptions . get ( superColumValue ) ;
Map < String , String > options = superOptions . get ( superColumn Value ) ;
if ( options = = null | | options . size ( ) = = 0 ) {
options = listRemoteOptions ( pureUri , superItemId , i temIdAndColumnWrappers, currUserAgencyId , "saveorupdate" ) ;
superOptions . put ( superColumValue , options ) ;
options = listRemoteOptions ( pureUri , superItemId , dbMetadataI temIdAndColumnWrappers, currUserAgencyId , "saveorupdate" ) ;
superOptions . put ( superColumn Value , options ) ;
}
String colValue = options . get ( cellContent ) ;
columnWrapper . setColValue ( colValue ) ;
} else {
Map < String , String > options = listRemoteOptions ( pureUri , superItemId , itemIdAndColumnWrappers , currUserAgencyId , "saveorupdate" ) ;
// 父item的options。例如当前遍历的是小区列,那查出来的就是网格下的小区
// 然后把 <currentItemId:<superItem:usperOptions>> 放到缓存里
Map < String , String > options = listRemoteOptions ( pureUri , superItemId , dbMetadataItemIdAndColumnWrappers , currUserAgencyId , "saveorupdate" ) ;
superOptions = new HashMap < > ( ) ;
superOptions . put ( superColumValue , options ) ;
itemIdAndOptionsCache . put ( i temId, superOptions ) ;
superOptions . put ( superColumn Value , options ) ;
itemIdAndOptionsCache . put ( currentI temId, superOptions ) ;
String colValue = options . get ( cellContent ) ;
columnWrapper . setColValue ( colValue ) ;
}
}
} else if ( "checkbox" . equals ( columnWrapper . getItemType ( ) ) ) {
//多选框没有具体的cellContent,因为多选框对应着excel的多列。并且复选框,为空就是否,所以不需要做必填检查
String checkBoxColValue = getCheckBoxColValue ( columnWrapper , row , checkBoxOptionColumnIdxAndLabel ) ;
columnWrapper . setColValue ( checkBoxColValue ) ;
}
// requiredColumns中的值不在排除字段中 && 是必填 && 未填写
if ( isPrimaryTable ) {
// 主表没有需要排除的列
if ( columnWrapper . getRequired ( ) = = 1 & & StringUtils . isBlank ( columnWrapper . colValue ) ) {
interupt = true ;
errorColumnNames . add ( columnWrapper . combinedLabel ) ;
}
} else {
// 从表需要排除掉一些不必要校验的列
if ( ! subTableNeedlessColumns . contains ( columnWrapper . columnName )
& & columnWrapper . getRequired ( ) = = 1
& & StringUtils . isBlank ( columnWrapper . colValue ) ) {
interupt = true ;
errorColumnNames . add ( columnWrapper . combinedLabel ) ;
if ( hasError ) {
continue ;
}
}
target . put ( columnWrapper . columnName , columnWrapper . colValue ) ;
// 填了,但找不到对应数据的检查
boolean hasNotFoundError = notFoundCheck ( isPrimaryTable , columnWrapper ) ;
if ( hasNotFoundError ) {
notFoundColumnName = columnWrapper . combinedLabel ;
hasError = true ;
}
target2Insert . put ( columnWrapper . columnName , columnWrapper . colValue ) ;
}
if ( hasError ) {
StringBuilder sb = new StringBuilder ( ) ;
// 组织报错信息
if ( CollectionUtils . isNotEmpty ( emptyColumnNames ) ) {
sb . append ( String . join ( "," , emptyColumnNames ) ) . append ( "的值未填写;" ) ;
}
if ( StringUtils . isNotBlank ( notFoundColumnName ) ) {
sb . append ( notFoundColumnName ) . append ( "填写的值在系统中未找到" ) ;
}
throw new EpmetException ( sb . toString ( ) ) ;
}
}
/ * *
* 必填 , 但是用户没填的 , 放到list中
* @param isPrimaryTable 是否是主表 。 true : 是主表 , false : 从表
* @param columnWrapper 数据库列包装对象
* /
public boolean requiredButEmptyCheck ( Boolean isPrimaryTable , ColumnWrapper columnWrapper ) {
// requiredColumns中的值不在排除字段中 && 是必填 && 未填写
if ( isPrimaryTable ) {
// 主表没有需要排除的列
if ( columnWrapper . getRequired ( ) = = 1 & & StringUtils . isBlank ( columnWrapper . cellContent ) ) {
return true ;
}
} else {
// 从表需要排除掉一些不必要校验的列
if ( ! subTableNeedlessColumns . contains ( columnWrapper . columnName )
& & columnWrapper . getRequired ( ) = = 1
& & StringUtils . isBlank ( columnWrapper . cellContent ) ) {
return true ;
}
}
if ( interupt ) {
throw new RenException ( String . join ( "," , errorColumnNames ) + "的值未填写,或者所填写信息在系统中未找到" ) ;
return false ;
}
/ * *
* 必填 , 并且在系统中没找到值的 , 放到list中
* @param isPrimaryTable 是否是主表 。 true : 是主表 , false : 从表
* @param columnWrapper 数据库列包装对象
* /
public boolean notFoundCheck ( Boolean isPrimaryTable , ColumnWrapper columnWrapper ) {
// requiredColumns中的值不在排除字段中 && 是必填 && 未填写
if ( isPrimaryTable ) {
// 主表没有需要排除的列
if ( columnWrapper . getRequired ( ) = = 1 & & StringUtils . isBlank ( columnWrapper . colValue ) ) {
return true ;
}
} else {
// 从表需要排除掉一些不必要校验的列
if ( ! subTableNeedlessColumns . contains ( columnWrapper . columnName )
& & columnWrapper . getRequired ( ) = = 1
& & StringUtils . isBlank ( columnWrapper . colValue ) ) {
return true ;
}
}
return false ;
}
/ * *
@ -1154,8 +1245,8 @@ public class IcResiUserImportServiceImpl implements IcResiUserImportService, Res
// 文件名
String resultDescFileName = UUID . randomUUID ( ) . toString ( ) . concat ( ".xls" ) ;
FileItemFactory factory = new DiskFileItemFactory ( 16 , null ) ;
FileItem fileItem = factory . createItem ( "file" , ContentType . APPLICATION_OCTET_STREAM . toString ( ) , tru e, resultDescFileName ) ;
FileItem fileItem = new DiskFileItemFactory ( DiskFileItemFactory . DEFAULT_SIZE_THRESHOLD , FileUtils . getAndCreateDirUnderEpmetFilesDir ( "temp" ) . toFile ( ) )
. createItem ( "file" , ContentType . APPLICATION_OCTET_STREAM . toString ( ) , fals e, resultDescFileName ) ;
OutputStream os = fileItem . getOutputStream ( ) ;
Result < UploadImgResultDTO > uploadResult = null ;
try {