基于hap的文件上传和下载
序言
现在,绝大部分的应用程序在很多的情况下都需要使用到文件上传与下载的功能,在本文中结合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层:
package hbi.core.test.dto; /**Auto Generated By Hap Code Generator**/ import com.hand.hap.mybatis.annotation.ExtensionAttribute; import org.hibernate.validator.constraints.Length; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Table(name = "tb_fruit") public class Fruit{ public static final String FIELD_ID = "id"; public static final String FIELD_FRUITNAME = "fruitname"; public static final String FIELD_PICTUREPATH = "picturepath"; public static final String FIELD_FILEPATH = "filepath"; @Id @GeneratedValue private Long id; @Length(max = 255) private String fruitname; @Length(max = 255) private String picturepath; @Length(max = 255) private String filepath; //省略get/set方法... } controller层:
package hbi.core.test.controllers; import com.hand.hap.attachment.exception.FileReadIOException; import com.hand.hap.core.IRequest; import com.hand.hap.core.exception.TokenException; import com.hand.hap.system.controllers.BaseController; import com.hand.hap.system.dto.ResponseData; import hbi.core.test.dto.Fruit; import hbi.core.test.service.IFruitService; import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; @Controller public class FruitController extends BaseController { @Autowired private IFruitService service; /** * word文件路径 */ private String wordFilePath="/u01/document/userfile"; /** * 图片文件路径 */ private String userPhotoPath = "/u01/document/userphoto"; /** * 文件最大 5M */ public static final Long FILE_MAX_SIZE = 5*1024*1024L; /** * 允许上传的图片格式 */ public static final List<String> IMG_TYPE = Arrays.asList("jpg", "jpeg", "png", "bmp"); /** * 允许上传的文档格式 */ public static final List<String> DOC_TYPE = Arrays.asList("pdf", "doc", "docx"); /** * ContentType */ public static final Map<String, String> EXT_MAPS = new HashMap<>(); static { // image EXT_MAPS.put("jpg", "image/jpeg"); EXT_MAPS.put("jpeg", "image/jpeg"); EXT_MAPS.put("png", "image/png"); EXT_MAPS.put("bmp", "image/bmp"); // doc EXT_MAPS.put("pdf", "application/pdf"); EXT_MAPS.put("ppt", "application/vnd.ms-powerpoint"); EXT_MAPS.put("doc", "application/msword"); EXT_MAPS.put("doc", "application/wps-office.doc"); EXT_MAPS.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); } /** * @author jiaqing.xu@hand-china.com * @date 2017/9/4 17:23 * @param wordFile photoFile fruitName * @return List<Fruit> * @description 保存水果信息 */ @RequestMapping(value = {"/api/public/upload/fruit/submit"}, method = RequestMethod.POST) @ResponseBody 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){ IRequest requestContext = createRequestContext(request); //上传word文件到磁盘 Map<String,Object> result1 = uploadFile(wordFile,wordFilePath,DOC_TYPE,null); //上传图片文件到磁盘 Map<String, Object> result2 = uploadFile(photoFile,userPhotoPath, IMG_TYPE, 200); List<Fruit> list = new ArrayList<>(); //如果创建成功则保存相应路径到数据库 if((boolean)result1.get("success")&&(boolean)result2.get("success")){ Fruit fruit = new Fruit(); fruit.setFruitname(fruitName); //设置图片路径 fruit.setPicturepath((String) result2.get("path")); //设置附件路径 fruit.setFilepath((String) result1.get("path")); //插入
fruit = service.insertSelective(requestContext,fruit);
list.add(fruit);
}
return list; } /** * @author jiaqing.xu@hand-china.com * @date 2017/9/4 16:18 * @param * @return * @description 【通用】 上传文件到磁盘的某一个目录 */ public Map<String, Object> uploadFile(MultipartFile file, String path, List<String> fileTypes, Integer ratio){ Map<String, Object> results = new HashMap<>(); results.put("success", false); if(file == null || file.getSize() < 0 || StringUtils.isBlank(file.getOriginalFilename())){ results.put("message", "文件为空"); return results; } if(file.getSize() > FILE_MAX_SIZE){ results.put("message", "文件最大不超过" + FILE_MAX_SIZE/1024/1024 + "M"); return results; } String originalFilename = file.getOriginalFilename(); if(!fileTypes.contains(originalFilename.substring(originalFilename.lastIndexOf(".")+1))){ results.put("message", "文件格式不正确"); return results; } SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS"); String datetime = formatter.format(new Date()); String yearmonth = datetime.substring(0, 6); // 在基础路径上加上年月路径 String fileDir = path + "/" + yearmonth; // 文件名以 [_时间戳_随机数#原文件名]的形式 随机数防止重复文件名 String randomNumber = String.valueOf((Math.random() * 90000) + 10000).substring(0, 5); String fileName = "_" + datetime + randomNumber + "=" + originalFilename; // 文件路径 String filePath = fileDir + "/" + fileName; try { // 创建目录 File dir = new File(fileDir); if(!dir.exists() && !dir.isDirectory()){ dir.mkdirs(); } // 文件输入流 InputStream is = file.getInputStream(); // 输出流 OutputStream os = new FileOutputStream(filePath); // 输出文件到磁盘 int len = 0; byte[] buffer = new byte[2048]; while((len = is.read(buffer, 0, 2048)) != -1){ os.write(buffer, 0, len); } os.flush(); os.close(); is.close(); //向结果中保存状态消息和存储路径 results.put("success", true); results.put("message", "SUCCESS"); results.put("path", filePath); // 压缩图片 if(ratio != null){ //ImgExif.ExifInfoToRotate(filePath); ImgCompress imgCompress = new ImgCompress(filePath); imgCompress.setFileName(filePath); imgCompress.resizeByWidth(ratio); } } catch (Exception e) { e.printStackTrace(); results.put("message", "ERROR"); return results; } return results; } /** * @author jiaqing.xu@hand-china.com * @date 2017/9/4 17:23 * @param * @return * @description 【通用】 读取上传的文件 将文件以流的形式输出 */ @RequestMapping(value = "/api/public/read/file") public void readFile(@RequestParam String path, HttpServletResponse response) throws FileReadIOException, TokenException { Map<String, Object> results = new HashMap<>(); try { File file = new File(path); if(!file.exists()){ results.put("success", false); results.put("message", "文件不存在"); JSONObject jsonObject = JSONObject.fromObject(results); response.getWriter().write(jsonObject.toString()); return; } // 类型 String contentType = EXT_MAPS.get(path.substring(path.lastIndexOf(".") + 1)); // 设置头 response.addHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(path.substring(path.indexOf("=") + 1), "UTF-8") + "\""); response.setContentType(contentType + ";charset=UTF-8"); response.setHeader("Accept-Ranges", "bytes"); // 输出文件 InputStream is = new FileInputStream(file); OutputStream os = response.getOutputStream(); int len = 0; byte[] buffer = new byte[2048]; while ((len = is.read(buffer, 0, 2048)) != -1){ os.write(buffer, 0, len); } os.flush(); os.close(); is.close(); } catch (IOException e) {
e.printStackTrace();
}
}
}
说明:
(1)文件保存路径wordFilePath、 水果照片保存路径userPhotoPath可以通过配置文件进行配置。
(2)其中保存的文件的路径在项目的根路径下,比如我的项目在D盘的某一个文件夹下,则生成的word文件的位置为D盘/u01/document/userfile路径下.
3. postman测试
注意点:在使用postman测试时,使用post请求,参数中body为form-data,依次将需要的参数填写到对应的位置。
返回后的数据为插入数据库中的记录。
4. 运行结果
数据库中插入的新的记录:
磁盘中的word文件:
磁盘中的图片:
浏览器进行下载测试:
基于hap的文件上传和下载的更多相关文章
- 基于jsp的文件上传和下载
参考: 一.JavaWeb学习总结(五十)--文件上传和下载 此文极好,不过有几点要注意: 1.直接按照作者的代码极有可能listfile.jsp文件中 <%@taglib prefix=&qu ...
- koa2基于stream(流)进行文件上传和下载
阅读目录 一:上传文件(包括单个文件或多个文件上传) 二:下载文件 回到顶部 一:上传文件(包括单个文件或多个文件上传) 在之前一篇文章,我们了解到nodejs中的流的概念,也了解到了使用流的优点,具 ...
- java web学习总结(二十四) -------------------Servlet文件上传和下载的实现
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- (转载)JavaWeb学习总结(五十)——文件上传和下载
源地址:http://www.cnblogs.com/xdp-gacl/p/4200090.html 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传 ...
- JavaWeb学习总结,文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- java文件上传和下载
简介 文件上传和下载是java web中常见的操作,文件上传主要是将文件通过IO流传放到服务器的某一个特定的文件夹下,而文件下载则是与文件上传相反,将文件从服务器的特定的文件夹下的文件通过IO流下载到 ...
- JavaWeb学习总结(五十)——文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb——文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb学习 (二十八)————文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
随机推荐
- SpringBoot 2 快速整合 | 统一异常处理
统一异常处理相关注解介绍 @ControllerAdvice 声明在类上用于指定该类为控制增强器类,如果想声明返回的结果为 RESTFull 风格的数据,需要在声明 @ExceptionHandler ...
- [Revit]开始:编写一个简单外部命令
1 创建项目 以Visual Stidio作为开发工具,测试平台为Revit 2017 打开VS,创建一个C# .NET Framwork类库项目,选择..net框架版本为.NET Framwork ...
- CF 13E Holes
Holes 题意:现在有一排洞,每个洞有一个弹力,能弹到ai之后的洞,球会弹到这个排的外面,现在有2个操作,0 a b 将第a个洞的弹力设为b, 1 a 将球放入第a个洞,求输出进洞的次数 和 弹出这 ...
- 牛客多校第七场 C Bit Compression 思维
链接:https://www.nowcoder.com/acm/contest/145/C来源:牛客网 A binary string s of length N = 2n is given. You ...
- 牛客小白月赛4 C 病菌感染 dfs
链接:https://www.nowcoder.com/acm/contest/134/C来源:牛客网 题目描述 铁子和顺溜上生物课的时候不小心将几滴超级病菌滴到了培养皿上,这可急坏了他们. 培养皿可 ...
- 牛客小白月赛6 B 范围 数学
链接:https://www.nowcoder.com/acm/contest/135/B来源:牛客网 题目描述 已知与均为实数,且满足: 给定A,B,求x的取值范围? 由于Apojacsleam的计 ...
- CodeForces Educational Codeforces Round 51 (Rated for Div. 2)
A:Vasya And Password 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen(&q ...
- C++临时变量的回顾思考以及librdkafka设置回调函数注意点
1 生命周期 如果仅仅是临时变量,并没有调用new来在堆上创建空间,那么注意 : 生命周期仅在该作用域中,即声明该临时变量的{}中: 2 使用(librdkafka C++回调使用) 在创建临时变量后 ...
- SpringBoot + JPA问题汇总
实体类有继承父类,但父类没有单独标明注解 异常表现 Caused by: org.hibernate.AnnotationException: No identifier specified for ...
- css 元素实际宽高
首先定义一个div. 然后稍微装修一下 下面开始区分 一.clientWidth和clientHeigh . clientTop和clientLeft 1,clientWidth的实际宽度 clien ...