序言
现在,绝大部分的应用程序在很多的情况下都需要使用到文件上传与下载的功能,在本文中结合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 @Controller114 115 public class FruitController extends BaseController {116 117 ????@Autowired118 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 ?????* 文件最大 5M140 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 ?????* ContentType164 165 ?????*/166 167 ????public static final Map<String, String> EXT_MAPS = new HashMap<>();168 169 ????static {170 171 ????????// image172 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 ????????// doc182 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.com200 201 ?????* @date 2017/9/4 17:23202 203 ?????* @param wordFile ?photoFile fruitName204 205 ?????* @return List<Fruit>206 207 ?????* @description 保存水果信息208 209 ?????*/210 211 ????@RequestMapping(value = {"/api/public/upload/fruit/submit"}, method = RequestMethod.POST)212 213 ????@ResponseBody214 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.com264 265 ?????* @date 2017/9/4 16:18266 267 ?????* @param268 269 ?????* @return270 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();366368 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.com416 417 ?????* @date 2017/9/4 17:23418 419 ?????* @param420 421 ?????* @return422 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
基于hap的文件上传和下载
原文地址:http://www.cnblogs.com/jiaqingshareing/p/7598453.html