文件的上传&预览&下载学习(一)
注:主要是说明后端逻辑和数据库表设计
1.当前主流的几种文件上传&预览&下载方式
- 把文件直接存储在服务器
- 分布式存储OSS,比如阿里OSS、Minio
2.数据库表设计
- 由于文件都是跟业务关联的,比如评论里面掺杂评论图片,常规的设计就是在'评论表'添加上传'图片名称'字段和'图片相对路径',在上传成功后返回给前端
1.1 如果是加入多个文件的话,这种设计就不太合适:10个文件在评论表就需要加20个字段
1.2 针对'1.1'进行改进,建一种'文件信息表',设计字段'外键 fk_id'用来存储评论id(如果后续有商品图片也可以用这个存),这时候有需要考虑一个问题,id是根据什么生成的,是否唯一,如果是雪花ID就无需考虑这个问题,但如果是递增那极可能重复(商品id和评论id同时为1的情况);这时就还需要在'文件信息表'添加一个'外键类型 fk_type'作区分,比如评论就是comment,商品就是goods。然后把'图片名称'字段和'图片相对路径'放到'文件信息表'来(预览路径和下载路径可能不同,下载路径是绝对路径,预览路径为了防止用户直接访问服务器其他位置,做一层虚拟映射nginx)


1.3 可能还需要加一个'文件下载名称',由于文件可能是'数字+字母(可能是md5)'的形式(如果是手机拍摄),然后要按照一定的规则比如'订单编号-产品名称-用户昵称'生成
3.后端实现
1.直接使用Java下载到指定目录(现根据外键查询出绝对路径,在下载)
@Override
public void downloadByOrderId(HttpServletResponse response, Long orderId, String fkType) throws IOException {
String fileLocation = null;
try{
// 一个订单只有一个报告pdf
QueryWrapper<FileUpload> fileUploadQueryWrapper = new QueryWrapper<>();
fileUploadQueryWrapper.eq("is_deleted","0");
fileUploadQueryWrapper.eq("fk_id",orderId);
fileUploadQueryWrapper.eq("fk_type",fkType);
FileUpload uploadEntity = uploadMapper.selectOne(fileUploadQueryWrapper);
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream"); //这边可以设置文件下载时的名字,我这边用的是文件原本的名字,可以根据实际场景设置
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(uploadEntity.getOldName(), "UTF-8"));
if(StrUtil.isNotBlank(uploadEntity.getLocation())){
fileLocation = uploadEntity.getLocation();
}
logger.info("fileLocation: "+fileLocation);
FileUtils.writeBytes(uploadEntity.getLocation(), response.getOutputStream());
}catch (Exception e){
logger.error("download error orderId: {} fkType: {} && fileLocation: {} msg: {}",orderId,fkType,fileLocation,e.getMessage());
}
}
public static void writeBytes(String filePath, OutputStream os) {
FileInputStream fi = null;
try {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
fi = new FileInputStream(file);
//TODO 扩大缓冲,多线程(请求的节点过多超时)
byte[] b = new byte[8192];
int length;
while ((length = fi.read(b,0,8192)) > 0) {
os.write(b, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(os != null) {
try {
os.close();
}catch (IOException e) {
e.printStackTrace();
}
}
if(fi != null) {
try {
fi.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.分布式存储Minio,参考博客:https://www.freesion.com/article/5069848586/ (下载和上面的方式相同 根据文件名先去Minio查询,获取输入流,然后下载)
文件的上传&预览&下载学习(一)的更多相关文章
- PHP WAMP 文件上传 及 简单的上传预览
...... 使用特殊的表单类型file, 主(上传)页面: <form action="chuli.php" method="post" enctype ...
- 上传文件的三种方式xhr,ajax和iframe及上传预览
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 基于bootstrap的上传插件fileinput实现ajax异步上传功能(支持多文件上传预览拖拽)
首先需要导入一些js和css文件 ? 1 2 3 4 5 6 <link href="__PUBLIC__/CSS/bootstrap.css" rel="exte ...
- html,图片上传预览,input file获取文件等相关操作
input file常用方法: var obj=document.getElementById("upimage"); var file=obj.files[0];//获取文件数据 ...
- 用html5文件api实现移动端图片上传&预览效果
想要用h5在移动端实现图片上传&预览效果,首先要了解html5的文件api相关知识(所有api只列举本功能所需): 1.Blob对象 Blob表示原始二进制数据,Html5的file对象就继 ...
- FileReader()读取文件、图片上传预览
前言 FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据. 其中File对象可以是来自用户 ...
- 用file标签实现多图文件上传预览
效果图: js 代码: <script> //下面用于多图片上传预览功能 function setImagePreviews(avalue) { var docObj = document ...
- 模拟QQ心情图片上传预览
出于安全性能的考虑,目前js端不支持获取本地图片进行预览,正好在做一款类似于QQ心情的发布框,找了不少jquery插件,没几个能满足需求,因此自己使用SWFuplad来实现这个图片上传预览. 先粘上以 ...
- 微信开发中使用微信JSSDK和使用URL.createObjectURL上传预览图片的不同处理对比
在做微信公众号或者企业微信开发业务应用的时候,我们常常会涉及到图片预览.上传等的处理,往往业务需求不止一张图片,因此相对来说,需要考虑的全面一些,用户还需要对图片进行预览和相应的处理,在开始的时候我使 ...
- 兼容好的JS图片上传预览代码
转 : http://www.codefans.net/articles/1395.shtml 兼容好的JS图片上传预览代码 (谷歌,IE11) <html xmlns="http:/ ...
随机推荐
- Python_DL_July_深度学习_10_深度学习与各种迁移学习应用
深度学习10(上)深度学习与各种迁移学习应用
- pytorch学习笔记(9)--损失函数
1.损失函数的作用: (1)计算实际输出和目标输出之间的差距: (2)为我们更新输出提供一定的依据(也就是反向传播) 官网链接:https://pytorch.org/docs/1.8.1/nn.ht ...
- [2004年NOIP提高组] 合并果子
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可以看出,所 ...
- HTML实战:个人信息登记表
效果展示: 代码示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- JAVA中的变量与基本操作
- 解决未定义的count键“报错为:"Uncaught ReferenceError: count is not defined"
报错: 源码:Vuex仓库.js let state = { count } export default state 解决:未赋值的count键
- c++学习2 基础关键词
三 volatile强制访问内存 在一个变量的频繁使用中,系统为了提高效率,会自动将内存里面的数据放入CPU里的寄存器里.但在某些特殊场景下,放入寄存器这个操作反倒会导致CPU无法及时获取最新的一手数 ...
- delete、truncate、drop的区别
delete:只删除数据,不删除结构.删除的数据存储在系统回滚段中,可以回滚.不会自动提交事务. 在InnoDB中,delete不会真的把数据删除,mysql实际上只是给删除的数据打了个标记为已删除, ...
- C#中的范围类型(Range Type)
//语法糖Rangestatic void Main(string[] args) { var myArray = new string[] { "Item1", "It ...
- modesim : mosel not define
这个星期仿真sdram时,添加的sdram 模型文件在modesim中总是找不到,在qq群里提问和私聊别人都没有得到解决方法.于是自己摸索了好多天.终于得到了解决. 可以看到modesim里面work ...