diff --git a/README.md b/README.md index fdb3119..e5031df 100644 --- a/README.md +++ b/README.md @@ -9,5 +9,9 @@ 4.图片上传部分:在文件上传部分已有功能的基础上实现了上传前缩略图预览,前台js文件后缀验证,后台代码文件后缀验证和文件类型验证(就算修改后缀名也无法成功上传),支持图片上传前压缩; +5.多选择器多文件上传:通过不同的文件选择器选择不同的文件,最后同时上传,Controller只是简单示意,并没有详细写实现,具体怎么做可参照上面的其它上穿方法。 + +# 文件上传这里好多方法可以抽象出来,当然这个项目只是一个示例,所以我偷了点懒,应用到生产环境时还要根据环境选择保存到不同的文件路径等等,大家根据自己的情况自己封装方法吧。 + diff --git a/build.gradle b/build.gradle index 246e925..0961c5e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,19 @@ -group 'zhangzhihao' -version '1.0-SNAPSHOT' +group "com.github.izhangzhihao" +version "1.0-SNAPSHOT" apply plugin: "java" apply plugin: "war" sourceCompatibility = 1.8 targetCompatibility = 1.8 -def springVersion = "4.3.2.RELEASE" -def HibernateVersion = "5.2.2.Final" +def springVersion = "4.3.4.RELEASE" +def HibernateVersion = "5.2.4.Final" +def JacksonVersion = "2.8.4" repositories { mavenLocal() maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } - jcenter() mavenCentral() - maven { url "http://repo.spring.io/release" } - maven { url "https://repo.spring.io/libs-snapshot" } } dependencies { @@ -34,7 +32,7 @@ dependencies { "org.springframework:spring-orm:${springVersion}", // MySQL - "mysql:mysql-connector-java:6.0.2", + "mysql:mysql-connector-java:6.0.4", //servlet "javax.servlet:javax.servlet-api:3.1.0", @@ -43,29 +41,26 @@ dependencies { "commons-fileupload:commons-fileupload:1.3.1", // JSON - // "com.alibaba:fastjson:1.2.6", - "com.fasterxml.jackson.core:jackson-core:2.7.4", - "com.fasterxml.jackson.core:jackson-databind:2.7.4", - "com.fasterxml.jackson.core:jackson-annotations:2.7.4", + "com.fasterxml.jackson.core:jackson-core:${JacksonVersion}", + "com.fasterxml.jackson.core:jackson-databind:${JacksonVersion}", + "com.fasterxml.jackson.core:jackson-annotations:${JacksonVersion}", - //Hibernate 5.2.0.Final有一个bug + //Hibernate "org.hibernate:hibernate-core:${HibernateVersion}", "org.hibernate:hibernate-validator:5.2.4.Final", - //JPA - //"org.hibernate:hibernate-entitymanager:5.1.0.Final", - //C3P0 - "c3p0:c3p0:0.9.1.2", + "com.mchange:c3p0:0.9.5.2", "org.hibernate:hibernate-c3p0:${HibernateVersion}", //ehcache - "net.sf.ehcache:ehcache-core:2.6.11", + "org.ehcache:ehcache:3.1.2", "org.hibernate:hibernate-ehcache:${HibernateVersion}", //jUnit "junit:junit:4.12", + //@NotNull "org.jetbrains:annotations:15.0", diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/BigFileUploadController.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/BigFileUploadController.java index 28ae41e..044ab7f 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/BigFileUploadController.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/BigFileUploadController.java @@ -59,25 +59,28 @@ public String bigFileUpload(String fileMd5, String fileName, String fileID) { */ @ResponseBody @RequestMapping(value = "/BigFileUp") - public String fileUpload(String guid, String md5value, String chunks, String chunk, String id, String name, String type, String lastModifiedDate, int size, MultipartFile file) { - String fileName = ""; + public String fileUpload(String guid, + String md5value, + String chunks, + String chunk, + String id, + String name, + String type, + String lastModifiedDate, + int size, + MultipartFile file) { + String fileName; try { - int xuhao = 0; - String path = FileUploadController.class.getResource("/").getFile(); - int index = path.indexOf("build"); - String tempPath = "/src/main/webapp/upload/"; - String uploadFolderPath = path.substring(0, index) + tempPath; + int index; + String uploadFolderPath = getRealPath(); - //创建临时文件夹保存分块文件 - String newTempPath = tempPath + guid + "/"; - //分块文件临时保存路径 - String mergePath = path.substring(0, index) + newTempPath; + String mergePath =uploadFolderPath + guid + "/"; String ext = name.substring(name.lastIndexOf(".")); //判断文件是否分块 if (chunks != null && chunk != null) { - xuhao = Integer.parseInt(chunk); - fileName = String.valueOf(xuhao) + ext; + index = Integer.parseInt(chunk); + fileName = String.valueOf(index) + ext; // 将文件分块保存到临时文件夹里,便于之后的合并文件 saveFile(mergePath, fileName, file); // 验证所有分块是否上传成功,成功的话进行合并 @@ -89,6 +92,7 @@ public String fileUpload(String guid, String md5value, String chunks, String chu } } catch (Exception ex) { + ex.printStackTrace(); return "{\"error\":true}"; } diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/FileUploadController.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/FileUploadController.java index f5c421a..6138bef 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/FileUploadController.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/FileUploadController.java @@ -14,6 +14,7 @@ import java.util.UUID; import static com.zhangzhihao.FileUpload.Java.Utils.CreateMd5.createMd5; +import static com.zhangzhihao.FileUpload.Java.Utils.SaveFile.getRealPath; import static com.zhangzhihao.FileUpload.Java.Utils.SaveFile.saveFile; @@ -36,15 +37,12 @@ public String fileUpload(@RequestParam("id") String id, @RequestParam("lastModifiedDate") String lastModifiedDate, @RequestParam("size") int size, @RequestParam("file") MultipartFile file) { - String fileName = ""; + String fileName; try { - String path = FileUploadController.class.getResource("/").getFile(); - int index = path.indexOf("build"); - String realPath = path.substring(0, index) + "/src/main/webapp/upload/"; String ext = name.substring(name.lastIndexOf(".")); fileName = UUID.randomUUID().toString() + ext; - saveFile(realPath, fileName, file); + saveFile(getRealPath(), fileName, file); } catch (Exception ex) { return "{\"error\":true}"; } diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/ImageUploadController.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/ImageUploadController.java index d4be3ac..1a3fce1 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/ImageUploadController.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/ImageUploadController.java @@ -16,6 +16,7 @@ import static com.zhangzhihao.FileUpload.Java.Utils.CreateMd5.createMd5; import static com.zhangzhihao.FileUpload.Java.Utils.DeepCopy.deepClone; import static com.zhangzhihao.FileUpload.Java.Utils.IsImag.isImage; +import static com.zhangzhihao.FileUpload.Java.Utils.SaveFile.getRealPath; import static com.zhangzhihao.FileUpload.Java.Utils.SaveFile.saveFile; @@ -49,9 +50,7 @@ public String fileUpload(@RequestParam("id") String id, if (!isImage(tempFile)) return "{\"error\":true}"; - String path = ImageUploadController.class.getResource("/").getFile(); - int build = path.indexOf("build"); - String realpath = path.substring(0, build) + "src/main/webapp/upload/"; + String realpath = getRealPath(); String ext = name.substring(name.lastIndexOf(".")); fileName = UUID.randomUUID().toString() + ext; saveFile(realpath, fileName, saveFile); diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/MultiPickerUploadController.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/MultiPickerUploadController.java new file mode 100644 index 0000000..3408c3b --- /dev/null +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Controller/MultiPickerUploadController.java @@ -0,0 +1,46 @@ +package com.zhangzhihao.FileUpload.Java.Controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * Created by 张志豪 on 2016/12/5 0005. + * 多个文件选择器上传文件,一个选择器对应一个文件 + */ +@Controller +@RequestMapping("/MultiPickerUpload") +public class MultiPickerUploadController { + + @GetMapping(value = "/Index") + public String Index() { + return "MultiPicker/Index"; + } + + @PostMapping("/") + public ResponseEntity fileUpload(@RequestParam("type") String type, + @RequestParam("name") String name, + @RequestParam("file") MultipartFile file) throws Exception { + + switch (type) { + case "researchReport": //研究报告 + //save file + break; + case "researchReportStuff": //研究报告支撑材料(限PDF) + //save file + break; + case "applyReport": //应用报告 + //save file + break; + case "applyReportStuff": //应用报告支撑材料(限PDF) + //save file + break; + default: + return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE); + } + return new ResponseEntity<>(HttpStatus.CREATED); + } + +} diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Service/FileService.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Service/FileService.java index 53212b4..edbd5f6 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Service/FileService.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Service/FileService.java @@ -6,6 +6,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import java.util.List; @Service public class FileService extends BaseService { @@ -14,13 +15,13 @@ public class FileService extends BaseService { public boolean isMd5Exist(String md5) { Query query = new Query(entityManager); - Object resultMD5 = query.from(File.class) + @SuppressWarnings("unchecked") List result = query.from(File.class) .select() .whereEqual("MD5", md5) .createTypedQuery() - .getSingleResult(); + .getResultList(); - return resultMD5 != null; + return !result.isEmpty(); } } diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/IsAllUploaded.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/IsAllUploaded.java index 99021e2..edb24e2 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/IsAllUploaded.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/IsAllUploaded.java @@ -8,13 +8,14 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import static com.zhangzhihao.FileUpload.Java.Utils.MergeFile.mergeFile; public class IsAllUploaded { - private static List uploadInfoList; + private final static List uploadInfoList = new ArrayList<>(); /** * @param md5 @@ -30,7 +31,9 @@ public static boolean isAllUploaded(@NotNull final String md5, .size(); boolean bool = (size == Integer.parseInt(chunks)); if (bool) { - uploadInfoList.removeIf(item -> item.getMd5() == md5); + synchronized (uploadInfoList) { + uploadInfoList.removeIf(item -> Objects.equals(item.getMd5(), md5)); + } } return bool; } @@ -53,10 +56,9 @@ public static void Uploaded(@NotNull final String md5, @NotNull final String ext, @NotNull final FileService fileService) throws Exception { - if (uploadInfoList == null) { - uploadInfoList = new ArrayList<>(); + synchronized (uploadInfoList) { + uploadInfoList.add(new UploadInfo(md5, chunks, chunk, uploadFolderPath, fileName, ext)); } - uploadInfoList.add(new UploadInfo(md5, chunks, chunk, uploadFolderPath, fileName, ext)); boolean allUploaded = isAllUploaded(md5, chunks); int chunksNumber = Integer.parseInt(chunks); diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/MergeFile.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/MergeFile.java index 02d2e39..a2cf63a 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/MergeFile.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/MergeFile.java @@ -24,7 +24,7 @@ public static void mergeFile(final int chunksNumber, throws Exception { /*合并输入流*/ String mergePath = uploadFolderPath + guid + "/"; - SequenceInputStream s = null; + SequenceInputStream s ; InputStream s1 = new FileInputStream(mergePath + 0 + ext); InputStream s2 = new FileInputStream(mergePath + 1 + ext); s = new SequenceInputStream(s1, s2); diff --git a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/SaveFile.java b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/SaveFile.java index 6d577a4..333639f 100644 --- a/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/SaveFile.java +++ b/src/main/java/com/zhangzhihao/FileUpload/Java/Utils/SaveFile.java @@ -1,64 +1,130 @@ package com.zhangzhihao.FileUpload.Java.Utils; +import com.zhangzhihao.FileUpload.Java.Controller.FileUploadController; import org.jetbrains.annotations.NotNull; import org.springframework.web.multipart.MultipartFile; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; public class SaveFile { - /** - * - * @param savePath - * @param fileFullName - * @param file - * @return + private static final File uploadDirectory = new File(getRealPath()); + /** + * @param savePath + * @param fileFullName + * @param file + * @return * @throws Exception */ - public static boolean saveFile(@NotNull final String savePath, - @NotNull final String fileFullName, - @NotNull final MultipartFile file) - throws Exception { - byte[] data = readInputStream(file.getInputStream()); - //new一个文件对象用来保存图片,默认保存当前工程根目录 - File uploadFile = new File(savePath + fileFullName); - //判断文件夹是否存在,不存在就创建一个 - File fileDirectory = new File(savePath); - if (!fileDirectory.exists()) { - if (!fileDirectory.mkdir()) { - throw new Exception("文件夹创建失败!路径为:" + savePath); + public static boolean saveFile(@NotNull final String savePath, + @NotNull final String fileFullName, + @NotNull final MultipartFile file) + throws Exception { + byte[] data = readInputStream(file.getInputStream()); + //new一个文件对象用来保存图片,默认保存当前工程根目录 + File uploadFile = new File(savePath + fileFullName); + //判断文件夹是否存在,不存在就创建一个 + File fileDirectory = new File(savePath); + synchronized (uploadDirectory){ + if(!uploadDirectory.exists()){ + if(!uploadDirectory.mkdir()){ + throw new Exception("保存文件的父文件夹创建失败!路径为:" + savePath); + } } - } + if (!fileDirectory.exists()) { + if (!fileDirectory.mkdir()) { + throw new Exception("文件夹创建失败!路径为:" + savePath); + } + } + } + + //创建输出流 + try (FileOutputStream outStream = new FileOutputStream(uploadFile)) {//写入数据 + outStream.write(data); + outStream.flush(); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + return uploadFile.exists(); + } + + public static byte[] readInputStream(InputStream inStream) throws Exception { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + //创建一个Buffer字符串 + byte[] buffer = new byte[1024]; + //每次读取的字符串长度,如果为-1,代表全部读取完毕 + int len; + //使用一个输入流从buffer里把数据读取出来 + while ((len = inStream.read(buffer)) != -1) { + //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 + outStream.write(buffer, 0, len); + } + //关闭输入流 + inStream.close(); + //把outStream里的数据写入内存 + return outStream.toByteArray(); + } + + /** + * 获得绝对路径(不带文件名) + * + * @return + */ + public static String getRealPath() { + String realPath; + String path = FileUploadController.class.getResource("/").getFile(); + int index = path.indexOf("build"); + realPath = path.substring(0, index) + "/src/main/webapp/upload/"; + realPath = realPath.replaceFirst("/", ""); + return realPath; + } - //创建输出流 - try (FileOutputStream outStream = new FileOutputStream(uploadFile)) {//写入数据 - outStream.write(data); - outStream.flush(); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - return uploadFile.exists(); - } + /** + * 根据文件路径获取File + * + * @param filePath + * @return + * @throws IOException + */ + public static java.io.File getFileByPath(String filePath) throws IOException { + Path path = Paths.get(getRealPath() + filePath); + if (Files.exists(path)) { + return new java.io.File(path.toUri()); + } + return null; + } - public static byte[] readInputStream(InputStream inStream) throws Exception { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - //创建一个Buffer字符串 - byte[] buffer = new byte[1024]; - //每次读取的字符串长度,如果为-1,代表全部读取完毕 - int len = 0; - //使用一个输入流从buffer里把数据读取出来 - while ((len = inStream.read(buffer)) != -1) { - //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 - outStream.write(buffer, 0, len); - } - //关闭输入流 - inStream.close(); - //把outStream里的数据写入内存 - return outStream.toByteArray(); - } + /** + * 压缩文件 + * + * @param srcFileList + * @param zipFile + * @throws IOException + */ + public static void zipFiles(List srcFileList, java.io.File zipFile) throws IOException { + byte[] buf = new byte[1024]; + //ZipOutputStream类:完成文件或文件夹的压缩 + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); + + for (java.io.File aSrcFileList : srcFileList) { + FileInputStream in = new FileInputStream(aSrcFileList); + out.putNextEntry(new ZipEntry(aSrcFileList.getName())); + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.closeEntry(); + in.close(); + } + out.close(); + } } diff --git a/src/main/resources/Hibernate.cfg.xml b/src/main/resources/Hibernate.cfg.xml deleted file mode 100644 index d56f2c2..0000000 --- a/src/main/resources/Hibernate.cfg.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - org.hibernate.dialect.MySQL5Dialect - - - - - - - - - true - - true - - update - - - - 2 - - - true - - - - - - - true - - - org.hibernate.cache.SingletonEhCacheRegionFactory - - - - true - - - - \ No newline at end of file diff --git a/src/main/resources/db.properties b/src/main/resources/db.properties index d931eba..065aab9 100644 --- a/src/main/resources/db.properties +++ b/src/main/resources/db.properties @@ -1,7 +1,7 @@ # ݿӲ jdbc.driverClass=com.mysql.jdbc.Driver -jdbc.connectionURL=jdbc:mysql://10.16.155.241:8081/FileUpload?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC +jdbc.connectionURL=jdbc:mysql:///FileUpload?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC jdbc.userName=root -jdbc.password=root +jdbc.password= jdbc.initPoolSize=5 jdbc.maxPoolSize=10 diff --git a/src/main/webapp/WEB-INF/views/BigFileUpload/Index.jsp b/src/main/webapp/WEB-INF/views/BigFileUpload/Index.jsp index 11f441a..d2d9209 100644 --- a/src/main/webapp/WEB-INF/views/BigFileUpload/Index.jsp +++ b/src/main/webapp/WEB-INF/views/BigFileUpload/Index.jsp @@ -38,7 +38,7 @@ //formData: { guid: WebUploader.guid() }, //一个文件有一个guid,在服务器端合并成一个文件 这里有个问题,多个文件或者上传一个文件成功后不刷新直接添加文件上传生成的guid不变!!! 暂时只能传一个大文件(已解决) //fileNumLimit :1, fileSizeLimit: 2000 * 1024 * 1024,//最大2GB - fileSingleSizeLImit: 2000 * 1024 * 1024, + fileSingleSizeLimit: 2000 * 1024 * 1024, resize: false//不压缩 @@ -51,15 +51,12 @@ //} }); - - - // 当有文件被添加进队列的时候 uploader.on('fileQueued', function (file) { $list.append('
' + '

' + file.name + '

' + - '

等待上传...

' + - '
');//id="' + file.id + 'btn" + '

正在计算文件MD5...请等待计算完毕后再点击上传!

' + + ''); //删除要上传的文件 //每次添加文件都给btn-delete绑定删除方法 $(".btn-delete").click(function () { @@ -78,6 +75,9 @@ //insertLog("
" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file preupload:计算文件(" + file.name + ")MD5完成. 耗时 " + (end - start) + '毫秒 fileMd5: ' + fileMd5); file.wholeMd5 = fileMd5;//获取到了md5 uploader.options.formData.md5value = file.wholeMd5;//每个文件都附带一个md5,便于实现秒传 + + $('#' + file.id).find('p.state').text('MD5计算完毕,可以点击上传了'); + $.ajax({//向服务端发送请求 cache: false, type: "post", @@ -195,23 +195,13 @@ } }); - - - uploader.on('uploadAccept', function (file, response) { - //if (uploader.errorCode) { - // // 通过return false来告诉组件,此文件上传有错。 - // return false; - //} - if (response._raw == '{"error":true}') { + if (response._raw === '{"error":true}') { return false; } }); }); - - - diff --git a/src/main/webapp/WEB-INF/views/MultiPicker/Index.jsp b/src/main/webapp/WEB-INF/views/MultiPicker/Index.jsp new file mode 100644 index 0000000..22fb050 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/MultiPicker/Index.jsp @@ -0,0 +1,233 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + 多选择器多文件上传 + + + + + + + + + + +
+ +
+ +

提示

+

只能上传四个文件,只支持以下后缀名的文件doc,docx,pdf,zip,rar,7z。如果需要上传其他文件(如图片)请压缩后上传。请依次点击按钮上传指定文件,如果添加了错误的文件可以删除。

+
+ +
+
+
+ +
+
+
+
+
+
+ 选择研究报告 + +
+
+
+
+ +
+
+
+
+ 选择研究报告支撑材料(限PDF) + +
+
+
+
+ +
+
+
+
+ 选择应用报告 + +
+
+
+
+ +
+
+
+
+ 选择应用报告支撑材料(限PDF) + +
+
+
+
+ +
+
+
开始上传所选文件
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index 376ecc1..d593fa4 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -10,5 +10,6 @@ 文件上传 图片上传 大文件上传 +多选择器多文件上传