首页 > 其他分享 >SpringMVC中实现文件上传下载的三种解决方案(推荐)

SpringMVC中实现文件上传下载的三种解决方案(推荐)

时间:2023-05-18 15:13:07浏览次数:48  
标签:文件 String SpringMVC 解决方案 上传下载 源码 pathSvr public fileSvr

 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数

下面直接贴代码吧,一些难懂的我大部分都加上注释了:

上传文件实体类:

看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。

public class FileInf {

 

     public FileInf(){}

     public String id="";

     public String pid="";

    public String pidRoot="";   

     /**  * 表示当前项是否是一个文件夹项。    */

     public boolean fdTask=false;        

     //   /// 是否是文件夹中的子文件  /// </summary>

     public boolean fdChild=false;

     /**  * 用户ID。与第三方系统整合使用。    */

     public int uid=0;

     /**  * 文件在本地电脑中的名称   */

     public String nameLoc="";

     /**  * 文件在服务器中的名称。   */

     public String nameSvr="";

     /**  * 文件在本地电脑中的完整路径。示例:D:\Soft\QQ2012.exe */

     public String pathLoc="";  

     /**  * 文件在服务器中的完整路径。示例:F:\\ftp\\uer\\md5.exe     */

     public String pathSvr="";

     /**  * 文件在服务器中的相对路径。示例:/www/web/upload/md5.exe   */

     public String pathRel="";

     /**  * 文件MD5    */

     public String md5="";

     /**  * 数字化的文件长度。以字节为单位,示例:120125    */

     public long lenLoc=0;

     /**  * 格式化的文件尺寸。示例:10.03MB   */

     public String sizeLoc="";

     /**  * 文件续传位置。  */

     public long offset=0;

     /**  * 已上传大小。以字节为单位 */

     public long lenSvr=0;

     /**  * 已上传百分比。示例:10%  */

     public String perSvr="0%";

     public boolean complete=false;

     public Date PostedTime = new Date();

     public boolean deleted=false;

     /**  * 是否已经扫描完毕,提供给大型文件夹使用,大型文件夹上传完毕后开始扫描。  */

     public boolean scaned=false;

}

 

首先是文件数据接收逻辑,负责接收控件上传的文件块数据,然后写到服务器的文件中。控件已经提供了块的索引,大小,MD5和长度信息,我们可以根据需要来灵活进行处理,也可以将文件块的数据保存到分布式存储系统中。

<%

out.clear();

String uid             = request.getHeader("uid");//

String id              = request.getHeader("id");

String lenSvr      = request.getHeader("lenSvr");

String lenLoc      = request.getHeader("lenLoc");

String blockOffset = request.getHeader("blockOffset");

String blockSize   = request.getHeader("blockSize");

String blockIndex  = request.getHeader("blockIndex");

String blockMd5        = request.getHeader("blockMd5");

String complete        = request.getHeader("complete");

String pathSvr         = "";

 

//参数为空

if(  StringUtils.isBlank( uid )

     || StringUtils.isBlank( id )

     || StringUtils.isBlank( blockOffset ))

{

     XDebug.Output("param is null");

     return;

}

 

// Check that we have a file upload request

boolean isMultipart = ServletFileUpload.isMultipartContent(request);

FileItemFactory factory = new DiskFileItemFactory();  

ServletFileUpload upload = new ServletFileUpload(factory);

List files = null;

try

{

     files = upload.parseRequest(request);

}

catch (FileUploadException e)

{// 解析文件数据错误 

    out.println("read file data error:" + e.toString());

    return;

  

}

 

FileItem rangeFile = null;

// 得到所有上传的文件

Iterator fileItr = files.iterator();

// 循环处理所有文件

while (fileItr.hasNext())

{

     // 得到当前文件

     rangeFile = (FileItem) fileItr.next();

     if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))

     {

         pathSvr = rangeFile.getString();

         pathSvr = PathTool.url_decode(pathSvr);

     }

}

 

boolean verify = false;

String msg = "";

String md5Svr = "";

long blockSizeSvr = rangeFile.getSize();

if(!StringUtils.isBlank(blockMd5))

{

     md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());

}

 

verify = Integer.parseInt(blockSize) == blockSizeSvr;

if(!verify)

{

     msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;

}

 

if(verify && !StringUtils.isBlank(blockMd5))

{

     verify = md5Svr.equals(blockMd5);

     if(!verify) msg = "block md5 error";

}

 

if(verify)

{

     //保存文件块数据

     FileBlockWriter res = new FileBlockWriter();

     //仅第一块创建

     if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));

     res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);

     up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));

    

     JSONObject o = new JSONObject();

     o.put("msg", "ok");

     o.put("md5", md5Svr); 

     o.put("offset", blockOffset);//基于文件的块偏移位置

     msg = o.toString();

}

rangeFile.delete();

out.write(msg);

%>

 

文件初始化部分

<%

out.clear();

WebBase web = new WebBase(pageContext);

String id     = web.queryString("id");

String md5         = web.queryString("md5");

String uid         = web.queryString("uid");

String lenLoc      = web.queryString("lenLoc");//数字化的文件大小。12021

String sizeLoc     = web.queryString("sizeLoc");//格式化的文件大小。10MB

String callback = web.queryString("callback");

String pathLoc     = web.queryString("pathLoc");

pathLoc            = PathTool.url_decode(pathLoc);

 

//参数为空

if ( StringUtils.isBlank(md5)

     && StringUtils.isBlank(uid)

     && StringUtils.isBlank(sizeLoc))

{

     out.write(callback + "({\"value\":null})");

     return;

}

 

FileInf fileSvr= new FileInf();

fileSvr.id = id;

fileSvr.fdChild = false;

fileSvr.uid = Integer.parseInt(uid);

fileSvr.nameLoc = PathTool.getName(pathLoc);

fileSvr.pathLoc = pathLoc;

fileSvr.lenLoc = Long.parseLong(lenLoc);

fileSvr.sizeLoc = sizeLoc;

fileSvr.deleted = false;

fileSvr.md5 = md5;

fileSvr.nameSvr = fileSvr.nameLoc;

 

//所有单个文件均以uuid/file方式存储

PathBuilderUuid pb = new PathBuilderUuid();

fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);

fileSvr.pathSvr = fileSvr.pathSvr.replace("\\","/");

 

DBConfig cfg = new DBConfig();

DBFile db = cfg.db();

FileInf fileExist = new FileInf();

    

boolean exist = db.exist_file(md5,fileExist);

//数据库已存在相同文件,且有上传进度,则直接使用此信息

if(exist && fileExist.lenSvr > 1)

{

     fileSvr.nameSvr             = fileExist.nameSvr;

     fileSvr.pathSvr        = fileExist.pathSvr;

     fileSvr.perSvr              = fileExist.perSvr;

     fileSvr.lenSvr              = fileExist.lenSvr;

     fileSvr.complete       = fileExist.complete;

     db.Add(fileSvr);

    

     //触发事件

    up6_biz_event.file_create_same(fileSvr);

}//此文件不存在

else

{

     db.Add(fileSvr);

     //触发事件

    up6_biz_event.file_create(fileSvr);

    

     FileBlockWriter fr = new FileBlockWriter();

     fr.CreateFile(fileSvr.pathSvr,fileSvr.lenLoc);

}

 

Gson gson = new Gson();

String json = gson.toJson(fileSvr);

 

json = URLEncoder.encode(json,"UTF-8");//编码,防止中文乱码

json = json.replace("+","%20");

json = callback + "({\"value\":\"" + json + "\"})";//返回jsonp格式数据。

out.write(json);%>

 

第一步:获取RandomAccessFile,随机访问文件类的对象

第二步:调用RandomAccessFile的getChannel()方法,打开文件通道 FileChannel,这块逻辑可以优化,如果以后有分布式存储需求,可以改为分布式存储,减轻单台服务器的压力。

public class FileBlockWriter {  

     public FileBlockWriter(){} 

     public void CreateFile(String pathSvr,long lenLoc)

     {

         try

         {

              File ps = new File(pathSvr);

              PathTool.createDirectory(ps.getParent());

             

             RandomAccessFile raf = new RandomAccessFile(pathSvr, "rw");

             raf.setLength(lenLoc);//fix:以原始大小创建文件

             raf.close();

 

         } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

         }       

     }

    

     public void write(long offset,String pathSvr,FileItem block)

     {       

         try

         {

              InputStream stream = block.getInputStream();           

              byte[] data = new byte[(int)block.getSize()];

              stream.read(data);

              stream.close();            

             

              RandomAccessFile raf = new RandomAccessFile(pathSvr,"rw");

              raf.seek(offset);

              raf.write(data);

              raf.close();

             

         } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

         }

     }

}

第三步:获取当前是第几个分块,计算文件的最后偏移量

第四步:获取当前文件分块的字节数组,用于获取文件字节长度

第五步:使用文件通道FileChannel类的 map()方法创建直接字节缓冲器  MappedByteBuffer

第六步:将分块的字节数组放入到当前位置的缓冲区内  mappedByteBuffer.put(byte[] b);

第七步:释放缓冲区

第八步:检查文件是否全部完成上传

 

好了,到此就全部结束了,如果有疑问或批评,欢迎评论和私信,我们一起成长一起学习。

 

后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库

效果展示:

 

视频演示:

windows控件安装,,linux-deb控件包安装,linux-rpm控件包安装,php7测试,php5测试,vue-cli-测试,asp.net-IIS Express测试,asp.net-IIS测试,asp.net-阿里云(oss)测试,asp.net-华为云(obs)测试,jsp-springboot测试,ActiveX(x86)源码编译,ActiveX(x64)源码编译,Windows(npapi)源码编译,macOS源码编译,Linux(x86_64)源码编译,Linux(arm)源码编译,Linux(mips-uos)源码编译,Linux(mips-kylin-涉密环境)源码编译,sm4加密传输,压缩传输,

示例下载地址

源代码文档

asp.net源码下载jsp-springboot源码下载jsp-eclipse源码下载jsp-myeclipse源码下载php源码下载csharp-winform源码下载vue-cli源码下载c++源码下载

详细配置信息及思路

标签:文件,String,SpringMVC,解决方案,上传下载,源码,pathSvr,public,fileSvr
From: https://www.cnblogs.com/songsu/p/17412011.html

相关文章

  • c# web中实现文件上传下载的三种解决方案(推荐)
    ​IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头。 一. 两个必要响应头Accept-Ranges、ETag        客户端每次提交下载请求时,服务端都要添加这两个响应头,以保证客户端和服务端将此下载识别为可以断点续传......
  • 档案馆库房内环境温湿度的控制与解决方案
    ​ 目录一、智慧档案馆建设目的二、智慧档案馆集成度三、智慧档案馆架构3.1库房环境监测3.2库房安防监控四、智慧档案馆功能简介4.1档案室一体化控制管理系统建设方案4.2温湿度检测建设方案4.3恒温控制建设方案4.4烟雾感应检测系统4.5安防系统建设方案4.6漏水报警监......
  • 智慧档案馆一体化保护建设平台解决方案
     北京盛世宏博科技有限公司档案馆、档案室、档案库房八防、九防、十防、十二防环境一体化管控平台欣赏可提供一以下服务:档案库房温湿度监控、恒温恒湿消毒净化系统、防火系统、防盗系统、漏水系统、门禁系统、视频系统、除尘净化系统、3D可视化监控系统等等更多了解可@北......
  • 端-边-云一体化视频融合预警解决方案助力文旅产业更出圈
    一、文旅现状当前,中国的旅游业正在慢慢转型,文化与旅游结合的需求越来越明显。在各地文旅局的大力宣传下,全国各地掀起文旅热潮,前有西安大唐不夜城火爆全国,后有淄博烧烤现象级出圈,再有洛阳城打造国风盛宴。在各地文旅积极“内卷”的推动下,游客的旅行激情正在被点燃。当然,各地政府在......
  • 产废单位EPM+SAP产废企业数字化管理解决方案——环保数字化转型利器
    哲讯产废单位EPM+SAP产废企业数字化解决方案随着环保部门对重点产废单位监管的日益加强,产废企业必须要做好内部危废转移管理。基于成熟的危废管理系统衍生产品“产废管理系统”,可以帮助产废企业规范化管理内部危废的转运与处置,轻松应对环保监管。系统设计遵循开放性原则,各系统采......
  • SpringMVC 异步(长轮询)实现消息定点推送
    $(function(){getMsg();});functiongetMsg(){$.ajax({url:"/polling/msg",type:"get",data:{},success:function(data){if(data......
  • 本地事务失效问题描述及其解决方案
    什么情况下会出现本地事务失效的问题,为什么会出现本地事务失效问题? 在分布式架构中,本地事务失效的原因主要是在于分布式事务的实现难度和复杂度,需要在多个服务之间进行协调、通信和同步状态等,在特定的情况下,可能会出现延迟,中断或者失败的问题。 举一个简单的例子:如果在多个......
  • Plsql或Navicat连接登陆Oracle时慢、执行语句的时候也特别慢的问题解决方案
    用Plsql或Navicat连接登陆Oracle时,等待时间特别长。经过漫长的等待后,执行语句的时候也特别慢,监听配置没毛病的情况下,大概率是监听日志文件过大导致的。监听日志路径:app\Administrator\diag\tnslsnr\LS--20171012URU\listener\trace\listener.log删除listener.log文件即可。......
  • 【.NET】C#/.NET新建项目sln,增加src和test文件夹问题和解决方案
    ​问题介绍    经常逛github找优秀的.NET项目看,看到github上的项目的层级有srctest,sln放在外层。如下图: 发现自己再VisaulStudio新建的项目即使添加了src和test,然后基于文件夹下新建项目,物理路径上也不是这样的结构。如图 物理路径下依然和sln是平级状态。解......
  • Spring+SpringMVC19_Spring练习-业务实现2
    六、用户表和角色表的分析  七、角色列表展示分析  八、角色列表展示-controller层实现  九、角色列表展示-service和dao层实现  十、角色列表展示-配置实现  十一、角色列表展示-页面展示  十二、角色的添加操作  十三、用户列表展示1 ......