业务需求:将zip格式的文件导入到系统,解析其中的所有图片,要求必须是图片还要限制文件大小不大于200Kb、不能出现中文,符合要求的图片上传云端或者本地保存-返回保存地址,然后再根据图片文件命名的idcard来绑定人员图片信息写入数据库。
单个文件的情况下,我们可以直接使用multipartFile对象的方法,直接获取文件名和大小等信息。但是现在传过来的file是压缩包,要自己解压再去读取文件名,直接百度好吧。
================没有s图================
查到的结果有一大半都是另存到磁盘,然后解压到当前目录,这样确实可以,但老是感觉这样不好(编程新手的傻傻分不清),可能是因为一直在io太麻烦不想搞。然后我就继续找,发现了apache自带的一个输入流 ZipImputStream 。
GBK
getNextEntry() 方法,返回的 ZipEntry
@ApiOperation(value = "批量采集",notes = "导入zip图片文件夹压缩包")
@PostMapping("/batchAdd")
@Log(title = "人脸管理【批量采集照片】",businessType = BusinessType.IMPORT)
public AjaxResult batchAdd(MultipartFile file) throws Exception{//tomcat默认最大大小为20mb
if (ObjectUtil.isNull(file)){
return AjaxResult.error("上传文件为空");
}
String fileName = file.getOriginalFilename();
System.out.println("文件名:"+fileName);
if (!"zip".equals(fileName.substring(fileName.lastIndexOf(".")+1))){
return AjaxResult.error(300,"请上传zip格式的压缩包");
}
if (file == null || file.getSize() <= 0){
return AjaxResult.error(300,"上传压缩文件为空");
}
//解析zip文件
ZipInputStream zipInputStream = null;
ZipEntry zipEntry = null;
int num = 0;
try {
zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));
while ((zipEntry = zipInputStream.getNextEntry()) != null){
String name = zipEntry.getName();
System.out.println("文件夹名:"+name);
if (name.endsWith("/") || name.endsWith("\\")){
System.out.println("存在空文件夹,文件夹名为:"+zipEntry.getName());
continue;
}
num++;
//空校验
String[] split ;
String photoName = null;
if (name.contains("/")){
split = name.split("/");
photoName = split[split.length-1];
}else if (name.contains("\\")){
split = name.split("\\\\");
photoName = split[split.length-1];
}else {
photoName = name;
}
String idCard = photoName.substring(0,photoName.indexOf("."));
System.out.println(num+" 文件名:"+photoName);
if (StringUtils.isEmpty(photoName)){
throw new RuntimeException("获取文件名错误");
}
//图片类型校验
String suffix = photoName.substring(photoName.lastIndexOf(".") + 1);
if (!("jpg".equalsIgnoreCase(suffix) || "png".equalsIgnoreCase(suffix))){
throw new RuntimeException("压缩包存在不符合图片格式(jpg和png)的文件");
}
//校验图片大小 大于20kb,小于200kb
if (zipEntry.getSize() < new Long(20*1024) || zipEntry.getSize() > new Long(200*1024)){
throw new RuntimeException("存在图片不符合要求,请检查小于20KB和大于200KB的图片并予以修改");
}
//校验图片命名不存在中文
Pattern compile = Pattern.compile("[\u4e00-\u9fa5]");
Matcher matcher = compile.matcher(photoName);
if (matcher.find()){
throw new RuntimeException("图片命名存在中文");
}
//调用百度接口,识别人脸 读取照片文件-调用上传-添加采集记录
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[4096];
int len = 0;
while ((len = zipInputStream.read(bytes)) > 0){
outputStream.write(bytes,0,len);
}
outputStream.flush();
outputStream.close();
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
MultipartFile multipartFile = getMultipartFile(inputStream, photoName);
System.out.println("idcard:"+idCard);
AjaxResult ajaxResult = photoUploadAndCollect(multipartFile,idCard);
//如果上传出错,抛出异常信息激活事务
// System.out.println("处理图片返回结果:"+ajaxResult);
System.out.println("code:"+ajaxResult.get("code"));
System.out.println(!"200".equals(String.valueOf(ajaxResult.get("code"))));
if (!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new RuntimeException(String.valueOf(ajaxResult.get("msg")));
}
zipInputStream.closeEntry();
inputStream.close();
}
zipInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (zipInputStream != null){
zipInputStream.close();
}
}
return AjaxResult.success("批量采集图片成功,共上传 "+num+" 张图片");
}
ZipEntry获得到的文件名格式如下:
/新建文件夹/435765199712305649.jpg
/新建文件夹/新建文件夹/
/新建文件夹(1)/435765199712305649.jpg
说明:如上所示,他会依次一直读到文件为止。当最后一级为文件夹时,就是第二个种情况,表示这是一个空文件夹。
上传图片:
当信息校验完成之后,就可以先上传照片了,可以利用已有的上传接口,但是参数是 multipartFile
类型,就又百度了一个字节流封装成MyltipartFile的方法(粘过了稍微改造了一下完美),如下所示:
(118条消息) 图片上传文件流格式转换 File文件流转为MultipartFile流详解_文件流转multipartfile_guobinhui的博客
/**
* 获取封装得MultipartFile
*
* @param inputStream inputStream
* @param fileName fileName
* @return MultipartFile
*/
public MultipartFile getMultipartFile(InputStream inputStream, String fileName) {
FileItem fileItem = createFileItem(inputStream, fileName);
//CommonsMultipartFile是feign对multipartFile的封装,但是要FileItem类对象
return new CommonsMultipartFile(fileItem);
}
/**
* FileItem类对象创建
*
* @param inputStream inputStream
* @param fileName fileName
* @return FileItem
*/
public FileItem createFileItem(InputStream inputStream, String fileName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
String textFieldName = "file";
FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
int bytesRead = 0;
byte[] buffer = new byte[10 * 1024 * 1024];
OutputStream os = null;
//使用输出流输出输入流的字节
try {
os = item.getOutputStream();
while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
inputStream.close();
} catch (IOException e) {
// log.error("Stream copy exception", e);
throw new IllegalArgumentException("文件上传失败");
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// log.error("Stream close exception", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// log.error("Stream close exception", e);
}
}
}
return item;
}
至此,我已经保存好了图片,只需要将图片和人员关联信息保存到数据库就圆满结束了。我已经有了图片地址,根据图片命名的idcard查一下人员信息,得到数据保存到数据库。如下所示:
private AjaxResult photoUploadAndCollect(MultipartFile multipartFile, String idCard) throws Exception{
//1查询人员信息
PersonnelInfo pi = personnelInfoService.getPersonnelInfoDetailByIdCard(idCard);
if (ObjectUtil.isNull(pi)){
throw new RuntimeException("获取身份证号为:"+idCard+" 的人员信息失败");
}
QueryWrapper<PersonnelBiologyInfo> biologyInfoQueryWrapper = new QueryWrapper<>();
biologyInfoQueryWrapper.eq("enable_flag",0);
biologyInfoQueryWrapper.eq("personnel_info_id",pi.getId());
PersonnelBiologyInfo biology = personnelBiologyInfoService.getOne(biologyInfoQueryWrapper);
if (ObjectUtil.isNull(biology)){
biology = new PersonnelBiologyInfo();
biology.setCreateTime(new Date());
biology.setCreateUser(Integer.valueOf(String.valueOf(getUserId())));
}else {
biology.setUpdateTime(new Date());
biology.setUpdateUser(Integer.valueOf(String.valueOf(getUserId())));
}
biology.setBiologyType("1");
biology.setPersonnelInfoId(pi.getId());
biology.setAuditStatus("0");
biology.setEnableFlag(0);
biology.setSource(0);
//2图片上传,接口有调用百度接口-识别人脸返回评分
AjaxResult ajaxResult = collectPictures(multipartFile);
if (!"200".equals(String.valueOf(ajaxResult.get("code")))){
return ajaxResult;
}
String fileName = String.valueOf(ajaxResult.get("fileName"));
//3添加采集记录
biology.setBiologyInfo(fileName);
biology.setFaceQuality(String.valueOf(ajaxResult.get("pf")));
boolean b = personnelBiologyInfoService.saveOrUpdate(biology);
if (!b){
throw new RuntimeException("身份证号为:"+idCard+" 保存人员生物信息失败");
}
return AjaxResult.success();
}
微调一下,完美结束,运行正常。
一个简单的小功能,记录一下,有问题还望指正,大佬勿喷心灵比较弱小。
大概就是使用apache自带的zipinputstream获取zip压缩包的数据流,然后通过网上搜的方法将每一个图片流转换成mulitpartFile类型,直接调用了若依已有方法上传保存,结束。先放这里,回头仔细说明一下。