使用websocket进行断点续传文件

使用websocket进行断点续传文件

上传要点

断点上传的目标是为了将大型文件分批分片上传,在服务端进行接收并组合,最终完成上传

代码

websocket接收文件

/**
 * websocket断点上传文件
 * zhanghaichao
 */
@ServerEndpoint("/websocket/fileup")
public class FileServer {

    /**
     * 记录所有上传文件属性
     */
    private static final Map<String,FileTargetInfo> fileTarge = new HashMap<>();

    /**
     * 当websocket连接成功的时候就是准备上传文件的时候
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        //扩大一次性上传的最大数值
        session.setMaxBinaryMessageBufferSize(BreakpointUploadConfig.blobSize+8);
    }

    /**
     * 当链接关闭的时候判断是否是上传成功状态,并进行删除未上传完文件或者保存文件操作
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        System.out.println("链接关闭");
        String id = session.getId();
        FileTargetInfo fileTargetInfo = fileTarge.get(id);
        if(fileTargetInfo!=null){
            fileTargetInfo.fileUploadComplete();
            fileTarge.remove(id);
        }
    }

    /**
     * 接收要上传文件的属性,文件名称,大小,key值
     * @param message
     * @param session
     */
    @OnMessage
    public void onTextMessage(String message, Session session) {
        try {
            FileInfo fileInfo = Json.getJson().parse(message, FileInfo.class);
            List<String> tList = TimeTools.getDayMonYear();
            String savePath = String.format(BreakpointUploadConfig.savePath+"%s/%s/%s/",tList.get(0),tList.get(1),tList.get(2));
            FileTargetInfo fileTargetInfo = new FileTargetInfo(fileInfo,savePath);
            //替换一下文件存放位置,不然将使用BreakpointUploadConfig.savePath来存放
            fileTarge.put(session.getId(),fileTargetInfo);
            UploadCommand uc=new UploadCommand(fileTargetInfo);
            response(session,uc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始上传二进制文件
     * @param session
     * @param bb
     */
    @OnMessage
    public void onBinaryMessage(Session session,ByteBuffer bb) {
        String id = session.getId();
        FileTargetInfo fileTargetInfo = fileTarge.get(id);
        fileTargetInfo.saveByteBuffer(bb);
        UploadCommand uc=new UploadCommand(fileTargetInfo);
        if(uc.getCompletePercent()==1){
            FileTargetInfo fileTarget = fileTarge.get(id);
            fileTarget.fileUploadComplete();
            fileTarge.remove(id);
        }
        response(session,uc);
    }

    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }


    private void response(Session session,Object obj) {
        try {
            session.getBasicRemote().sendText(Json.getJson().toJson(obj));
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

接收文件属性

/**
 * 待上传文件基本信息类
 * @author zhc
 *
 */
public class FileInfo {
    private String fileName;
    private String fileId;
    private long fileSize;
    private String fileInfo;
    public String getFileName() {
        return fileName;
    }
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
    public String getFileId() {
        return fileId;
    }
    public void setFileId(String fileId) {
        this.fileId = fileId;
    }
    public long getFileSize() {
        return fileSize;
    }
    public void setFileSize(long fileSize) {
        this.fileSize = fileSize;
    }
    public String getFileInfo() {
        return fileInfo;
    }
    public void setFileInfo(String fileInfo) {
        this.fileInfo = fileInfo;
    }

}

内部文件状态

/**
 * 内部保存文件状态
 */
public class FileTargetInfo implements Serializable{
    private static final long serialVersionUID = -892304047563801858L;

    /**上传文件基本目录*///todo
    private String savePath = BreakpointUploadConfig.savePath;
    public int blobSize = BreakpointUploadConfig.blobSize;
    /**上传文件信息*/
    private FileInfo fileInfo;
    /**文件上传进度*/
    private float completePercent=0;
    /**服务器端文件名*/
    private String fileName;
    /**
     * 文件大小
     */
    private long fileSize=0;


    private long indexStart=0;
    private long indexEnd=0;

    private File file;
    private File tempFile;
    private RandomAccessFile raFile;
    private FileChannel fileChannel;

    public FileTargetInfo(FileInfo fileInfo,String savePath){
        this.savePath = savePath;
        this.initInfo(fileInfo);
    }



    public FileTargetInfo(FileInfo fileInfo){
        this.initInfo(fileInfo);
    }

    private void initInfo(FileInfo fileInfo){
        this.fileSize = fileInfo.getFileSize();
        this.fileInfo = fileInfo;
        this.fileName=fileInfo.getFileId()+"."+fileInfo.getFileName().substring(fileInfo.getFileName().lastIndexOf(".")+1);

        if(this.blobSize>this.fileSize){
            indexEnd = this.fileSize;
        }else{
            indexEnd = this.blobSize;
        }

        File filemkdirs =new File(this.savePath);
        //如果文件夹不存在则创建
        if(!filemkdirs .exists()  && !filemkdirs .isDirectory())
        {
            filemkdirs .mkdirs();
        }

        //开始创建文件模板
        this.file=new File(savePath+this.fileName);
        this.tempFile=new File(savePath+this.fileInfo.getFileId()+".temp");
        try {
            this.raFile=new RandomAccessFile(this.tempFile, "rw");
            this.raFile.setLength(this.fileInfo.getFileSize());
            this.fileChannel=this.raFile.getChannel();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存数据
     * @return
     */
    public synchronized FileTargetInfo saveByteBuffer(ByteBuffer bb){
        try {
            this.fileChannel.write(bb, this.indexStart);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        if(this.indexEnd>=this.fileSize){//上传完毕
            this.completePercent = 1;
            this.indexEnd = -1;
            this.indexStart = -1;
            this.fileUploadComplete();
            return this;
        }

        this.completePercent = (float)this.indexEnd/(float)this.fileSize;

        //头变尾
        this.indexStart = this.indexEnd;

        if(this.fileSize-this.indexEnd>this.blobSize){
            this.indexEnd+=this.blobSize;
        }else{
            this.indexEnd = this.fileSize;
        }
        return this;
    }


    public void fileUploadComplete(){
        this.closeFileWriteAccessChannel();
        if(this.completePercent>=1){
            this.tempFile.renameTo(this.file);
        }
        this.tempFile.delete();
    }

    public void closeFileWriteAccessChannel(){
        try {
            this.fileChannel.close();
            this.raFile.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void setSavePath(String savePath) {
        this.savePath = savePath;
    }

    public int getBlobSize() {
        return blobSize;
    }

    public void setBlobSize(int blobSize) {
        this.blobSize = blobSize;
    }

    public Long getFileSize() {
        return fileSize;
    }

    public void setFileSize(Long fileSize) {
        this.fileSize = fileSize;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public File getTempFile() {
        return tempFile;
    }

    public void setTempFile(File tempFile) {
        this.tempFile = tempFile;
    }

    public RandomAccessFile getRaFile() {
        return raFile;
    }

    public void setRaFile(RandomAccessFile raFile) {
        this.raFile = raFile;
    }

    public FileChannel getFileChannel() {
        return fileChannel;
    }

    public void setFileChannel(FileChannel fileChannel) {
        this.fileChannel = fileChannel;
    }

    public FileInfo getFileInfo() {
        return fileInfo;
    }

    public void setFileInfo(FileInfo fileInfo) {
        this.fileInfo = fileInfo;
    }

    public float getCompletePercent() {
        return completePercent;
    }

    public void setCompletePercent(float completePercent) {
        this.completePercent = completePercent;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public long getIndexStart() {
        return indexStart;
    }

    public void setIndexStart(long indexStart) {
        this.indexStart = indexStart;
    }

    public long getIndexEnd() {
        return indexEnd;
    }

    public void setIndexEnd(long indexEnd) {
        this.indexEnd = indexEnd;
    }
}

用于返回json数据

/**
 * 文件上传命令信息类
 * 此类会被转成JSON发送到客户端
 * @author zhanghaichao
 *
 */
public class UploadCommand {
    private final String typeId="uploadCommand";
    private String fileId;
    private int index;
    private long indexStart;
    private long indexEnd;
    private long blobSize;
    private float completePercent=0;


    public UploadCommand(FileTargetInfo fileTargetInfo){
        FileInfo fileInfo = fileTargetInfo.getFileInfo();
        this.fileId = fileInfo.getFileId();
        this.indexStart = fileTargetInfo.getIndexStart();
        this.indexEnd = fileTargetInfo.getIndexEnd();
        this.completePercent = fileTargetInfo.getCompletePercent();
        this.blobSize = fileTargetInfo.getFileSize();
    }

    public String getFileId() {
        return fileId;
    }
    public void setFileId(String fileId) {
        this.fileId = fileId;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
    public long getIndexStart() {
        return indexStart;
    }
    public void setIndexStart(long indexStart) {
        this.indexStart = indexStart;
    }
    public long getIndexEnd() {
        return indexEnd;
    }
    public void setIndexEnd(long indexEnd) {
        this.indexEnd = indexEnd;
    }
    public long getBlobSize() {
        return blobSize;
    }
    public void setBlobSize(long blobSize) {
        this.blobSize = blobSize;
    }
    public float getCompletePercent() {
        return completePercent;
    }
    public void setCompletePercent(float completePercent) {
        this.completePercent = completePercent;
    }
    public String getTypeId() {
        return typeId;
    }

}

html部分

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>FileUpload</title>
    <script src="/static/js/jquery-2.1.1.min.js"></script>
</head>
<body>
<input type="file" id="file">
<input type="button" id="but" value="上传">
</body>
<script>
    var file = $('#file');
    var f;
    file.on('change', function (e) {
        var files = e.currentTarget.files;
        f = files[0]
        uploadFileInfo(f);

    });

    function uploadFileInfo(f) {
        var fileInfo = {};
        fileInfo.fileName = f.name;
        fileInfo.fileSize = f.size;
        fileInfo.fileInfo = f.type;
        fileInfo.fileId = Date.parse(new Date());//写死一个hash值
        ws.send(JSON.stringify(fileInfo));
    }

    function uploadFile(obj) {
        var blob = f.slice(obj.indexStart, obj.indexEnd);
        var reader = new FileReader();
        reader.onload = function (e) {
            ws.send(e.target.result);
        };
        reader.readAsArrayBuffer(blob);
    }

    var options = {
        concurrentHash: 2,
        concurrentUpload: 2,
        debugMode: false,
        wsuri: 'ws://localhost:8080/websocket/fileup'
    };


    var onmessage = function (that) {
        return function (e) {
            var obj = JSON.parse(e.data);
            if (obj.typeId == 'uploadCommand') {
                console.log('文件完成:' + parseInt(obj.completePercent * 65 + 35, 10) + '%');
                if (obj.completePercent != 1) {
                    uploadFile(obj);
                } else {
                    console.log('文件上传完成,开始上传下一个文件。');
                }
            }
        }
    }

    var onopen = function (that) {
        console.log('Websocket is opened.');
    }


    var ws;
    $(function () {
        ws = new WebSocket(options.wsuri);
        ws.onopen = onopen(this);
        ws.onmessage = onmessage(this);
    });

</script>
</html>

根据以下地址进行改编目标还有一个项目地址

https://blog.csdn.net/Fabuler/article/details/42527519

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值