SpringBoot 仿抖音短视频小程序开发(三)

SpringBoot 仿抖音短视频小程序开发(一):项目的简介( https://segmentfault.com/a/11...
SpringBoot 仿抖音短视频小程序开发(二):项目功能分析与具体实现( https://segmentfault.com/a/11...
源代码: SpringBoot 仿抖音短视频小程序开发 全栈式实战项目( https://gitee.com/scau_zns/sh...)
短视频后台管理系统:( https://gitee.com/scau_zns/sh...

小程序的后台管理系统

SpringBoot 仿抖音短视频小程序开发(三)_第1张图片

涉及的技术栈:Bootstrap + jQuery + jGrid + SSM框架 + zookeeper

一、用户列表的获取与分页

前端代码:

            

jGrid发送请求获取数据封装好展示到页面

// 用户列表
        var handleList = function() {
            
            // 上下文对象路径
            var hdnContextPath = $("#hdnContextPath").val();
            var apiServer = $("#apiServer").val();
            
            var jqGrid = $("#usersList");  
            jqGrid.jqGrid({  
                caption: "短视频用户列表",  
                url: hdnContextPath + "/users/list.action",  
                mtype: "post",  
                styleUI: 'Bootstrap',//设置jqgrid的全局样式为bootstrap样式  
                datatype: "json",  
                colNames: ['ID', '头像', '用户名', '昵称', '粉丝数', '关注数', '获赞数'],  
                colModel: [  
                    { name: 'id', index: 'id', width: 30, sortable: false, hidden: false },  
                    { name: 'faceImage', index: 'username', width: 50, sortable: false,
                        formatter:function(cellvalue, options, rowObject) {
                            
                            var src = apiServer + cellvalue;
                            var img = ""
                            return img;
                        }  
                    },
                    { name: 'username', index: 'password', width: 30, sortable: false },
                    { name: 'nickname', index: 'nickname', width: 30, sortable: false },
                    { name: 'fansCounts', index: 'age', width: 20, sortable: false },
                    { name: 'followCounts', index: 'sexValue', width: 20, sortable: false },
                    { name: 'receiveLikeCounts', index: 'province', width: 20, sortable: false, hidden: false }
                ],  
                viewrecords: true,          // 定义是否要显示总记录数
                rowNum: 10,                    // 在grid上显示记录条数,这个参数是要被传递到后台
                rownumbers: true,              // 如果为ture则会在表格左边新增一列,显示行顺序号,从1开始递增。此列名为'rn'
                autowidth: true,              // 如果为ture时,则当表格在首次被创建时会根据父元素比例重新调整表格宽度。如果父元素宽度改变,为了使表格宽度能够自动调整则需要实现函数:setGridWidth
                height: 500,                // 表格高度,可以是数字,像素值或者百分比
                rownumWidth: 36,             // 如果rownumbers为true,则可以设置行号 的宽度
                pager: "#usersListPager",        // 分页控件的id  
                subGrid: false                // 是否启用子表格
            }).navGrid('#usersListPager', {
                edit: false,
                add: false,
                del: false,
                search: false
            });
            
      
            // 随着窗口的变化,设置jqgrid的宽度  
            $(window).bind('resize', function () {  
                var width = $('.usersList_wrapper').width()*0.99;  
                jqGrid.setGridWidth(width);  
            });  
            
            // 不显示水平滚动条
            jqGrid.closest(".ui-jqgrid-bdiv").css({ "overflow-x" : "hidden" });
            
            // 条件查询所有用户列表
            $("#searchUserListButton").click(function(){
                var searchUsersListForm = $("#searchUserListForm");
                jqGrid.jqGrid().setGridParam({ 
                    page: 1,
                    url: hdnContextPath + "/users/list.action?" + searchUsersListForm.serialize(),
                }).trigger("reloadGrid");
            });
        }

后端获取用户列表分页数据的接口:

    @PostMapping("/list")
    @ResponseBody
    public PagedResult list(Users user , Integer page) {
        
        PagedResult result = usersService.queryUsers(user, page == null ? 1 : page, 10);
        return result;
    }

SpringBoot 仿抖音短视频小程序开发(三)_第2张图片
搜索功能的实现:


        

使用jGrid发送请求给后台

        // 条件查询所有用户列表
        $("#searchUserListButton").click(function(){
            var searchUsersListForm = $("#searchUserListForm");
            jqGrid.jqGrid().setGridParam({ 
                page: 1,
                url: hdnContextPath + "/users/list.action?" + searchUsersListForm.serialize(),
            }).trigger("reloadGrid");
        });

二、背景音乐BGM的上传、查询和删除

SpringBoot 仿抖音短视频小程序开发(三)_第3张图片

上传

    $("#file").fileupload({
        pasteZone: "#bgmContent",
        dataType: "json",
        done: function(e, data) {
            console.log(data);
            
            if (data.result.status != '200') {
                alert("长传失败...");
            } else {
                var bgmServer = $("#bgmServer").val();
                var url = bgmServer + data.result.data;
                $("#bgmContent").html("点我播放");
                $("#path").attr("value", data.result.data);
            }
            
        }
    });

后台接口保存BGM的方法参考上传头像的方法

SpringBoot 仿抖音短视频小程序开发(三)_第4张图片

分页查询

参考用户列表信息的分页查询多少

删除BGM

    var deleteBgm = function(bgmId) {
    var flag = window.confirm("是否确认删除???");
    if (!flag) {
        return;
    }
    $.ajax({
        url: $("#hdnContextPath").val() + '/video/delBgm.action?bgmId=' + bgmId,
        type: "POST",
        success: function(data) {
            if (data.status == 200 && data.msg == 'OK') {
                alert('删除成功~~');
                var jqGrid = $("#bgmList");  
                jqGrid.jqGrid().trigger("reloadGrid");
            }
        }
    })
}

三、举报管理

禁止播放

SpringBoot 仿抖音短视频小程序开发(三)_第5张图片

var forbidVideo = function(videoId) {
    var flag = window.confirm("是否禁播");
    if (!flag) {
        return;
    }
    $.ajax({
        url: $("#hdnContextPath").val() + "/video/forbidVideo.action?videoId=" + videoId,
        type: "POST",
        async: false,
        success: function(data) {
            if(data.status == 200 && data.msg == "OK") {
                alert("操作成功");
                var jqGrid = $("#usersReportsList");  
                //reloadGrid是重新加载表格
                jqGrid.jqGrid().trigger("reloadGrid");
            } else {
                console.log(JSON.stringify(data));
            }
        }
    })
}

四、后台管理系统增加或删除BGM,向zookeeper-server创建子节点,让小程序后端监听【重点】

1、首先安装Zookeeper到Linux上,启动服务器

SpringBoot 仿抖音短视频小程序开发(三)_第6张图片

2、编写zk客户端代码:

import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZKCurator {
    //zk客户端
    private CuratorFramework client = null;
    
    final static Logger log = LoggerFactory.getLogger(ZKCurator.class);
 
    public ZKCurator(CuratorFramework client) {
        this.client = client;
    }
    
    public void init() {
        client = client.usingNamespace("admin");
        try {
            //判断在admin命名空间下是否有bgm节点 /admin/bgm
            if( client.checkExists().forPath("/bgm") == null ) {
                //对于zk来讲,有两种类型的节点,一种是持久节点(永久存在,除非手动删除),另一种是临时节点(会话断开,自动删除)
                client.create().creatingParentContainersIfNeeded()
                .withMode(CreateMode.PERSISTENT) //持久节点
                .withACL(Ids.OPEN_ACL_UNSAFE)  //匿名权限
                .forPath("/bgm"); 
                log.info("zookeeper客户端连接初始化成功");
                log.info("zookeeper服务端状态:{}",client.isStarted());
            }
        } catch (Exception e) {
            log.error("zookeeper客户端连接初始化失败");
            e.printStackTrace();
        }
    }
    
    /**
     * 增加或者删除Bgm,向zk-server创建子节点,供小程序后端监听
     * @param bgmId
     * @param operType
     */
    public void sendBgmOperator(String bgmId, String operObject) {
        try {
            client.create().creatingParentContainersIfNeeded()
            .withMode(CreateMode.PERSISTENT) //持久节点
            .withACL(Ids.OPEN_ACL_UNSAFE)  //匿名权限
            .forPath("/bgm/" + bgmId, operObject.getBytes());

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
}

3、在applicationContext-zookeeper.xml配置zookeeper:

    
    
        
        
        
        
    
    
    
    
        
        
        
        
    
     
     
    
        
    

4、上传或者删除BGM时调用VideoServiceImpl.java的方法

    @Autowired
    private ZKCurator zKCurator;
    @Override
    public void addBgm(Bgm bgm) {
        String id = sid.nextShort();
        bgm.setId(id);
        bgmMapper.insert(bgm);
        Map map = new HashMap<>();
        map.put("operType", BGMOperatorTypeEnum.ADD.type);
        map.put("path", bgm.getPath());
        zKCurator.sendBgmOperator(id, JSONUtils.toJSONString(map));
    }

    @Override
    public void deleteBgm(String id) {
        Bgm bgm = bgmMapper.selectByPrimaryKey(id);
        
        bgmMapper.deleteByPrimaryKey(id);
        Map map = new HashMap<>();
        map.put("operType", BGMOperatorTypeEnum.DELETE.type);
        map.put("path", bgm.getPath());
        zKCurator.sendBgmOperator(id, JSONUtils.toJSONString(map));
    }

5、小程序编写代码监听zookeeper的节点,并对其做出相应的删除和上传操作【重点】

初始化zookeeper客户端

   private CuratorFramework client = null;

    final static Logger log = LoggerFactory.getLogger(ZKCuratorClient.class);

//    public static final String ZOOKEEPER_SERVER = "120.79.18.36:2181";

    public void init() {
        if(client != null) {
            return;
        }
        //重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
        //创建zk客户端  120.79.18.36:2181
        client = CuratorFrameworkFactory.builder().connectString(resourceConfig.getZookeeperServer()).sessionTimeoutMs(10000)
                .retryPolicy(retryPolicy).namespace("admin").build();
        //启动客户端
        client.start();
        try {
            addChildWatch("/bgm");
        } catch (Exception e) {
            e.printStackTrace();
        }
    } 

监听zk-server的节点,当短视频后台管理系统上传或者删除某个BGM的时候,小程序后台服务器通过Zookeeper监听自动下载背景音乐

public void addChildWatch(String nodePath) throws Exception {
        final PathChildrenCache cache = new PathChildrenCache(client, nodePath, true);
        cache.start();
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
                    log.info("监听到事件CHILD_ADDED");
                    //1. 从数据库查询bgm对象,获取路径Path
                    String path = event.getData().getPath();
                    String operatorObjStr = new String(event.getData().getData());
                    Map map = JsonUtils.jsonToPojo(operatorObjStr, Map.class);
                    String operatorType = map.get("operType");
                    String songPath = map.get("path");

//                    String[] arr = path.split("/");
//                    String bgmId = arr[arr.length-1];
//                    Bgm bgm =  bgmService.queryBgmById(bgmId);
//                    if(bgm == null){
//                        return;
//                    }
                    //1.1 bgm所在的相对路径
//                String songPath = bgm.getPath();

                    //2. 定义保存到本地的bgm路径
//                String filePath = "E:\\imooc_videos_dev" + songPath;
                    String filePath = resourceConfig.getFileSpace() + songPath;

                    //3. 定义下载的路径(播放url)
                    String[] arrPath = songPath.split("\\\\"); //windows
//                    String[] arrPath = songPath.split("/"); //linux
                    String finalPath = "";
                    //3.1 处理url的斜杠以及编码
                    for(int i=0; i

你可能感兴趣的:(ssm,bootstrap,jquery,java,springboot)