带有进度条的fastdfs文件下载的demo,也有上传,删除文件的功能

通过fastdfs-java-client的api按块下载文件,下载成功后写入到输出流并将进度按用户通过websocket推送到客户端

注:该demo只是单纯实现了有进度条的下载,如果下载的接口不做其它处理用户会卡在下载进程里,后续再做处理

源码git地址:https://github.com/xujun738/spring-uploadfile.git这里的代码已经在用户请求后另起一个线程进行下载处理

1.pom.xml

<!—fastdfs-client—>

<dependency>

   <groupId>com.github.tobato</groupId>

   <artifactId>fastdfs-client</artifactId>

   <version>1.26.5</version>

</dependency>

<!—springboot  websocket—>

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

springboot集成fastdfs

配置application.yml

fdfs:

  so-timeout: 600000

  connectTimeout: 600

  thumbImage:             #缩略图生成参数

    width: 150

    height: 150

  pool:

    jmx-enabled: false

    max-total: 200

    max-wait-millis: 30000

  trackerList:            #TrackerList参数,支持多个

    - ip:22122   # 107.182.180.143:22122

  visit:

url:http://ip  #47.100.116.208

    port: 8888

Websocket配置类

@Configuration

public class WebSocketConfig {

    @Bean

    public ServerEndpointExporter serverEndpointExporter() {

        return new ServerEndpointExporter();

    }

}

websocket服务类

/**

* <p>Description : </p>

* <p>Copyright : Copyright (c) 2018</p>

* <p>Company : tgram </p>

*

* @author eric

* @version 1.0

* @Date 2019/3/8 上午9:57

*/

@ServerEndpoint("/websocket/{userId}")

@Component

public class MyWebSocket {

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。

    private static int onlineCount = 0;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。

    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据

    private Session session;

    private String userId = null;

    /**

     * 连接建立成功调用的方法

     */

    @OnOpen

    public void onOpen(Session session, @PathParam("userId") String userId) {

        this.session = session;

        this.userId = userId;

        webSocketSet.add(this);     //加入set中

        addOnlineCount();           //在线数加1

        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());

        try {

            sendMessage("连接成功");

        } catch (IOException e) {

            System.out.println("IO异常");

        }

    }

    /**

     * 连接关闭调用的方法

     */

    @OnClose

    public void onClose() {

        webSocketSet.remove(this);  //从set中删除

        subOnlineCount();           //在线数减1

        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());

    }

    /**

     * 收到客户端消息后调用的方法

     *

     * @param message 客户端发送过来的消息

     */

    @OnMessage

    public void onMessage(String message, Session session) {

        System.out.println("来自客户端的消息:" + message);

        //群发消息

        for (MyWebSocket item : webSocketSet) {

            try {

                item.sendMessage(message);

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

    /**

     * 发生错误时调用

     *

     * @OnError public void onError(Session session, Throwable error) {

     * System.out.println("发生错误");

     * error.printStackTrace();

     * }

     * <p>

     * <p>

     * public void sendMessage(String message) throws IOException {

     * this.session.getBasicRemote().sendText(message);

     * //this.session.getAsyncRemote().sendText(message);

     * }

     * <p>

     * <p>

     * /**

     * 群发自定义消息

     */

    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {

        for (MyWebSocket item : webSocketSet) {

            try {

                //这里可以设定只推送给这个userId的,为null则全部推送

                if (userId == null) {

                    item.sendMessage(message);

                } else if (item.userId.equals(userId)) {

                    item.sendMessage(message);

                }

            } catch (IOException e) {

                continue;

            }

        }

    }

    /**

     * 实现服务器主动推送

     */

    public void sendMessage(String message) throws IOException {

        this.session.getBasicRemote().sendText(message);

    }

    public static synchronized int getOnlineCount() {

        return onlineCount;

    }

    public static synchronized void addOnlineCount() {

        MyWebSocket.onlineCount++;

    }

    public static synchronized void subOnlineCount() {

        MyWebSocket.onlineCount--;

    }

}

5.控制层类

@Controller

@RequestMapping("/upload")

public class UploadCtrl {

    @Autowired

    private FastDFSClientWrapper fastDFSClientWrapper;

    @Autowired

    private FastFileStorageClient storageClient;

    @RequestMapping(value = "", method = RequestMethod.POST)

    @ResponseBody

    public InfoMsg fileUpload(@RequestParam("uploadFile") MultipartFile file) {

        InfoMsg infoMsg = new InfoMsg();

        if (file.isEmpty()) {

            infoMsg.setCode("error");

            infoMsg.setMsg("Please select a file to upload");

            return infoMsg;

        }

        try {

            String url = fastDFSClientWrapper.uploadFile(file);

            System.out.println("上传的文件URL:   " + url);

            JSONObject jsonObject = new JSONObject();

            jsonObject.put("url", url);

            jsonObject.put("filesize", file.getSize());

//       File tmp = new File(TMP_PATH, file.getOriginalFilename());

//       if(!tmp.getParentFile().exists()){

//          tmp.getParentFile().mkdirs();

//       }

//       file.transferTo(tmp);

            infoMsg.setCode("success");

            infoMsg.setMsg("You successfully uploaded '" + file.getOriginalFilename() + "'");

        } catch (IOException e) {

            infoMsg.setCode("error");

            infoMsg.setMsg("Uploaded file failed");

        }

        return infoMsg;

    }

    @RequestMapping(value = "/delete", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")

    @ResponseBody

    public String deleteFile(String fileName) {

        try {

            fastDFSClientWrapper.deleteFile(fileName);

            return "删除成功";

        } catch (Exception e) {

            e.printStackTrace();

            return "删除失败";

        }

    }

    @RequestMapping(value = "/download")

    @ResponseBody

    public void download(String fileName, HttpServletResponse response, String userId) throws IOException {

        StorePath storePath = StorePath.parseFromUrl(fileName);

        // 配置文件下载

        response.setHeader("content-type", "application/octet-stream");

        response.setContentType("application/octet-stream");

        // 下载文件能正常显示中文

        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

//        byte[] r = storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), new DownloadCallback<byte[]>() {

//            @Override

//            public byte[] recv(InputStream ins) throws IOException {

//                byte[] reulst = IOUtils.toByteArray(ins);

//                System.out.println(reulst.length);

//                return reulst;

//            }

//        });

//        response.getOutputStream().write(r);

        FileInfo fileInfo = storageClient.queryFileInfo(storePath.getGroup(), storePath.getPath());

        long fileSize = fileInfo.getFileSize();

        System.out.println("文件总大小:" + fileSize);

        long slice = Math.floorDiv(fileSize, 100);

        long left = fileSize - slice * 99;

        byte[] sliceBytes = null;

        int downloadBytes = 0;

        ByteBuffer bb = new ByteBuffer();

        for (int i = 0; i < 100; i++) {

            if (i != 99) {

                sliceBytes = storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), i * slice, slice, ins -> {

                    byte[] result = IOUtils.toByteArray(ins);

                    response.getOutputStream().write(result);

                    return result;

                });

            } else {

                sliceBytes = storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), 99 * slice, left, ins -> {

                    byte[] result = IOUtils.toByteArray(ins);

                    response.getOutputStream().write(result);

                    return result;

                });

            }

            downloadBytes = downloadBytes + sliceBytes.length;

            MyWebSocket.sendInfo((i + 1) + "", userId);

        }

        response.getOutputStream().flush();

//        新起一个线程,然后按段下载文件,每段下载成功后将进度值推送到对应的用户

        System.out.println("共下载:" + downloadBytes);

    }

}

服务启动类

@SpringBootApplication

@Import(FdfsClientConfig.class)

@EnableAutoConfiguration

public class StudyApplication {

   public static void main(String[] args) {

      new SpringApplication(StudyApplication.class).run(args);

   }

}

7.html页面

<!DOCTYPE HTML>

<html>

<head>

    <title>My WebSocket</title>

</head>

<body>

Welcome<br/>

<input id="text" type="text" /><button onclick="send()">Send</button>    <button onclick="closeWebSocket()">Close</button>

<div id="message">

</div>

</body>

<script type="text/javascript">

    var websocket = null;

    //判断当前浏览器是否支持WebSocket

    if('WebSocket' in window){

websocket = new WebSocket("ws://localhost:8080/websocket/admin1");

    }

    else{

        alert('Not support websocket')

    }

    //连接发生错误的回调方法

    websocket.onerror = function(){

        setMessageInnerHTML("error");

    };

    //连接成功建立的回调方法

    websocket.onopen = function(event){

        setMessageInnerHTML("open");

    }

    //接收到消息的回调方法

    websocket.onmessage = function(event){

        setMessageInnerHTML(event.data);

    }

    //连接关闭的回调方法

    websocket.onclose = function(){

        setMessageInnerHTML("close");

    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。

    window.onbeforeunload = function(){

        websocket.close();

    }

    //将消息显示在网页上

    function setMessageInnerHTML(innerHTML){

        document.getElementById('message').innerHTML += innerHTML + '<br/>';

    }

    //关闭连接

    function closeWebSocket(){

        websocket.close();

    }

    //发送消息

    function send(){

        var message = document.getElementById('text').value;

        websocket.send(message);

    }

</script>

</html>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • JAVA面试题 1、作用域public,private,protected,以及不写时的区别答:区别如下:作用域 ...
    JA尐白阅读 1,143评论 1 0
  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢梦敢当阅读 8,876评论 0 50
  • 一. Java基础部分.................................................
    wy_sure阅读 3,785评论 0 11
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,565评论 1 114
  • 姓名:易平香 企业名称:东莞耀升机电有限公司 组别:AT感谢组/272期努力一组 【日精进打卡第70天】 【知~学...
    shine1yi阅读 164评论 0 0