热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

序言现在,绝大部分的应用程序在很多的情况下都需要使用到文件上传与下载的功能,在本文中结合hap利用spirngmvc实现文件的上传和下载,

序言

现在,绝大部分的应用程序在很多的情况下都需要使用到文件上传与下载的功能,在本文中结合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 @Id34 35 @GeneratedValue36 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 IMG_TYPE = Arrays.asList("jpg", "jpeg", "png", "bmp");
152
153 /**
154
155 * 允许上传的文档格式
156
157 */
158
159 public static final List DOC_TYPE = Arrays.asList("pdf", "doc", "docx");
160
161 /**
162
163 * ContentType
164
165 */
166
167 public static final Map EXT_MAPS &#61; 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 * &#64;author jiaqing.xu&#64;hand-china.com
200
201 * &#64;date 2017/9/4 17:23
202
203 * &#64;param wordFile photoFile fruitName
204
205 * &#64;return List
206
207 * &#64;description 保存水果信息
208
209 */
210
211 &#64;RequestMapping(value &#61; {"/api/public/upload/fruit/submit"}, method &#61; RequestMethod.POST)
212
213 &#64;ResponseBody
214
215 public List fruitSubmit(&#64;RequestParam(value &#61; "wordFile", required &#61; true) MultipartFile wordFile,&#64;RequestParam(value &#61; "photoFile", required &#61; true) MultipartFile photoFile, &#64;RequestParam(value&#61;"fruitName",required &#61; true) String fruitName,HttpServletRequest request){
216
217 IRequest requestContext &#61; createRequestContext(request);
218
219 //上传word文件到磁盘
220
221 Map result1 &#61; uploadFile(wordFile,wordFilePath,DOC_TYPE,null);
222
223 //上传图片文件到磁盘
224
225 Map result2 &#61; uploadFile(photoFile,userPhotoPath, IMG_TYPE, 200);
226
227
228
229 List list &#61; new ArrayList<>();
230
231 //如果创建成功则保存相应路径到数据库
232
233 if((boolean)result1.get("success")&&(boolean)result2.get("success")){
234
235 Fruit fruit &#61; 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 &#61; service.insertSelective(requestContext,fruit);
251 list.add(fruit);
253 }
255 return list;
256
257 }
258
259
260
261 /**
262
263 * &#64;author jiaqing.xu&#64;hand-china.com
264
265 * &#64;date 2017/9/4 16:18
266
267 * &#64;param
268
269 * &#64;return
270
271 * &#64;description 【通用】 上传文件到磁盘的某一个目录
272
273 */
274
275 public Map uploadFile(MultipartFile file, String path, List fileTypes, Integer ratio){
276
277 Map results &#61; new HashMap<>();
278
279 results.put("success", false);
280
281 if(file &#61;&#61; 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", "文件最大不超过" &#43; FILE_MAX_SIZE/1024/1024 &#43; "M");
292
293 return results;
294
295 }
296
297 String originalFilename &#61; file.getOriginalFilename();
298
299 if(!fileTypes.contains(originalFilename.substring(originalFilename.lastIndexOf(".")&#43;1))){
300
301 results.put("message", "文件格式不正确");
302
303 return results;
304
305 }
306
307 SimpleDateFormat formatter &#61; new SimpleDateFormat("yyyyMMddHHmmssSSS");
308
309 String datetime &#61; formatter.format(new Date());
310
311 String yearmonth &#61; datetime.substring(0, 6);
312
313 // 在基础路径上加上年月路径
314
315 String fileDir &#61; path &#43; "/" &#43; yearmonth;
316
317 // 文件名以 [_时间戳_随机数#原文件名]的形式 随机数防止重复文件名
318
319 String randomNumber &#61; String.valueOf((Math.random() * 90000) &#43; 10000).substring(0, 5);
320
321 String fileName &#61; "_" &#43; datetime &#43; randomNumber &#43; "&#61;" &#43; originalFilename;
322
323 // 文件路径
324
325 String filePath &#61; fileDir &#43; "/" &#43; fileName;
326
329 try {
330
331 // 创建目录
332
333 File dir &#61; new File(fileDir);
334
335 if(!dir.exists() && !dir.isDirectory()){
336
337 dir.mkdirs();
338
339 }
340
341 // 文件输入流
342
343 InputStream is &#61; file.getInputStream();
344
345 // 输出流
346
347 OutputStream os &#61; new FileOutputStream(filePath);
348
349 // 输出文件到磁盘
350
351 int len &#61; 0;
352
353 byte[] buffer &#61; new byte[2048];
354
355 while((len &#61; is.read(buffer, 0, 2048)) !&#61; -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 !&#61; null){
382
383 //ImgExif.ExifInfoToRotate(filePath);
384
385 ImgCompress imgCompress &#61; 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 * &#64;author jiaqing.xu&#64;hand-china.com
416
417 * &#64;date 2017/9/4 17:23
418
419 * &#64;param
420
421 * &#64;return
422
423 * &#64;description 【通用】 读取上传的文件 将文件以流的形式输出
424
425 */
426
427 &#64;RequestMapping(value &#61; "/api/public/read/file")
428
429 public void readFile(&#64;RequestParam String path, HttpServletResponse response) throws FileReadIOException, TokenException {
430
431 Map results &#61; new HashMap<>();
432
433 try {
434
435 File file &#61; new File(path);
436
437 if(!file.exists()){
438
439 results.put("success", false);
440
441 results.put("message", "文件不存在");
442
443 JSONObject jsonObject &#61; JSONObject.fromObject(results);
444
445 response.getWriter().write(jsonObject.toString());
446
447 return;
448
449 }
450
451 // 类型
452
453 String contentType &#61; EXT_MAPS.get(path.substring(path.lastIndexOf(".") &#43; 1));
454
455 // 设置头
456
457 response.addHeader("Content-Disposition", "attachment;filename&#61;\"" &#43; URLEncoder.encode(path.substring(path.indexOf("&#61;") &#43; 1), "UTF-8") &#43; "\"");
458
459 response.setContentType(contentType &#43; ";charset&#61;UTF-8");
460
461 response.setHeader("Accept-Ranges", "bytes");
462
463 // 输出文件
464
465 InputStream is &#61; new FileInputStream(file);
466
467 OutputStream os &#61; response.getOutputStream();
468
469 int len &#61; 0;
470
471 byte[] buffer &#61; new byte[2048];
472
473 while ((len &#61; is.read(buffer, 0, 2048)) !&#61; -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 }

 

 

说明&#xff1a;

&#xff08;1&#xff09;文件保存路径wordFilePath、 水果照片保存路径userPhotoPath可以通过配置文件进行配置。 

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

3.  postman测试

 

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

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

4.  运行结果

数据库中插入的新的记录&#xff1a;

 

磁盘中的word文件&#xff1a;

 

磁盘中的图片&#xff1a;

 

 

 

浏览器进行下载测试&#xff1a;

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

 

 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
author-avatar
abc
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有