java写ftp服务播放视频,上传视频(前端+后端)

后端一共就三个接口,获取列表,获取视频,以及上传视频


    //利用ftp技术,将文件上传到ftp服务器
    @CrossOrigin(origins = "*") // 允许任何来源的请求
    @PostMapping("/uploadFileToFTP")
    //ftp 上传方法
    public  boolean uploadFile(@RequestParam("file") MultipartFile file,@RequestParam("batchId") String batchId) throws IOException {
        boolean flag = uploadFile(FTPProperties.getServer(),FTPProperties.getPort(),FTPProperties.getUsername(),
                FTPProperties.getPassword(),batchId,"video",file.getOriginalFilename(),file.getInputStream());
        //根据反馈输出日志
        if (flag){
            log.info("上传成功,文件名为:"+file.getOriginalFilename()+"文件大小="+file.getSize()+"字节"+"MB="+file.getSize()/1024/1024+"MB");
        }else {
            log.error("上传失败,文件名为:"+file.getOriginalFilename()+"文件大小="+file.getSize()+"字节"+"MB="+file.getSize()/1024/1024+"MB");
        }
            return flag;
    }

    /**
     * #!/bin/bash
     *
     * # 安装vsftpd
     * sudo yum remove vsftpd -y
     * sudo yum install vsftpd -y
     *
     * # 启动vsftpd服务
     * sudo systemctl start vsftpd
     *
     * # 检查服务状态
     * sudo systemctl status vsftpd
     * 云服务器记得开端口
     *
     * 创建一个新用户
     * 切记 必须在/etc/vsftpd/user_list
     *
     * 指定允许使用vsftpd的用户列表文件=》 也就是自己的用户名,要不然访问530错误
     * @param url
     * @param port
     * @param username
     * @param password
     * @param path
     * @param path1
     * @param filename
     * @param input
     * @return
     */

    public  boolean uploadFile(String url,// FTP服务器hostname
                                     int port,// FTP服务器端口
                                     String username, // FTP登录账号
                                     String password, // FTP登录密码
                                     String path, // FTP服务器保存目录
                                     String path1, // FTP服务器保存目录1
                                     String filename, // 上传到FTP服务器上的文件名
                                     InputStream input // 输入流
    ){
        boolean success = false;
        FTPClient ftp = new FTPClient();
        ftp.setControlEncoding("UTF-8");
        try {
            int reply;
            ftp.connect(url, port);// 连接FTP服务器
            // 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            ftp.login(username, password);// 登录
            reply = ftp.getReplyCode();// 获取服务器的响应码。
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return success;
            }
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftp.makeDirectory(path);  //创建文件夹
            ftp.changeWorkingDirectory(path);  //切换到文件夹
//            ftp.makeDirectory(path1);
//            ftp.changeWorkingDirectory(path1);
            boolean b = ftp.storeFile(filename, input);//最终默认上传到 /home/ftpuser 目录下  批次id目录内
            if (b){
                //异步写入日志
                asynWriteVideoImportLog(path, filename, input);
            }
            input.close();
            ftp.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }

    @Async("normalThreadPool")
    public void asynWriteVideoImportLog(String path, String filename, InputStream input) throws IOException {
        //写入日志
        FtpImportTableEntity ftpImportTableEntity = new FtpImportTableEntity();
        ftpImportTableEntity.setFileName(filename);
        ftpImportTableEntity.setAddress(path +"/"+ filename);
        ftpImportTableEntity.setSize((int) input.available());
        ftpImportTableEntity.setTester(Long.parseLong(filename.split("_")[1]));
        ftpImportTableEntity.setTime(LocalDateTime.now());
        ftpImportTableEntity.setBatch(Long.parseLong(path));
        ftpImportTableService.save(ftpImportTableEntity);
    }
    @CrossOrigin(origins = "*") // 允许任何来源的请求
    @GetMapping("/ftp/getVideo")
    public void getVideo(HttpServletResponse response, @RequestParam String videoPath, @RequestParam String videoName) {
        //创建FTPClient
        FTPClient ftp = new FTPClient();
        ftp.setControlEncoding("UTF-8");
        try {
            int reply;
            ftp.connect(FTPProperties.getServer(), FTPProperties.getPort());// 连接FTP服务器
            // 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            ftp.login(FTPProperties.getUsername(), FTPProperties.getPassword());// 登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
            }
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftp.changeWorkingDirectory(videoPath);//切换到文件保存目录

            FTPFile[] ftpFiles = ftp.listFiles();//获取FTP服务器上的文件别表
            InputStream in = null;
            for (FTPFile file : ftpFiles) {  //遍历文件列表
                // 取得指定文件
                if (file.getName().equals(videoName)) {
                    if (file.isFile()) {
                        String fileName = file.getName();
                        //获取文件流
                        in = ftp.retrieveFileStream(new String(fileName.getBytes("gbk"), "ISO-8859-1"));
                        //创建ByteArrayOutputStream
                        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                        int ch;
                        //循环将文件流写入ByteArrayOutputStream 中
                        while ((ch = in.read()) != -1) {
                            swapStream.write(ch);
                        }
                        //将ByteArrayOutputStream 转成byte[]
                        byte[] bytes = swapStream.toByteArray();
                        //通过输出流输出即可
                        response.getOutputStream().write(bytes);
                        in.close();
                    }
                }
            }

        } catch (SocketException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @CrossOrigin(origins = "*") // 允许任何来源的请求
    @GetMapping("/ftp/getVideoList")
    public List<VideoInfo> getVideoList() {
        List<VideoInfo> videoList = new ArrayList<>();

        // 连接FTP服务器
        FTPClient ftp = new FTPClient();
        ftp.setControlEncoding("UTF-8");

        try {
            int reply;
            ftp.connect(FTPProperties.getServer(), FTPProperties.getPort());
            ftp.login(FTPProperties.getUsername(), FTPProperties.getPassword());
            reply = ftp.getReplyCode();

            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
            }

            FTPFile[] files = ftp.listFiles(); // 获取FTP服务器上所有文件
            for (FTPFile file : files) {
                listFilesRecursive(ftp, "/home/ftpuser", videoList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ftp.logout();
                ftp.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return videoList;
    }


    private void listFilesRecursive(FTPClient ftp, String path, List<VideoInfo> videoList) throws IOException {
        FTPFile[] files = ftp.listFiles(path);
        for (FTPFile file : files) {
            if (file.isDirectory()) {
                // 如果是文件夹,递归进入文件夹
                listFilesRecursive(ftp, path + "/"+ file.getName() , videoList);
            } else if (file.getName().toLowerCase().endsWith(".mp4")) {
                // 处理视频文件
                String videoPath = path ; // 视频文件路径
                String videoName = file.getName(); // 视频文件名称
                videoList.add(new VideoInfo(videoPath, videoName));
            }
        }
    }

前端就是简单的html

上传:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Layui Upload Example</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/layui/2.6.8/css/layui.css">
    <script src="https://cdn.staticfile.org/layui/2.6.8/layui.js"></script>
    <style>
        .layui-progress-big {
            width: 200px;
        }
    </style>
</head>
<body>
<div class="layui-col-md12">
    <div class="layui-card">
        <div class="layui-card-body">
            <div class="layui-upload">
                <button type="button" class="layui-btn layui-btn-normal" id="test-upload-testList">选择文件</button>(可同时选择多个文件,不能重名,视频大小不能超过300M)
                <div class="layui-upload-list">
                    <table class="layui-table">
                        <thead>
                        <tr>
                            <th>文件名</th>
                            <th>大小</th>
                            <th>上传进度</th>
                            <th>状态</th>
                            <th>操作</th>
                        </tr>
                        </thead>
                        <tbody id="test-upload-demoList"></tbody>
                    </table>
                </div>
                <button type="button" class="layui-btn" id="test-upload-testListAction" onclick="gbtxt()">开始上传</button>
            </div>
        </div>
    </div>
</div>

<script>
    layui.config({
        base: '${ctxPath}/static/layuiadmin/' // 静态资源所在路径
    }).extend({
        index: 'lib/index' // 主入口模块
    }).use(['element','form','layer'], function(){
        var $ = layui.$
            ,form = layui.form
            ,upload = layui.upload;

        var element = layui.element;
        var demoListView = $('#test-upload-demoList');
        // 在获取 id 变量之前,先检查是否找到 id 为 "carsid" 的元素
        var carsidElement = document.getElementById("carsid");
        var id = carsidElement ? carsidElement.value : 'default value' // 如果没有找到合适的元素,可以使用默认值
        // var id = document.getElementById("carsid").value
            ,uploadListIns = upload.render({
                elem: '#test-upload-testList',
                url: 'http://localhost:8080/uploadFileToFTP',
                accept: 'video',
                data: {"id": id, "batchId": 1765649974278980867},
                multiple: true,
                auto: false,
                bindAction: '#test-upload-testListAction',
                before: function (obj, index) {
                    layer.load();
                    var n = 0;
                    timer = setInterval(function(){
                        n = n + Math.random() * 10 | 0;
                        if (n > 95){
                            n = 95;
                            clearInterval(timer);
                        }
                        element.progress('progress_' + index, n + '%');
                    }, 50 + Math.random() * 100);
                },
                choose: function(obj){
                    var btnname = document.getElementById("test-upload-testListAction");
                    btnname.innerHTML = "开始上传";
                    document.getElementById("test-upload-testListAction").disabled = false;
                    var files = this.files = obj.pushFile(); // 将每次选择的文件追加到文件队列
                    // 读取本地文件
                    obj.preview(function(index, file, result){
                        var tr = $(['<tr id="upload-'+ index +'">',
                            '<td>'+ file.name +'</td>',
                            '<td>'+ (file.size/1024).toFixed(1) +'kb</td>',
                            '<td><div class="layui-progress layui-progress-big" lay-filter="progress_'+index+'" lay-showPercent="true"><div class="layui-progress-bar" lay-percent="0%"></div></div></td>',
                            '<td>等待上传</td>',
                            '<td>',
                            '<button class="layui-btn layui-btn-mini test-upload-demo-reload layui-hide">重传</button>',
                            '<button class="layui-btn layui-btn-mini layui-btn-danger test-upload-demo-delete">删除</button>',
                            '</td>',
                            '</tr>'].join(''));

                        // 单个重传
                        tr.find('.test-upload-demo-reload').on('click', function(){
                            obj.upload(index, file);
                        });

                        // 删除
                        tr.find('.test-upload-demo-delete').on('click', function(){
                            delete files[index]; // 删除对应的文件
                            tr.remove();
                            uploadListIns.config.elem.next()[0].value = ''; // 清空 input file 值,以免删除后出现同名文件不可选
                        });
                        demoListView.append(tr);
                    });
                },
                allDone: function(obj) {
                    var btnname = document.getElementById("test-upload-testListAction");
                    btnname.innerHTML = "上传完成";
                    document.getElementById("test-upload-testListAction").disabled = true;
                    layer.closeAll();
                },
                done: function(res, index, upload){
                    element.progress('progress_' + index, '100%');   // 上传成功
                    //输出返回的res
                    console.log("res=",res)
                    if (res){
                        var tr = demoListView.find('tr#upload-'+ index)
                            ,tds = tr.children();
                        tds.eq(3).html('<span style="color: #5FB878;">上传成功</span>');
                        tds.eq(4).html(''); // 清空操作
                        return delete this.files[index]; // 删除文件队列已经上传成功的文件
                    }else {
                        var tr = demoListView.find('tr#upload-'+ index)
                            ,tds = tr.children();
                        tds.eq(3).html('<span style="color: #FF5722;">上传失败</span>');
                        tds.eq(4).find('.test-upload-demo-reload').removeClass('layui-hide'); // 显示重传
                    }
                    this.error(index, upload);
                },
                error: function(index, upload){
                    var tr = demoListView.find('tr#upload-'+ index)
                        ,tds = tr.children();
                    tds.eq(3).html('<span style="color: #FF5722;">上传失败</span>');
                    tds.eq(4).find('.test-upload-demo-reload').removeClass('layui-hide'); // 显示重传
                }
            });
    });

    function gbtxt() {
        var btnname = document.getElementById("test-upload-testListAction");
        btnname.innerHTML = "上传中,请稍候...";
        document.getElementById("test-upload-testListAction").disabled = true;
    }
</script>
</body>
</html>

播放:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>FTP Video Player</title>
  <style>
    /* 调整视频列表样式 */
    #videoList {
      list-style-type: none;
      padding: 0;
      margin: 20px 0;
      display: flex;
      flex-wrap: wrap;
    }

    #videoList li {
      flex: 0 0 calc(33% - 20px); /* 计算三分之一宽度,减去间隔 */
      margin: 10px;
      border: 1px solid #ccc;
      border-radius: 5px;
    }

    #videoList li a {
      display: block;
      text-decoration: none;
      color: #333;
      font-weight: bold;
      padding: 10px;
    }

    #videoList li a:hover {
      color: #0066cc;
    }


    .popup {
      display: none;
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.8); /* 半透明黑色背景 */
      z-index: 9999;
    }

    .video-container {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      max-width: 90%;
      max-height: 90%;
    }

    .close-icon {
      position: absolute;
      top: 10px;
      right: 10px;
      color: #fff;
      cursor: pointer;
    }
  </style>
</head>
<body>
<h1>FTP Video Player</h1>
<ul id="videoList"></ul>

<div class="popup" id="videoPopup">
  <span class="close-icon" onclick="closeVideoPopup()">Close &#10005;</span>
  <div class="video-container">
    <video id="popupVideoPlayer" controls>
      Your browser does not support the video tag.
    </video>
  </div>
</div>

<script>
  fetch('http://localhost:8080/ftp/getVideoList') // 后端接口获取FTP上的视频文件列表
          .then(response => response.json())
          .then(data => {
            const videoList = document.getElementById('videoList');
            data.forEach(video => {
              const li = document.createElement('li');
              const link = document.createElement('a');
              link.href = '#';
              link.textContent = video.name;
              link.addEventListener('click', () => openVideoPopup(video.path, video.name));
              li.appendChild(link);
              videoList.appendChild(li);
            });
          })
          .catch(error => console.error(error));

  function openVideoPopup(videoPath, videoName) {
    const videoPopup = document.getElementById('videoPopup');
    const popupVideoPlayer = document.getElementById('popupVideoPlayer');
    popupVideoPlayer.src = `http://localhost:8080/ftp/getVideo?videoPath=${videoPath}&videoName=${videoName}`;
    videoPopup.style.display = 'block';
  }

  function closeVideoPopup() {
    const videoPopup = document.getElementById('videoPopup');
    videoPopup.style.display = 'none';
  }
</script>
</body>
</html>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值