H5界面预览或下载文件(Minio或本地文件)

本文介绍了在H5界面中通过Minio服务实现文件预览和下载的两种方法,包括利用Minio自带的预览地址和通过后端获取文件流。同时讨论了安全性及跨域问题。
该文章已生成可运行项目,

H5界面预览或下载文件(Minio或本地文件)

一、使用场景

最近有个老系统,需要添加图片预览和文件下载功能,文件保存在Minio上。前端需要在H5界面上,使用js获取文件信息进行图片的预览和文件下载

先说一下两种情况,本地文件(或者通过IO流获取的文件)只能通过流方式传输到前端,然后进行展示或下载。

但是Minio上的文件,有两种方式可以处理:1.通过Minio自带的预览地址直接展示,比较方便但是会暴露Minio地址(需要安全性考虑),而且一般用于图片之类的可以直接预览的文件格式;2.读取文件流,和本地文件一样传输到前端,然后处理展示或下载,适用于类似文档表格等格式的文件。

可以先看下效果
在这里插入图片描述


话不多说,直接上代码

Minio上传下载相关内容就不赘述了,直接依赖就能用了。

二、Minio自带预览地址

Java代码实现

@RequestMapping("/preViewFile")
@ResponseBody
public String preViewFile(){
    try {
            return minioClient.getPresignedObjectUrl(Method.GET, bucketName, fileName, 60 * 60 * 24,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
}
//第一个参数是请求方式,默认给GET就行,bucketName是保存的桶名称,fileName就是Minio文件保存的地址,第四个参数是链接有效时间,最后一个请求参数,一般给Null就行。

JS代码实现

//按钮随便写一个,onclick调用onPrewViewFile()就行,这里就不赘述了!
function onPrewViewFile() {
	top.$.modal.loading('文件加载中');
	$.ajax({
            cache: true,
            type: "get",
            url: prefix + "/preViewFile",
            data: {},//如果有参数,可以在这里添加请求参数,get也可以改成post
            async: false,
            error : function(request) {
                top.$.modal.closeLoading();
                $.modal.alertError("系统错误");
            },
            success: function(data) { 
                window.open(data, "_blank", "width=800,height=600,left=" + (screen.width/2 - 400) + ",top=" + (screen.height/2 - 300));
                top.$.modal.closeLoading();
            }
        });
}
//JAVA后台返回的值就是地址,所以直接使用window.open打开就可以预览了!!!  "_blank"是新开窗口,再后面是窗口大小和位置,可以自定义(就是style样式)

三、文件流形式展示和下载

JAVA代码实现

	@RequestMapping("/preViewFile2")
    @ResponseBody
    public void preViewFile2(HttpServletResponse response){
        try {
            //本地文件获取流方式
            InputStream inputStream = new FileInputStream(new File("filePath"));
            //Minio获取流方式
            InputStream inputStream = minioClient.getObject(bucketName, "filePath");
            //请求返回的response
            ServletOutputStream outputStream = null;
            try {
                //设置响应头属性,第一个是附件名
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline;filename=" + "fileName");
                //第二个允许外部客户端访问,解决跨域问题等,如果有其他要求,可自行添加
                response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
                //如果要给前端赋值类型,取消下面这行注释,fileType换成自己的文件类型即可!
                //response.setHeader(HttpHeaders.CONTENT_TYPE,"filType");
                
                //将流写入response的输出流中
                outputStream = response.getOutputStream();
                byte b[] = new byte[1024];
                int n;
                while ((n = inputStream.read(b)) != -1) {
                    outputStream.write(b, 0, n);
                }
                outputStream.flush();
            } catch (Exception e) {
                //有异常抛出去给外层统一处理
                throw e;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        }catch (Exception e){
            logger.info("获取文件流报错", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

//将文件流保存到response中传给前端进行处理

JS代码实现

需要注意的是,图片可以预览,但是文档类的需要其他插件才行,所以这里只做图片预览和文件下载!!!

//按钮随便写一个,onclick调用onPrewViewFile2()就行,这里就不赘述了!

function onPrewViewFile2() {
    	top.$.modal.loading('文件加载中');
    	//新建ajax请求
    	var xhr = new XMLHttpRequest();
    	//请求方式、地址和是否异步,如果是带参数,可以将参数放入最后的xhr.send(params)中即可
    	xhr.open("GET", prefix + "/preViewFile2", true);
    	//相应类型是二进制
        xhr.responseType = "blob";
        xhr.onload = function(e) {
            //如果返回是200,正常
            if (this.status == 200) {
                var blob = this.response;
                //fileType我原本是通过表格名称截取传进方法的,如果不通过方法传进来,则使用下面这条语句
                //也可以通过let contentType = response.headers.get('Content-Type');在后端设置好后,前端获取
                if (fileType == 'jpeg' ||fileType == 'jpg' || fileType == 'png') {
                	//如果是文件格式
                    var reader = new FileReader();
                    reader.onloadend = function () {
                        let image = new Image();
                        //文件地址赋值给image.src(文件地址在后面的reader.readAsDataURL(blob)会生成)
                        image.src = reader.result;
                        //给浏览器的请求地址,如果不给也可以预览,但是chrome浏览器左上角会有个圈圈一直转啊转,转的头晕。
                        //加上请求地址就好了,其他浏览器暂时没看到此问题
                        let url = URL.createObjectURL(blob);
                        //打开新的窗口,设置窗口的样式即可
                        let popupWindow = window.open(url, "_blank", "width=800,height=600,left=" + (screen.width / 2 - 400) + ",top=" + (screen.height / 2 - 300));
                        popupWindow.document.write('<html><head><title>图片预览</title></head><body style="margin: 0; padding: 0; text-align: center;">');
                        popupWindow.document.write('<img src="' + image.src + '" alt="Preview Image" style="max-width: 100%; max-height: 100vh;">');
                        popupWindow.document.write('</body></html>');
                    }
                    //将二进制文件生成对应的数据地址
                    reader.readAsDataURL(blob);
                    top.$.modal.closeLoading();
                } else {
                    //如果是其他格式,则只允许下载
                    //创建一个a链接组件,用于下载
                    let a = document.createElement('a');
                    //将二进制数据创建成可下载的地址
                    let url = URL.createObjectURL(blob);
                    //赋值给a组件
                    a.href = url;
                    
                    //fileName我原本是表格获取,如果没有,则使用下面这两行代码即可
                    //let contentDisposition = response.headers.get('Content-Disposition');
    				//let fileName = contentDisposition.split('filename=')[1];
                    
                    //将文件名赋值给a.download,用于下载名
                    a.download = fileName;
                    //添加上a组件后,主动click实现下载效果。
                    document.body.appendChild(a);
                    a.click();
                    //释放上面创建的url对象,避免内存过大
                    window.URL.revokeObjectURL(url);
                    top.$.modal.msgSuccess("下载成功");
                }
            }else {
                top.$.modal.closeLoading();
                top.$.modal.alertError("请求错误");
            }
        };
		//发送请求
        xhr.send();
}

//注意:如果 top.$.modal.alertError("请求错误")报错,可能是缺少对应的js包,这只是个提示,可以删除掉。

总结

  1. Minio服务本身带有文件预览功能,我们只用获取对应地址直接打开就可以预览了,但是这会暴露Minio地址,如果对安全性有要求,不建议!
  2. 流形式的实现会比较复杂,需要后端获取流后传输到前端进行处理,但是对于预览和下载都可以适用,也是不错的方式。

如果需要多文件上传样式和按钮的,可以看一下另一篇文章,实现多文件的选择和删除。

多文件上传按钮样式

🙉在小小的电脑上面敲呀敲呀敲,写短短的代码,埋小小的坑🙈

🙉在大大的电脑上面敲呀敲呀敲,写大大的代码,埋大大的坑🙈

🙉在特别大的电脑上面敲呀敲呀敲,写特别大的代码,埋特别大的坑🙈

🙉优秀的你肯定是一个不爱写Bug并且爱点赞关注的靓仔吧!🙈

本文章已经生成可运行项目
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值