package com.chenyanwu.erp.erpframework.controller.upload; import com.chenyanwu.erp.erpframework.common.ResultBean; import com.chenyanwu.erp.erpframework.service.impl.upload.WaterMarkImpl; import com.chenyanwu.erp.erpframework.service.upload.WaterMarkTemplate; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.math.BigInteger; import java.nio.channels.FileChannel; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.*; /** * @Auther: chenyanwu * @Date: 2019/5/9 10:35 * @Description: * @Version 1.0 */ @Controller @RequestMapping("/fileupload") public class UploadFileController { @Value("${file.temppath}") private String TEMP_PATH; @Value("${file.path}") private String REAL_PATH; @Value("${file.repath}") private String RE_DRAWING_PATH; /** * 每个块的命名衔接符,便于根据块名找到块序号 */ private static final String CHUNK_NAME_SPLIT = "_"; /** * 块文件后缀 */ private static final String SUFFIX = ".part"; /** * 分片大小 */ private static final Integer CHUNK_SIZE = 5 * 1024 * 1024; /** * 图片支持格式 */ private static final String PHOTO_TYPE = "jpg,pne"; /** * 视频支持格式 */ private static final String VIDEO_TYPE = "rm,rmvb,mpeg1-4,mov,mtv,dat,wmv,avi,3gp,amv,dmv,flv,exe"; @RequestMapping(value = "/videolist", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ModelAndView list(HttpServletRequest request, HttpServletResponse response) { ModelAndView modelAndView = new ModelAndView("/upload/uploadvideo"); modelAndView.addObject("typeList", VIDEO_TYPE); modelAndView.addObject("button", "多视频上传"); return modelAndView; } @RequestMapping(value = "/photolist", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ModelAndView photoList(HttpServletRequest request, HttpServletResponse response) { ModelAndView modelAndView = new ModelAndView("/upload/uploadphoto"); modelAndView.addObject("typeList", PHOTO_TYPE); modelAndView.addObject("button", "多图片上传"); return modelAndView; } @RequestMapping(value = "/upload", produces = "application/json; charset=utf-8") @ResponseBody public double upload(MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception { try { //文件名 String name = request.getParameter("name"); //文件块数 String chunks = request.getParameter("chunks"); //文件MD5值 String fileMd5 = request.getParameter("fileMd5"); //块号 String chunk = request.getParameter("chunk"); if (null != file) { //开始时间 long startTime = System.currentTimeMillis(); //判断上传的文件是否被分片(小于5M的不会分片) if (null == chunks && null == chunk) { //没有被切片 File realFile = new File(REAL_PATH, name); //如果下载路径不存在则新建,否则删除原有的文件 if (!realFile.getParentFile().exists()) { realFile.getParentFile().mkdirs(); } if (realFile.exists()) { realFile.delete(); } //上传 file.transferTo(realFile); //创建文件 realFile.createNewFile(); //如果是图片加水印 reDrawingPhoto(realFile, "ERP", null, RE_DRAWING_PATH); //实际上传文件大小(单位KB) long size1 = realFile.length() / 1024; //结束时间 long endTime = System.currentTimeMillis(); //速度(KB/s) double speed = size1 * 1000 / ((endTime - startTime)); System.out.println("大小:" + size1 + "KB 开始时间:" + new Date(startTime) + " 结束时间:" + new Date(endTime) + " 平均速度:" + speed + "KB/s"); return speed; } //存储分片临时文件夹 String tempFileDir = TEMP_PATH + File.separator + fileMd5; File parentFileDir = new File(tempFileDir); if (!parentFileDir.exists()) { parentFileDir.mkdirs(); } //碎片文件(按分片序号命名(fileMd5_chunk_.part)便于排序) File partF = new File(tempFileDir + File.separator + fileMd5 + CHUNK_NAME_SPLIT + chunk + CHUNK_NAME_SPLIT + SUFFIX); //mvc文件模块上传填充碎片 //如果已存在,则删除重新写 if (partF.exists()) { partF.delete(); } file.transferTo(partF); //创建碎片 partF.createNewFile(); //碎片大小 long sizePart = partF.length() / 1024; long endTime = System.currentTimeMillis(); //碎片传输速度 double speed = sizePart * 1000 / ((endTime - startTime)); System.out.println("碎片大小:" + sizePart + "KB 开始时间:" + new Date(startTime) + " 结束时间:" + new Date(endTime) + " 平均速度:" + speed + "KB/s"); return speed; } } catch (Exception e) { e.printStackTrace(); throw new Exception("上传出错!"); } return 0; } /** * @param realFile 文件 * @param text 水印文字 * @param integer 旋转 * @param strPath 存放路径 */ private void reDrawingPhoto(File realFile, String text, Integer integer, String strPath) { WaterMarkTemplate wm = new WaterMarkImpl(); wm.watermark(realFile, realFile.getName(), text, integer, strPath); } @RequestMapping(value = "/combine", produces = "application/json; charset=utf-8") @ResponseBody public ResultBean combine(String name, HttpServletRequest request, HttpServletResponse response) throws Exception { String fileMd5 = request.getParameter("fileMd5"); String size = request.getParameter("size"); //没有分片的文件 if (size != null && Integer.parseInt(size) < CHUNK_SIZE) { return new ResultBean(name + "上传成功!"); } // 所有分片文件都上传完成 // 将所有分片文件合并到一个文件中 File tempFileDir = new File(TEMP_PATH + File.separator + fileMd5); //获取文件夹里所有碎片文件 File[] fileArray = tempFileDir.listFiles(new FileFilter() { //排除目录只要文件 @Override public boolean accept(File pathname) { // TODO Auto-generated method stub if (pathname.isDirectory()) { return false; } return true; } }); if (fileArray == null || fileArray.length == 0) { return new ResultBean(); } //转成集合,便于排序 List<File> fileList = new ArrayList<>(Arrays.asList(fileArray)); Collections.sort(fileList, new Comparator<File>() { @Override public int compare(File o1, File o2) { // TODO Auto-generated method stub if (Integer.parseInt(o1.getName().split(CHUNK_NAME_SPLIT)[1]) < Integer.parseInt(o2.getName().split(CHUNK_NAME_SPLIT)[1])) { return -1; } return 1; } }); //synchronized (this) { File destTempFile = new File(REAL_PATH, name); if (!destTempFile.getParentFile().exists()) { destTempFile.getParentFile().mkdirs(); } FileOutputStream destTempfos = new FileOutputStream(destTempFile, true); //输出流通道NIO FileChannel outChnnel = destTempfos.getChannel(); //输入流通道NIO FileChannel inChannel; //合并 for (File file : fileList) { inChannel = new FileInputStream(file).getChannel(); inChannel.transferTo(0, inChannel.size(), outChnnel); inChannel.close(); //删除分片 file.delete(); } outChnnel.close(); //关闭流 destTempfos.close(); //删除文件夹 if (tempFileDir.isDirectory() && tempFileDir.exists()) { FileUtils.deleteDirectory(tempFileDir); } return new ResultBean(name + "上传成功!"); } /** * 检验分片是否未上传或者未完成 * result.header.status=0是已上传完整,否则为1 * * @param request * @param response * @return * @throws Exception */ @RequestMapping(value = "/checkChunk", produces = "application/json; charset=utf-8") @ResponseBody public ResultBean checkChunk(HttpServletRequest request, HttpServletResponse response) throws Exception { //检查当前分块是否上传成功 String fileMd5 = request.getParameter("fileMd5"); String chunk = request.getParameter("chunk"); String chunkSize = request.getParameter("chunkSize"); String dir = TEMP_PATH + File.separator + fileMd5; String partName = fileMd5 + CHUNK_NAME_SPLIT + chunk + CHUNK_NAME_SPLIT; String suffix = ".part"; File checkFile = new File(dir + File.separator + partName + suffix); //检查文件是否存在,且大小是否一致 if (checkFile.exists() && checkFile.length() == Integer.parseInt(chunkSize)) { //上传过 return new ResultBean("上传过"); } else { //没有上传过 return new ResultBean(); } } /** * 文件上传前根据MD5检查 * 上传过实现秒传 * * @param request * @param response * @return * @throws Exception */ @RequestMapping(value = "/checkFile", produces = "application/json; charset=utf-8") @ResponseBody public ResultBean checkFile(HttpServletRequest request, HttpServletResponse response) throws Exception { //检查当前分块是否上传成功 String fileMd5 = request.getParameter("fileMd5"); String fileName = request.getParameter("fileName"); String path = REAL_PATH + File.separator + fileName; FileInputStream inputStream = new FileInputStream(new File(path)); MessageDigest md = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[1024]; int length = -1; while ((length = inputStream.read(buffer, 0, 1024)) != -1) { md.update(buffer, 0, length); } BigInteger bigInt = new BigInteger(1, md.digest()); String realFileMD5 = bigInt.toString(16); if (realFileMD5.equals(fileMd5)) { return new ResultBean("文件已存在!"); } else { return new ResultBean("文件未存在!"); } } @RequestMapping("/uploadImg") @ResponseBody public ResultBean uploadImg(Long classesId, HttpServletRequest request) { List<Map<String, Object>> resultPath = new ArrayList<Map<String, Object>>(); try { // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // Set factory constraints // 设置缓冲区大小,这里是4kb factory.setSizeThreshold(4096); // 设置缓冲区目录 factory.setRepository(null); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Set overall request size constraint // 设置最大文件尺寸,这里是4MB upload.setSizeMax(4194304); // 得到所有的文件 List<FileItem> items = upload.parseRequest(request); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); // 文件夹 String uploadDir = REAL_PATH + File.separator + sdf.format(new Date()); //虚拟路径 String uploadVirPath = TEMP_PATH + File.separator + sdf.format(new Date()); Iterator<FileItem> i = items.iterator(); while (i.hasNext()) { FileItem fi = i.next(); String fileName = fi.getName(); if (fileName != null) { // 解决文件名乱码问题 File fullFile = new File(new String(fi.getName().getBytes(), "utf-8")); File savedFile = new File(uploadDir, fullFile.getName()); if (!savedFile.getParentFile().exists()) { savedFile.getParentFile().mkdir(); } if (!savedFile.exists()) { savedFile.createNewFile(); } Map<String, Object> map = new HashMap<String, Object>(); map.put("url", uploadVirPath + "/" + fullFile.getName()); map.put("fileSize", (fi.getSize())); fi.write(savedFile); resultPath.add(map); } } } catch (Exception e) { e.printStackTrace(); } return new ResultBean(resultPath); } }