基于Java实现的通用文件上传和下载

序言

现在,绝大部分的应用程序在很多的情况下都需要使用到文件上传与下载的功能,在本文中结合hap利用spirng mvc实现文件的上传和下载,包括上传下载图片、上传下载文档。前端所使用的技术不限,本文重点在于后端代码的实现。希望可以跟随我的一步步实践,最终轻松掌握在hap中的文件上传和下载的具体实现。

案例

1.  数据库设计

表结构

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------

-- Table structure for tb_fruit

-- ----------------------------

DROP TABLE IF EXISTS `tb_fruit`;

CREATE TABLE `tb_fruit` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `fruitName` varchar(255) DEFAULT NULL,

  `picturePath` varchar(255) DEFAULT NULL,

  `filePath` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

字段描述

Id 主键自增

fruitName 水果名称

picturePath 图片路径

filePath 附件2.  先使用代码生成工具根据表结构生成对应的测试 

 dto层:

  2 
  3 package hbi.core.test.dto;
  4 
  5 /**Auto Generated By Hap Code Generator**/
  6 
  7 import com.hand.hap.mybatis.annotation.ExtensionAttribute;
  8 
  9 import org.hibernate.validator.constraints.Length;
 10 
 11 import javax.persistence.GeneratedValue;
 12 
 13 import javax.persistence.Id;
 14 
 15 import javax.persistence.Table;
 16 
 17 @Table(name = "tb_fruit")
 18 
 19 public class Fruit{
 20 
 21  
 22 
 23      public static final String FIELD_ID = "id";
 24 
 25      public static final String FIELD_FRUITNAME = "fruitname";
 26 
 27      public static final String FIELD_PICTUREPATH = "picturepath";
 28 
 29      public static final String FIELD_FILEPATH = "filepath";
 30 
 31  
 32 
 33      @Id
 34 
 35      @GeneratedValue
 36 
 37      private Long id;
 38 
 39  
 40 
 41      @Length(max = 255)
 42 
 43      private String fruitname;
 44 
 45  
 46 
 47      @Length(max = 255)
 48 
 49      private String picturepath;
 50 
 51  
 52 
 53     @Length(max = 255)
 54 
 55 private String filepath;
 56 
 57 //省略get/set方法...
 58 
 59 }
 60 


controller层:
 69 package hbi.core.test.controllers;
 70 
 71 import com.hand.hap.attachment.exception.FileReadIOException;
 72 
 73 import com.hand.hap.core.IRequest;
 74 
 75 import com.hand.hap.core.exception.TokenException;
 76 
 77 import com.hand.hap.system.controllers.BaseController;
 78 
 79 import com.hand.hap.system.dto.ResponseData;
 80 
 81 import hbi.core.test.dto.Fruit;
 82 
 83 import hbi.core.test.service.IFruitService;
 84 
 85 import net.sf.json.JSONObject;
 86 
 87 import org.apache.commons.lang.StringUtils;
 88 
 89 import org.springframework.beans.factory.annotation.Autowired;
 90 
 91 import org.springframework.stereotype.Controller;
 92 
 93 import org.springframework.validation.BindingResult;
 94 
 95 import org.springframework.web.bind.annotation.*;
 96 
 97 import org.springframework.web.multipart.MultipartFile;
 98 
 99 import javax.servlet.http.HttpServletRequest;
100 
101 import javax.servlet.http.HttpServletResponse;
102 
103 import java.io.*;
104 
105 import java.net.URLEncoder;
106 
107 import java.text.SimpleDateFormat;
108 
109 import java.util.*;
110 
111  
112 
113 @Controller
114 
115 public class FruitController extends BaseController {
116 
117     @Autowired
118 
119     private IFruitService service;
120 
121     /**
122 
123      * word文件路径
124 
125      */
126 
127     private String wordFilePath="/u01/document/userfile";
128 
129     /**
130 
131      * 图片文件路径
132 
133      */
134 
135     private String userPhotoPath = "/u01/document/userphoto";
136 
137     /**
138 
139      * 文件最大 5M
140 
141      */
142 
143     public static final Long FILE_MAX_SIZE = 5*1024*1024L;
144 
145     /**
146 
147      * 允许上传的图片格式
148 
149      */
150 
151     public static final List<String> IMG_TYPE = Arrays.asList("jpg", "jpeg", "png", "bmp");
152 
153     /**
154 
155      * 允许上传的文档格式
156 
157      */
158 
159     public static final List<String> DOC_TYPE = Arrays.asList("pdf", "doc", "docx");
160 
161     /**
162 
163      * ContentType
164 
165      */
166 
167     public static final Map<String, String> EXT_MAPS = new HashMap<>();
168 
169     static {
170 
171         // image
172 
173         EXT_MAPS.put("jpg", "image/jpeg");
174 
175         EXT_MAPS.put("jpeg", "image/jpeg");
176 
177         EXT_MAPS.put("png", "image/png");
178 
179         EXT_MAPS.put("bmp", "image/bmp");
180 
181         // doc
182 
183         EXT_MAPS.put("pdf", "application/pdf");
184 
185         EXT_MAPS.put("ppt", "application/vnd.ms-powerpoint");
186 
187         EXT_MAPS.put("doc", "application/msword");
188 
189         EXT_MAPS.put("doc", "application/wps-office.doc");
190 
191         EXT_MAPS.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
192 
193     }
194 
195  
196 
197     /**
198 
199      * @author jiaqing.xu@hand-china.com
200 
201      * @date 2017/9/4 17:23
202 
203      * @param wordFile  photoFile fruitName
204 
205      * @return List<Fruit>
206 
207      * @description 保存水果信息
208 
209      */
210 
211     @RequestMapping(value = {"/api/public/upload/fruit/submit"}, method = RequestMethod.POST)
212 
213     @ResponseBody
214 
215     public List<Fruit> fruitSubmit(@RequestParam(value = "wordFile", required = true) MultipartFile wordFile,@RequestParam(value = "photoFile", required = true) MultipartFile photoFile, @RequestParam(value="fruitName",required = true) String fruitName,HttpServletRequest request){
216 
217         IRequest requestContext = createRequestContext(request);
218 
219         //上传word文件到磁盘
220 
221         Map<String,Object> result1 = uploadFile(wordFile,wordFilePath,DOC_TYPE,null);
222 
223         //上传图片文件到磁盘
224 
225         Map<String, Object> result2 = uploadFile(photoFile,userPhotoPath, IMG_TYPE, 200);
226 
227  
228 
229         List<Fruit> list = new ArrayList<>();
230 
231         //如果创建成功则保存相应路径到数据库
232 
233         if((boolean)result1.get("success")&&(boolean)result2.get("success")){
234 
235             Fruit fruit = new Fruit();
236 
237             fruit.setFruitname(fruitName);
238 
239             //设置图片路径
240 
241             fruit.setPicturepath((String) result2.get("path"));
242 
243             //设置附件路径
244 
245             fruit.setFilepath((String) result1.get("path"));
246 
247             //插入
249             fruit = service.insertSelective(requestContext,fruit);
251             list.add(fruit);
253         }
255         return list;
256 
257     }
258 
259  
260 
261     /**
262 
263      * @author jiaqing.xu@hand-china.com
264 
265      * @date 2017/9/4 16:18
266 
267      * @param
268 
269      * @return
270 
271      * @description  【通用】 上传文件到磁盘的某一个目录
272 
273      */
274 
275     public Map<String, Object> uploadFile(MultipartFile file, String path, List<String> fileTypes, Integer ratio){
276 
277         Map<String, Object> results = new HashMap<>();
278 
279         results.put("success", false);
280 
281         if(file == null || file.getSize() < 0 || StringUtils.isBlank(file.getOriginalFilename())){
282 
283             results.put("message", "文件为空");
284 
285             return results;
286 
287         }
288 
289         if(file.getSize() > FILE_MAX_SIZE){
290 
291             results.put("message", "文件最大不超过" + FILE_MAX_SIZE/1024/1024 + "M");
292 
293             return results;
294 
295         }
296 
297         String originalFilename = file.getOriginalFilename();
298 
299         if(!fileTypes.contains(originalFilename.substring(originalFilename.lastIndexOf(".")+1))){
300 
301             results.put("message", "文件格式不正确");
302 
303             return results;
304 
305         }
306 
307         SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");
308 
309         String datetime = formatter.format(new Date());
310 
311         String yearmonth = datetime.substring(0, 6);
312 
313         // 在基础路径上加上年月路径
314 
315         String fileDir = path + "/" + yearmonth;
316 
317         // 文件名以 [_时间戳_随机数#原文件名]的形式 随机数防止重复文件名
318 
319         String randomNumber = String.valueOf((Math.random() * 90000) + 10000).substring(0, 5);
320 
321         String fileName = "_" + datetime + randomNumber + "=" + originalFilename;
322 
323         // 文件路径
324 
325         String filePath = fileDir + "/" + fileName;
326 
329         try {
330 
331             // 创建目录
332 
333             File dir = new File(fileDir);
334 
335             if(!dir.exists() && !dir.isDirectory()){
336 
337                 dir.mkdirs();
338 
339             }
340 
341             // 文件输入流
342 
343             InputStream is = file.getInputStream();
344 
345             // 输出流
346 
347             OutputStream os = new FileOutputStream(filePath);
348 
349             // 输出文件到磁盘
350 
351             int len = 0;
352 
353             byte[] buffer = new byte[2048];
354 
355             while((len = is.read(buffer, 0, 2048)) != -1){
356 
357                 os.write(buffer, 0, len);
358 
359             }
360 
361             os.flush();
362 
363             os.close();
364 
365             is.close();
366
368 
369             //向结果中保存状态消息和存储路径
370 
371             results.put("success", true);
372 
373             results.put("message", "SUCCESS");
374 
375             results.put("path", filePath);
376 
377  
378 
379             // 压缩图片
380 
381             if(ratio != null){
382 
383                 //ImgExif.ExifInfoToRotate(filePath);
384 
385                 ImgCompress imgCompress = new ImgCompress(filePath);
386 
387                 imgCompress.setFileName(filePath);
388 
389                 imgCompress.resizeByWidth(ratio);
390 
391             }
392 
393         } catch (Exception e) {
394 
395             e.printStackTrace();
396 
397             results.put("message", "ERROR");
398 
399             return results;
400 
401         }
402 
403  
404 
405         return results;
406 
407     }
408 
413     /**
414 
415      * @author jiaqing.xu@hand-china.com
416 
417      * @date 2017/9/4 17:23
418 
419      * @param
420 
421      * @return
422 
423      * @description  【通用】 读取上传的文件  将文件以流的形式输出
424 
425      */
426 
427     @RequestMapping(value = "/api/public/read/file")
428 
429     public void readFile(@RequestParam String path, HttpServletResponse response) throws FileReadIOException, TokenException {
430 
431         Map<String, Object> results = new HashMap<>();
432 
433         try {
434 
435             File file = new File(path);
436 
437             if(!file.exists()){
438 
439                 results.put("success", false);
440 
441                 results.put("message", "文件不存在");
442 
443                 JSONObject jsonObject = JSONObject.fromObject(results);
444 
445                 response.getWriter().write(jsonObject.toString());
446 
447                 return;
448 
449             }
450 
451             // 类型
452 
453             String contentType = EXT_MAPS.get(path.substring(path.lastIndexOf(".") + 1));
454 
455             // 设置头
456 
457             response.addHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(path.substring(path.indexOf("=") + 1), "UTF-8") + "\"");
458 
459             response.setContentType(contentType + ";charset=UTF-8");
460 
461             response.setHeader("Accept-Ranges", "bytes");
462 
463             // 输出文件
464 
465             InputStream is = new FileInputStream(file);
466 
467             OutputStream os = response.getOutputStream();
468 
469             int len = 0;
470 
471             byte[] buffer = new byte[2048];
472 
473             while ((len =  is.read(buffer, 0, 2048)) != -1){
474 
475                 os.write(buffer, 0, len);
476 
477             }
478 
479             os.flush();
480 
481             os.close();
482 
483             is.close();
484 
485         } catch (IOException e) {
487             e.printStackTrace();
489         }
491     }
493 }

 

 

说明:

(1)文件保存路径wordFilePath、 水果照片保存路径userPhotoPath可以通过配置文件进行配置。 

(2)其中保存的文件的路径在项目的根路径下,比如我的项目在D盘的某一个文件夹下,则生成的word文件的位置为D盘/u01/document/userfile路径下.

3.  postman测试

 

注意点:在使用postman测试时,使用post请求,参数中body为form-data,依次将需要的参数填写到对应的位置。

返回后的数据为插入数据库中的记录。

4.  运行结果

数据库中插入的新的记录:

 

磁盘中的word文件:

 

磁盘中的图片:

 

 

 

浏览器进行下载测试:

http://localhost:8080/api/public/read/file?path=/u01/document/userphoto/201709/_2017090417503366053845=大西瓜.jpg

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值