最近公司有个需求,批量导入企业信息。
企业信息存在excel中,企业logo图片存在同级logo文件夹中,目录是这样的
(使用规范说明是给业务人员写的说明文档,下载模板时一同生成的)
这个上传注定是一个压缩包的方式
HTML
后台使用MultipartFile接收文件,具体是这样的
/**
* 插入企业信息
* @param file
* @return
* @throws IOException
*/
@ResponseBody
@RequestMapping(value = "/enterpriseInfo")
public List importEnterpriseInfo(@RequestParam("file") MultipartFile file,HttpServletResponse response) throws IOException {
List results = super.importExcel(file);
System.out.println(results);
List vos = manageService.findListEnterprise(this.checkRepeatData(results));
//如果企业名称没有重复
if(CollectionUtils.isEmpty(vos)){
manageService.insertBatchEnterpriseInfo(results);
return results;
} else{
//如果重复了将重复的企业返回告知用户
/*this.getRepeatData(vos,response);*/
return vos;
}
}
导入信息解析
/**
* 导入
* @param file
* @return
* @throws IOException
*/
public List importExcel(MultipartFile file)throws IOException{
InputStream inputStream = file.getInputStream();
ZipInputStream zipIn = new ZipInputStream(inputStream, Charset.forName("GBK"));
String randomStr = StringUtils.radomString();
String destDir = enterprisesInfoPath + File.separator + randomStr;
StreamZipUtils.unzipFromStream(zipIn, destDir);
File rootDir = new File(destDir);
this.getFileFinalPath(rootDir);
rootDir = new File(fileFinalPath);
//获取目录下的Excel表格以及照片文件夹
File excel = null;
File photoDir = null;
if (rootDir.exists()) {
File files[] = rootDir.listFiles();
for (File f : files){
if(f.getName().toLowerCase().endsWith(".xlsx")){
excel = f;
}else{
photoDir = f;
}
}
if (null == excel || null == photoDir) {
throw new RuntimeException("未找到对应Excel文件或图片目录");
}
}
String fileName= excel.getName();
boolean extension = fileName.toLowerCase().endsWith(".xlsx");
List results = null;
if(extension){
FileInputStream is = new FileInputStream(excel);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(),
ContentType.APPLICATION_OCTET_STREAM.toString(), is);
results = read2007Excel(multipartFile,photoDir);
}else{
throw new IOException("不支持的文件类型");
}
return results;
}
public static String radomString(){
String result="";
for(int i=0;i<6;i++){
int intVal=(int)(Math.random()*26+97);
result=result+(char)intVal;
}
return result;
}
public static void unzipFromStream(ZipInputStream zipis, String dest) {
File destDir = new File(dest);
destDir.mkdirs();
FileOutputStream out = null;
try {
ZipEntry fentry = null;
while ((fentry = zipis.getNextEntry()) != null) {
// fentry逐个读取zip中的条目,第一个读取的名称为test。
// test条目是文件夹,因此会创建一个File对象,File对象接收的参数为地址
// 然后就会用exists,判断该参数所指定的路径的文件或者目录是否存在
// 如果不存在,则构建一个文件夹;若存在,跳过
// 如果读到一个zip,也继续创建一个文件夹,然后继续读zip里面的文件,如txt
if (fentry.isDirectory()) {
File dir = new File(dest + File.separator + fentry.getName());
if (!dir.exists()) {
dir.mkdirs();
}
} else {
// fname是文件名,fileoutputstream与该文件名关联
String fname = new String(dest + File.separator + fentry.getName());
File fileDir = new File(fname);
if(!fileDir.getParentFile().exists()){
fileDir.getParentFile().mkdirs();
}
// 新建一个out,指向fname,fname是输出地址
out = new FileOutputStream(fname);
byte[] doc = new byte[512];
int n;
// 若没有读到,即读取到末尾,则返回-1
while ((n = zipis.read(doc, 0, 512)) != -1) {
// 这就把读取到的n个字节全部都写入到指定路径了
out.write(doc, 0, n);
}
out.flush();
doc = null;
}
}
} catch (Exception ioex) {
log.error("解压缩错误:", ioex);
} finally {
try {
if (zipis != null) {
zipis.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
log.error("io错误:", e);
}
}
}
/**
* 获取文件最终路径(用于用户嵌套文件夹)
* @param file
* @return
*/
public String getFileFinalPath(File file){
for (File f : file.listFiles()){
if(f.isDirectory()){
f = new File(f.getPath());
getFileFinalPath(f);
}
if(f.getName().toLowerCase().endsWith(".xlsx")){
fileFinalPath = f.getParent();
break;
}
}
return fileFinalPath;
}
注意:fileFinalPath为静态变量
/**
* 扫描盘符中企业Logo图片
* @return
*/
protected String scanningDriveLetterImage(String enterpriseName,File photoDir){
File file = new File(photoDir.getPath()+"/"+enterpriseName);
File[] files = file.listFiles();
if(files == null){
logger.error("图片存储路径",photoDir.getPath()+"/"+enterpriseName);
throw new RuntimeException("没有找到["+enterpriseName+"]的LOGO图片,当前查找图片路径:"+file.getPath());
}
for (File f : files){
String[] str = f.getName().split("\\.");
if(str[0].equals(enterpriseName)){
file = f;
}
}
MultiValueMap multiValueMap = new LinkedMultiValueMap();
FileSystemResource fsr = new FileSystemResource(file);
multiValueMap.add("file",fsr);
ResponseEntity responseEntity = this.restTemplateForFile("http://xxx/upload/multipartFile",multiValueMap,String.class);
String path = responseEntity.getBody();
return path;
}
这一段代码需要单独拎出来说明,
由于上传企业logo并不是前端下请求,而是后端主动去扫描磁盘,因此必须要模仿http设置请求体和请求头,因为我们使用的是springcloud构建的微服务,在我们将文件从feign中转发到实现的时候会先报没有设置请求头为multipart/form-data,这时我们这样做的
@RequestMapping(value = "/upload",method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
我们使用了 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,现在不在报设置请求为multipart/form-data的错误了,转而报没有文件随机参数,而这是设置不了的,所以只能使用spring提供的http包中的对象进行代理发送http请求
org.springframework.http包中为我们提供了这些对象
MultiValueMap multiValueMap = new LinkedMultiValueMap();
FileSystemResource fsr = new FileSystemResource(file);
multiValueMap.add("file",fsr);
ResponseEntity responseEntity = this.restTemplateForFile("http://xxxx/upload/multipartFile",multiValueMap,String.class);
String path = responseEntity.getBody();
/**
* 使用Spring的restTemplate的postForEntity方法代理发送http请求
* @param url 请求路径
* @param map 文件主体
* @param responseType 内置响应
* @param
* @return
*/
private ResponseEntity restTemplateForFile(String url, MultiValueMap map, Class responseType){
//设置请求头
HttpHeaders headers = new HttpHeaders();
//设置上传Content-Type类型
MediaType mediaType = MediaType.parseMediaType("multipart/form-data");
headers.setContentType(mediaType);
//用httpEntity封装整个请求报文
HttpEntity> httpEntity = new HttpEntity(map,headers);
ResponseEntity responseEntity = restTemplate.postForEntity(url, httpEntity, responseType);
return responseEntity;
}
解析excel的就不写了,不在本文重点