• SpringBoot实现微信短视频小程序


    小程序页面目录:

    index 首页

    userRegist 用户注册页面

    userLogin 用户登录页面

    chooseBgm 选择背景音乐页面

    resource 图片存放目录

    1.用户注册实现

    1.1 注册页面

    regist.wxml

    
        
        
    

    1.2 注册接口

    @ApiOperation(value="用户注册", notes="用户注册的接口")
    	@PostMapping("/regist")
    	public IMoocJSONResult regist(@RequestBody Users user) throws Exception {
    		
    		// 1. 判断用户名和密码必须不为空
    		if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
    			return IMoocJSONResult.errorMsg("用户名和密码不能为空");
    		}
    		
    		// 2. 判断用户名是否存在
    		boolean usernameIsExist = userService.queryUsernameIsExist(user.getUsername());
    		
    		// 3. 保存用户,注册信息
    		if (!usernameIsExist) {
    			user.setNickname(user.getUsername());
    			user.setPassword(MD5Utils.getMD5Str(user.getPassword()));
    			user.setFansCounts(0);
    			user.setReceiveLikeCounts(0);
    			user.setFollowCounts(0);
    			userService.saveUser(user);
    		} else {
    			return IMoocJSONResult.errorMsg("用户名已经存在,请换一个再试");
    		}
    		user.setPassword("");
    		UsersVO userVO = setUserRedisSessionToken(user);
    		return IMoocJSONResult.ok(userVO);
    	}
    	
    	public UsersVO setUserRedisSessionToken(Users userModel) {
    		String uniqueToken = UUID.randomUUID().toString();
    		redis.set(USER_REDIS_SESSION + ":" + userModel.getId(), uniqueToken, 1000 * 60 * 30);
    		
    		UsersVO userVO = new UsersVO();
    		BeanUtils.copyProperties(userModel, userVO);
    		userVO.setUserToken(uniqueToken);
    		return userVO;
    	}

    1.3.交互

    点击注册按钮,提交表单,

    ,

    js执行doRegist方法,使用e.detail.value获取表单对象,进而获取用户名和密码,验证用户名和密码的长度是否为0,为0表示为空,验证通过后,展示一个弹框请等待,使用wx.request请求后台注册接口,如果后台返回code为200时,wx.hideLoading();去掉弹框,并弹出用户注册成功,app.setGlobalUserInfo(res.data.data);将用户信息存储到全局对象app中,使用 wx.redirectTo跳转到我的页面

    doRegist: function(e) {
          var me = this;
          var formObject = e.detail.value;
          var username = formObject.username;
          var password = formObject.password;
    
          // 简单验证
          if (username.length == 0 || password.length == 0) {
            wx.showToast({
              title: '用户名或密码不能为空',
              icon: 'none',
              duration: 3000
            })
          } else {
            var serverUrl = app.serverUrl;
            wx.showLoading({
              title: '请等待...',
            });
            wx.request({
              url: serverUrl + '/regist',
              method: "POST",
              data: {
                username: username,
                password: password
              },
              header: {
                'content-type': 'application/json' // 默认值
              },
              success: function(res) {
                console.log(res.data);
                wx.hideLoading();
                var status = res.data.status;
                if (status == 200) {
                  wx.showToast({
                    title: "用户注册成功~!!!",
                    icon: 'none',
                    duration: 3000
                  }),
                  // app.userInfo = res.data.data;
                  // fixme 修改原有的全局对象为本地缓存
                  app.setGlobalUserInfo(res.data.data);
                  // 页面跳转
                    wx.redirectTo({
                      url: '../mine/mine',
                    })
                } else if (status == 500) {
                  wx.showToast({
                    title: res.data.msg,
                    icon: 'none',
                    duration: 3000
                  })
                }
              }
            })
          }
        },

    点击返回登录按钮,触发事件bindtap="goLoginPage"

    goLoginPage:function() {
          wx.navigateTo({
            url: '../userLogin/login',
          })
        }

    使用wx.navigateTo跳转到登录页面

    2.用户登录实现

    2.1 登录页面

    login.wxml

    
        
        
    

    2.2 登录接口

    @ApiOperation(value="用户登录", notes="用户登录的接口")
    	@PostMapping("/login")
    	public IMoocJSONResult login(@RequestBody Users user) throws Exception {
    		String username = user.getUsername();
    		String password = user.getPassword();
    		
    //		Thread.sleep(3000);
    		
    		// 1. 判断用户名和密码必须不为空
    		if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
    			return IMoocJSONResult.ok("用户名或密码不能为空...");
    		}
    		
    		// 2. 判断用户是否存在
    		Users userResult = userService.queryUserForLogin(username, 
    				MD5Utils.getMD5Str(user.getPassword()));
    		
    		// 3. 返回
    		if (userResult != null) {
    			userResult.setPassword("");
    			UsersVO userVO = setUserRedisSessionToken(userResult);
    			return IMoocJSONResult.ok(userVO);
    		} else {
    			return IMoocJSONResult.errorMsg("用户名或密码不正确, 请重试...");
    		}
    	}

    2.3 交互

    进入登录页面,加载onLoad()方法

    onLoad: function (params) {
        var me = this;
        var redirectUrl = params.redirectUrl;
        // debugger;
        if (redirectUrl != null && redirectUrl != undefined && redirectUrl != '') {
          redirectUrl = redirectUrl.replace(/#/g, "?");
          redirectUrl = redirectUrl.replace(/@/g, "=");
    
          me.redirectUrl = redirectUrl;
        }
      },

    点击登录按钮,提交表单

    先使用e.detail.value获取表单对象,进行获取用户名和密码,对其验证是否为空,弹出请等待框,使用wx.request请求后台登录接口,在success回调方法中去掉弹框,如果返回的code为200则弹出登录成功,将用户对象设置到全局对象app中,跳转到我的页面

     // 登录  
      doLogin: function (e) {
        var me = this;
        var formObject = e.detail.value;
        var username = formObject.username;
        var password = formObject.password;
        // 简单验证
        if (username.length == 0 || password.length == 0) {
          wx.showToast({
            title: '用户名或密码不能为空',
            icon: 'none',
            duration: 3000
          })
        } else {
          var serverUrl = app.serverUrl;
          wx.showLoading({
            title: '请等待...',
          });
          // 调用后端
          wx.request({
            url: serverUrl + '/login',
            method: "POST",
            data: {
              username: username,
              password: password
            },
            header: {
              'content-type': 'application/json' // 默认值
            },
            success: function (res) {
              console.log(res.data);
              wx.hideLoading();
              if (res.data.status == 200) {
                // 登录成功跳转 
                wx.showToast({
                  title: '登录成功',
                  icon: 'success',
                  duration: 2000
                });
                // app.userInfo = res.data.data;
                // fixme 修改原有的全局对象为本地缓存
                app.setGlobalUserInfo(res.data.data);
                // 页面跳转
    
                var redirectUrl = me.redirectUrl;
                if (redirectUrl != null && redirectUrl != undefined && redirectUrl != '') {
                  wx.redirectTo({
                    url: redirectUrl,
                  })
                } else {
                  wx.redirectTo({
                    url: '../mine/mine',
                  })
                }
                
              } else if (res.data.status == 500) {
                // 失败弹出框
                wx.showToast({
                  title: res.data.msg,
                  icon: 'none',
                  duration: 3000
                })
              }
            }
          })
        }
      },

    点击 没有账号?点击注册 触发事件

    bindtap="goRegistPage"

      goRegistPage:function() {
        wx.redirectTo({
          url: '../userRegist/regist',
        })
      }

    跳转到注册页面

    3.上传头像实现

    3.1 上传代码

    mine.wxml

    
          
        

    isMe字段定义在js里面,标识是否是当前登录用户,这里分为2中情况:

    1)登录的用户

    2)从视频详情里面的发布者点击进去,跳转到我的页面,该页面只能查看自己的头像

    页面加载函数的逻辑:

    根据params.publisherId判断是否是当前登录用户,为空就是当前登录用户,不为空就是视频发布者用户,设置用户id,调用查询用户信息接口,获取用户信息

    onLoad: function (params) {
        var me = this;
    
        // var user = app.userInfo;
        // fixme 修改原有的全局对象为本地缓存
        var user = app.getGlobalUserInfo();
        var userId = user.id;
    
        var publisherId = params.publisherId;
        if (publisherId != null && publisherId != '' && publisherId != undefined) {
          userId = publisherId;
          me.setData({
            isMe: false,
            publisherId: publisherId,
            serverUrl: app.serverUrl
          })
        }
        me.setData({
          userId: userId
        })
    
    
        wx.showLoading({
          title: '请等待...',
        });
        var serverUrl = app.serverUrl;
        // 调用后端
        wx.request({
          url: serverUrl + '/user/query?userId=' + userId + "&fanId=" + user.id,
          method: "POST",
          header: {
            'content-type': 'application/json', // 默认值
            'headerUserId': user.id,
            'headerUserToken': user.userToken
          },
          success: function (res) {
            console.log(res.data);
            wx.hideLoading();
            if (res.data.status == 200) {
              var userInfo = res.data.data;
              var faceUrl = "../resource/images/noneface.png";
              if (userInfo.faceImage != null && userInfo.faceImage != '' && userInfo.faceImage != undefined) {
                faceUrl = serverUrl + userInfo.faceImage;
              }
    
    
              me.setData({
                faceUrl: faceUrl,
                fansCounts: userInfo.fansCounts,
                followCounts: userInfo.followCounts,
                receiveLikeCounts: userInfo.receiveLikeCounts,
                nickname: userInfo.nickname,
                isFollow: userInfo.follow
              });
            } else if (res.data.status == 502) {
              wx.showToast({
                title: res.data.msg,
                duration: 3000,
                icon: "none",
                success: function () {
                  wx.redirectTo({
                    url: '../userLogin/login',
                  })
                }
              })
            }
          }
        })
    
        me.getMyVideoList(1);
      },

    changeFace()事件,使用wx.chooseImage返回上传后的文件路径,wx.uploadFile调用上传头像接口

    changeFace: function () {
        var me = this;
        wx.chooseImage({
          count: 1,
          sizeType: ['compressed'],
          sourceType: ['album'],
          success: function (res) {
            var tempFilePaths = res.tempFilePaths;
            console.log(tempFilePaths);
    
            wx.showLoading({
              title: '上传中...',
            })
            var serverUrl = app.serverUrl;
            // fixme 修改原有的全局对象为本地缓存
            var userInfo = app.getGlobalUserInfo();
    
            wx.uploadFile({
              url: serverUrl + '/user/uploadFace?userId=' + userInfo.id,  //app.userInfo.id,
              filePath: tempFilePaths[0],
              name: 'file',
              header: {
                'content-type': 'application/json', // 默认值
                'headerUserId': userInfo.id,
                'headerUserToken': userInfo.userToken
              },
              success: function (res) {
                var data = JSON.parse(res.data);
                console.log(data);
                wx.hideLoading();
                if (data.status == 200) {
                  wx.showToast({
                    title: '上传成功!~~',
                    icon: "success"
                  });
    
                  var imageUrl = data.data;
                  me.setData({
                    faceUrl: serverUrl + imageUrl
                  });
    
                } else if (data.status == 500) {
                  wx.showToast({
                    title: data.msg
                  });
                } else if (res.data.status == 502) {
                  wx.showToast({
                    title: res.data.msg,
                    duration: 2000,
                    icon: "none",
                    success: function () {
                      wx.redirectTo({
                        url: '../userLogin/login',
                      })
                    }
                  });
    
                }
    
              }
            })
    
    
          }
        })
      },

    3.2 上传头像接口

    @ApiOperation(value="用户上传头像", notes="用户上传头像的接口")
    	@ApiImplicitParam(name="userId", value="用户id", required=true, 
    						dataType="String", paramType="query")
    	@PostMapping("/uploadFace")
    	public IMoocJSONResult uploadFace(String userId, 
    				@RequestParam("file") MultipartFile[] files) throws Exception {
    		
    		if (StringUtils.isBlank(userId)) {
    			return IMoocJSONResult.errorMsg("用户id不能为空...");
    		}
    		
    		// 文件保存的命名空间
    		String fileSpace = "C:/imooc_videos_dev";
    		// 保存到数据库中的相对路径
    		String uploadPathDB = "/" + userId + "/face";
    		
    		FileOutputStream fileOutputStream = null;
    		InputStream inputStream = null;
    		try {
    			if (files != null && files.length > 0) {
    				
    				String fileName = files[0].getOriginalFilename();
    				if (StringUtils.isNotBlank(fileName)) {
    					// 文件上传的最终保存路径
    					String finalFacePath = fileSpace + uploadPathDB + "/" + fileName;
    					// 设置数据库保存的路径
    					uploadPathDB += ("/" + fileName);
    					
    					File outFile = new File(finalFacePath);
    					if (outFile.getParentFile() != null || !outFile.getParentFile().isDirectory()) {
    						// 创建父文件夹
    						outFile.getParentFile().mkdirs();
    					}
    					
    					fileOutputStream = new FileOutputStream(outFile);
    					inputStream = files[0].getInputStream();
    					IOUtils.copy(inputStream, fileOutputStream);
    				}
    				
    			} else {
    				return IMoocJSONResult.errorMsg("上传出错...");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			return IMoocJSONResult.errorMsg("上传出错...");
    		} finally {
    			if (fileOutputStream != null) {
    				fileOutputStream.flush();
    				fileOutputStream.close();
    			}
    		}
    		
    		Users user = new Users();
    		user.setId(userId);
    		user.setFaceImage(uploadPathDB);
    		userService.updateUserInfo(user);
    		
    		return IMoocJSONResult.ok(uploadPathDB);
    	}

    4.上传作品功能

    4.1 上传作品代码

    uploadVideo事件,wx.chooseVideo打开选择视频控件,选择好视频后,打开选择背景音频页面并携带相关参数

    uploadVideo: function () {
        // fixme 视频上传复用
        // videoUtil.uploadVideo();
        // 以下是原来的代码,不删除,便于参照
        var me = this;
    
        wx.chooseVideo({
          sourceType: ['album'],
          success: function (res) {
            console.log(res);
    
            var duration = res.duration;
            var tmpHeight = res.height;
            var tmpWidth = res.width;
            var tmpVideoUrl = res.tempFilePath;
            var tmpCoverUrl = res.thumbTempFilePath;//图片临时目录
    
            if (duration > 11) {
              wx.showToast({
                title: '视频长度不能超过10秒...',
                icon: "none",
                duration: 2500
              })
            } else if (duration < 1) {
              wx.showToast({
                title: '视频长度太短,请上传超过1秒的视频...',
                icon: "none",
                duration: 2500
              })
            } else {
              // 打开选择bgm的页面
              wx.navigateTo({
                url: '../chooseBgm/chooseBgm?duration=' + duration
                + "&tmpHeight=" + tmpHeight
                + "&tmpWidth=" + tmpWidth
                + "&tmpVideoUrl=" + tmpVideoUrl
                + "&tmpCoverUrl=" + tmpCoverUrl
                ,
              })
            }
    
          }
        })
    
      },

    4.2 bgm页面

    
        
    
            
    
    
              
                
              
              
            
              
    
    
            
    
            
                
                
            
    
            
            
            
            
        
    

    页面加载函数,onLoad(),使用wx.request请求后台背景音频列表接口展示在页面

    onLoad: function (params) {
          
          var me = this;
          console.log(params);
          me.setData({
            videoParams: params
          });
    
          wx.showLoading({
            title: '请等待...',
          });
          var serverUrl = app.serverUrl;
          var user = app.getGlobalUserInfo();
          debugger;
          // 调用后端
          wx.request({
            url: serverUrl + '/bgm/list',
            method: "POST",
            header: {
              'content-type': 'application/json', // 默认值
              'headerUserId': user.id,
              'headerUserToken': user.userToken
            },
            success: function (res) {
              console.log(res.data);
              wx.hideLoading();
              if (res.data.status == 200) {
                var bgmList = res.data.data;
                me.setData({
                  bgmList: bgmList,
                  serverUrl: serverUrl
                });
              } else if (res.data.status == 502) {
                wx.showToast({
                  title: res.data.msg,
                  duration: 2000,
                  icon: "none",
                  success: function () {
                    wx.redirectTo({
                      url: '../userLogin/login',
                    })
                  }
                });
              }
            }
          })
        },

    4.3 交互

    ,使用 wx.uploadFile调用后台上传视频接口

    upload: function(e) {
          var me = this;
    
          var bgmId = e.detail.value.bgmId;
          var desc = e.detail.value.desc;
    
          console.log("bgmId:" + bgmId);
          console.log("desc:" + desc);
    
          var duration = me.data.videoParams.duration;
          var tmpHeight = me.data.videoParams.tmpHeight;
          var tmpWidth = me.data.videoParams.tmpWidth;
          var tmpVideoUrl = me.data.videoParams.tmpVideoUrl;
          var tmpCoverUrl = me.data.videoParams.tmpCoverUrl;
    
          // 上传短视频
          wx.showLoading({
            title: '上传中...',
          })
          var serverUrl = app.serverUrl;
          // fixme 修改原有的全局对象为本地缓存
          var userInfo = app.getGlobalUserInfo();
    
          wx.uploadFile({
            url: serverUrl + '/video/upload',
            formData: {
              userId: userInfo.id,    // fixme 原来的 app.userInfo.id
              bgmId: bgmId,
              desc: desc,
              videoSeconds: duration,
              videoHeight: tmpHeight,
              videoWidth: tmpWidth
            },
            filePath: tmpVideoUrl,
            name: 'file',
            header: {
              'content-type': 'application/json', // 默认值
              'headerUserId': userInfo.id,
              'headerUserToken': userInfo.userToken
            },
            success: function (res) {
              var data = JSON.parse(res.data);
              wx.hideLoading();
              if (data.status == 200) {
                wx.showToast({
                  title: '上传成功!~~',
                  icon: "success"
                });     
                // 上传成功后跳回之前的页面
                wx.navigateBack({
                  delta: 1
                })
    
              } else if (res.data.status == 502) {
                wx.showToast({
                  title: res.data.msg,
                  duration: 2000,
                  icon: "none"
                });
                wx.redirectTo({
                  url: '../userLogin/login',
                })
              } else {
                wx.showToast({
                  title: '上传失败!~~',
                  icon: "success"
                });
              }
    
            }
          })
        }

    4.4 上传视频接口

    @ApiOperation(value="上传视频", notes="上传视频的接口")
    	@ApiImplicitParams({
    		@ApiImplicitParam(name="userId", value="用户id", required=true, 
    				dataType="String", paramType="form"),
    		@ApiImplicitParam(name="bgmId", value="背景音乐id", required=false, 
    				dataType="String", paramType="form"),
    		@ApiImplicitParam(name="videoSeconds", value="背景音乐播放长度", required=true, 
    				dataType="String", paramType="form"),
    		@ApiImplicitParam(name="videoWidth", value="视频宽度", required=true, 
    				dataType="String", paramType="form"),
    		@ApiImplicitParam(name="videoHeight", value="视频高度", required=true, 
    				dataType="String", paramType="form"),
    		@ApiImplicitParam(name="desc", value="视频描述", required=false, 
    				dataType="String", paramType="form")
    	})
    	@PostMapping(value="/upload", headers="content-type=multipart/form-data")
    	public IMoocJSONResult upload(String userId, 
    				String bgmId, double videoSeconds, 
    				int videoWidth, int videoHeight,
    				String desc,
    				@ApiParam(value="短视频", required=true)
    				MultipartFile file) throws Exception {
    		
    		if (StringUtils.isBlank(userId)) {
    			return IMoocJSONResult.errorMsg("用户id不能为空...");
    		}
    		
    		// 文件保存的命名空间
    //		String fileSpace = "C:/imooc_videos_dev";
    		// 保存到数据库中的相对路径
    		String uploadPathDB = "/" + userId + "/video";
    		String coverPathDB = "/" + userId + "/video";
    		
    		FileOutputStream fileOutputStream = null;
    		InputStream inputStream = null;
    		// 文件上传的最终保存路径
    		String finalVideoPath = "";
    		try {
    			if (file != null) {
    				
    				String fileName = file.getOriginalFilename();
    				// abc.mp4
    				String arrayFilenameItem[] =  fileName.split("\\.");
    				String fileNamePrefix = "";
    				for (int i = 0 ; i < arrayFilenameItem.length-1 ; i ++) {
    					fileNamePrefix += arrayFilenameItem[i];
    				}
    				// fix bug: 解决小程序端OK,PC端不OK的bug,原因:PC端和小程序端对临时视频的命名不同
    //				String fileNamePrefix = fileName.split("\\.")[0];
    				
    				if (StringUtils.isNotBlank(fileName)) {
    					
    					finalVideoPath = FILE_SPACE + uploadPathDB + "/" + fileName;
    					// 设置数据库保存的路径
    					uploadPathDB += ("/" + fileName);
    					coverPathDB = coverPathDB + "/" + fileNamePrefix + ".jpg";
    					
    					File outFile = new File(finalVideoPath);
    					if (outFile.getParentFile() != null || !outFile.getParentFile().isDirectory()) {
    						// 创建父文件夹
    						outFile.getParentFile().mkdirs();
    					}
    					
    					fileOutputStream = new FileOutputStream(outFile);
    					inputStream = file.getInputStream();
    					IOUtils.copy(inputStream, fileOutputStream);
    				}
    				
    			} else {
    				return IMoocJSONResult.errorMsg("上传出错...");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			return IMoocJSONResult.errorMsg("上传出错...");
    		} finally {
    			if (fileOutputStream != null) {
    				fileOutputStream.flush();
    				fileOutputStream.close();
    			}
    		}
    		
    		// 判断bgmId是否为空,如果不为空,
    		// 那就查询bgm的信息,并且合并视频,生产新的视频
    		if (StringUtils.isNotBlank(bgmId)) {
    			Bgm bgm = bgmService.queryBgmById(bgmId);
    			String mp3InputPath = FILE_SPACE + bgm.getPath();
    			
    			MergeVideoMp3 tool = new MergeVideoMp3(FFMPEG_EXE);
    			String videoInputPath = finalVideoPath;
    			
    			String videoOutputName = UUID.randomUUID().toString() + ".mp4";
    			uploadPathDB = "/" + userId + "/video" + "/" + videoOutputName;
    			finalVideoPath = FILE_SPACE + uploadPathDB;
    			tool.convertor(videoInputPath, mp3InputPath, videoSeconds, finalVideoPath);
    		}
    		System.out.println("uploadPathDB=" + uploadPathDB);
    		System.out.println("finalVideoPath=" + finalVideoPath);
    		
    		// 对视频进行截图
    		FetchVideoCover videoInfo = new FetchVideoCover(FFMPEG_EXE);
    		videoInfo.getCover(finalVideoPath, FILE_SPACE + coverPathDB);
    		
    		// 保存视频信息到数据库
    		Videos video = new Videos();
    		video.setAudioId(bgmId);
    		video.setUserId(userId);
    		video.setVideoSeconds((float)videoSeconds);
    		video.setVideoHeight(videoHeight);
    		video.setVideoWidth(videoWidth);
    		video.setVideoDesc(desc);
    		video.setVideoPath(uploadPathDB);
    		video.setCoverPath(coverPathDB);
    		video.setStatus(VideoStatusEnum.SUCCESS.value);
    		video.setCreateTime(new Date());
    		
    		String videoId = videoService.saveVideo(video);
    		
    		return IMoocJSONResult.ok(videoId);
    	}

    5.关注作品功能

    5.1 关注代码

    
            
          

    followMe()事件,e.currentTarget.dataset.followtype获取data-followType的值,根据类型判断是关注或取消关注,调用对应的接口

    followMe: function (e) {
        var me = this;
    
        var user = app.getGlobalUserInfo();
        var userId = user.id;
        var publisherId = me.data.publisherId;
    
        var followType = e.currentTarget.dataset.followtype;
    
        // 1:关注 0:取消关注
        var url = '';
        if (followType == '1') {
          url = '/user/beyourfans?userId=' + publisherId + '&fanId=' + userId;
        } else {
          url = '/user/dontbeyourfans?userId=' + publisherId + '&fanId=' + userId;
        }
    
        wx.showLoading();
        wx.request({
          url: app.serverUrl + url,
          method: 'POST',
          header: {
            'content-type': 'application/json', // 默认值
            'headerUserId': user.id,
            'headerUserToken': user.userToken
          },
          success: function () {
            wx.hideLoading();
            if (followType == '1') {
              me.setData({
                isFollow: true,
                fansCounts: ++me.data.fansCounts
              })
            } else {
              me.setData({
                isFollow: false,
                fansCounts: --me.data.fansCounts
              })
            }
          }
        })
      },

    5.2 关注接口

    @PostMapping("/beyourfans")
    	public IMoocJSONResult beyourfans(String userId, String fanId) throws Exception {
    		
    		if (StringUtils.isBlank(userId) || StringUtils.isBlank(fanId)) {
    			return IMoocJSONResult.errorMsg("");
    		}
    		
    		userService.saveUserFanRelation(userId, fanId);
    		
    		return IMoocJSONResult.ok("关注成功...");
    	}
    	
    	@PostMapping("/dontbeyourfans")
    	public IMoocJSONResult dontbeyourfans(String userId, String fanId) throws Exception {
    		
    		if (StringUtils.isBlank(userId) || StringUtils.isBlank(fanId)) {
    			return IMoocJSONResult.errorMsg("");
    		}
    		
    		userService.deleteUserFanRelation(userId, fanId);
    		
    		return IMoocJSONResult.ok("取消关注成功...");
    	}

    6.首页视频展示功能

    6.1 首页页面

        
    
    
         //封面图
          
            
          
    
    
        
            
                
                {{item.nickname}}
            
        
    
    
        

    6.2 获取视频列表接口

    /**
    	 * 
    	 * @Description: 分页和搜索查询视频列表
    	 * isSaveRecord:1 - 需要保存
    	 * 				 0 - 不需要保存 ,或者为空的时候
    	 */
    	@PostMapping(value="/showAll")
    	public IMoocJSONResult showAll(@RequestBody Videos video, Integer isSaveRecord,
    			Integer page, Integer pageSize) throws Exception {
    		
    		if (page == null) {
    			page = 1;
    		}
    		
    		if (pageSize == null) {
    			pageSize = PAGE_SIZE;
    		}
    		
    		PagedResult result = videoService.getAllVideos(video, isSaveRecord, page, pageSize);
    		return IMoocJSONResult.ok(result);
    	}

    6.3 交互

    页面加载的时候调用后台获取视频列表接口,onPullDownRefresh为下拉刷新触底监听事件,onReachBottom是页面上拉触底事件的函数

    onLoad: function (params) {
        var me = this;
        var screenWidth = wx.getSystemInfoSync().screenWidth;
        me.setData({
          screenWidth: screenWidth,
        });
    
        var searchContent = params.search;
        var isSaveRecord = params.isSaveRecord;
        if (isSaveRecord == null || isSaveRecord == '' || isSaveRecord == undefined) {
          isSaveRecord = 0;
        }
    
        me.setData({
          searchContent: searchContent
        });
    
        // 获取当前的分页数
        var page = me.data.page;
        me.getAllVideoList(page, isSaveRecord);
      },
    
      getAllVideoList: function (page, isSaveRecord) {
        var me = this;
        var serverUrl = app.serverUrl;
        wx.showLoading({
          title: '请等待,加载中...',
        });
    
        var searchContent = me.data.searchContent;
    
        wx.request({
          url: serverUrl + '/video/showAll?page=' + page + "&isSaveRecord=" + isSaveRecord,
          method: "POST",
          data: {
            videoDesc: searchContent
          },
          success: function (res) {
            wx.hideLoading();
            wx.hideNavigationBarLoading();
            wx.stopPullDownRefresh();
    
            console.log(res.data);
    
            // 判断当前页page是否是第一页,如果是第一页,那么设置videoList为空
            if (page === 1) {
              me.setData({
                videoList: []
              });
            }
    
            var videoList = res.data.data.rows;
            var newVideoList = me.data.videoList;
    
            me.setData({
              videoList: newVideoList.concat(videoList),
              page: page,
              totalPage: res.data.data.total,
              serverUrl: serverUrl
            });
    
          }
        })
      },
    
      onPullDownRefresh: function() {
          //在当前页面显示导航条加载动画
        wx.showNavigationBarLoading();
        this.getAllVideoList(1, 0);
      },
    
      //上拉刷新
      onReachBottom:function() {
        var me = this;
        var currentPage = me.data.page;
        var totalPage = me.data.totalPage;
    
        // 判断当前页数和总页数是否相等,如果想的则无需查询
        if (currentPage === totalPage) {
          wx.showToast({
            title: '已经没有视频啦~~',
            icon: "none"
          })
          return;
        }
    
        var page = currentPage + 1;
    
        me.getAllVideoList(page, 0);
      },
    
      showVideoInfo: function(e) {
        var me = this;
        var videoList = me.data.videoList;
        var arrindex = e.target.dataset.arrindex;
        var videoInfo = JSON.stringify(videoList[arrindex]);
    
        wx.redirectTo({
          url: '../videoinfo/videoinfo?videoInfo=' + videoInfo
        })
      }

    7.视频搜索功能

    7.1 搜索页面

    wxSearchView.wxml

    
       
        
          
          
          
            
          
        
      
        
             搜索
             主页
         
    
    
    
    
      
        
        
          
            
              {{item}}
            
          
        
    
        
          
            搜索记录
            
            
          
          
            
              {{item}}
            
          
        
    
        
          搜索热点
          
            
              {{item}}
            
          
        
      
    

    7.2 交互

    // 1 导入js文件
    var WxSearch = require('../../wxSearchView/wxSearchView.js');
    
    const app = getApp()
    
    Page({
      data: {
      },
    
      onLoad: function () {
    
        // 2 搜索栏初始化
        var that = this;
    
        // 查询热搜词
        var serverUrl = app.serverUrl;
        wx.request({
          url: serverUrl + '/video/hot',
          method: "POST",
          success: function(res) {
            console.log(res);
            var hotList = res.data.data;
    
            WxSearch.init(
              that,  // 本页面一个引用
              hotList,
              // ['热门视频', '推荐视频', "java", "小程序", 'zookeeper', 'springboot'], // 热点搜索推荐,[]表示不使用
              hotList,// 搜索匹配,[]表示不使用
              that.mySearchFunction, // 提供一个搜索回调函数
              that.myGobackFunction //提供一个返回回调函数
            );
    
    
    
          }
        })
    
      },
    
      // 3 转发函数,固定部分,直接拷贝即可
      wxSearchInput: WxSearch.wxSearchInput,  // 输入变化时的操作
      wxSearchKeyTap: WxSearch.wxSearchKeyTap,  // 点击提示或者关键字、历史记录时的操作
      wxSearchDeleteAll: WxSearch.wxSearchDeleteAll, // 删除所有的历史记录
      wxSearchConfirm: WxSearch.wxSearchConfirm,  // 搜索函数
      wxSearchClear: WxSearch.wxSearchClear,  // 清空函数
    
      // 4 搜索回调函数  
      mySearchFunction: function (value) {
        // do your job here
        // 示例:跳转
        wx.redirectTo({
          url: '../index/index?isSaveRecord=1&search=' + value
        })
      },
    
      // 5 返回回调函数
      myGobackFunction: function () {
        // do your job here
        // 示例:返回
        wx.redirectTo({
          url: '../index/index'
        })
      }
    
    
    })

    8.收藏功能

    1.页面代码

    videoinfo.wxml

     
                
                    
                
                
                    
                

    2.交互

    触发likeVideoOrNot事件,通过me.data.userLikeVideo来判断是收藏还是取消收藏

    likeVideoOrNot: function () {
        var me = this;
        var videoInfo = me.data.videoInfo;
        var user = app.getGlobalUserInfo();
    
        if (user == null || user == undefined || user == '') {
          wx.navigateTo({
            url: '../userLogin/login',
          })
        } else {
          
          var userLikeVideo = me.data.userLikeVideo;
          var url = '/video/userLike?userId=' + user.id + '&videoId=' + videoInfo.id + '&videoCreaterId=' + videoInfo.userId;
          if (userLikeVideo) {
            url = '/video/userUnLike?userId=' + user.id + '&videoId=' + videoInfo.id + '&videoCreaterId=' + videoInfo.userId;
          }
    
          var serverUrl = app.serverUrl;
          wx.showLoading({
            title: '...',
          })
          wx.request({
            url: serverUrl + url,
            method: 'POST',
            header: {
              'content-type': 'application/json', // 默认值
              'headerUserId': user.id,
              'headerUserToken': user.userToken
            },
            success:function(res) {
              wx.hideLoading();
              me.setData({
                userLikeVideo: !userLikeVideo
              });
            }
          })
    
    
        }
      },

    3.收藏和取消收藏接口

    @PostMapping(value="/userLike")
    	public IMoocJSONResult userLike(String userId, String videoId, String videoCreaterId) 
    			throws Exception {
    		videoService.userLikeVideo(userId, videoId, videoCreaterId);
    		return IMoocJSONResult.ok();
    	}
    	
    	@PostMapping(value="/userUnLike")
    	public IMoocJSONResult userUnLike(String userId, String videoId, String videoCreaterId) throws Exception {
    		videoService.userUnLikeVideo(userId, videoId, videoCreaterId);
    		return IMoocJSONResult.ok();
    	}

    8.评论功能

    1.页面代码

    videoinfo.wxml

     
     
     
         
         
    
    
    
    
    
    
      
          
              
              
                  
                  
                  
                    回复
                    
                  
                  
                    留言:
                  
              
          
          {{item.comment}}
      
     
    
     
    

    2.交互

    点击评论按钮,触发leaveComment事件,将commentFocus值设置为true

    leaveComment: function() {
        this.setData({
          commentFocus: true
        });
      },
    
      replyFocus: function(e) {
        var fatherCommentId = e.currentTarget.dataset.fathercommentid;
        var toUserId = e.currentTarget.dataset.touserid;
        var toNickname = e.currentTarget.dataset.tonickname;
     
        this.setData({
          placeholder: "回复  " + toNickname,
          replyFatherCommentId: fatherCommentId,
          replyToUserId: toUserId,
          commentFocus: true
        });
      },
    
      saveComment:function(e) {
        var me = this;
        var content = e.detail.value;
    
        // 获取评论回复的fatherCommentId和toUserId
        var fatherCommentId = e.currentTarget.dataset.replyfathercommentid;
        var toUserId = e.currentTarget.dataset.replytouserid;
    
        var user = app.getGlobalUserInfo();
        var videoInfo = JSON.stringify(me.data.videoInfo);
        var realUrl = '../videoinfo/videoinfo#videoInfo@' + videoInfo;
    
        if (user == null || user == undefined || user == '') {
          wx.navigateTo({
            url: '../userLogin/login?redirectUrl=' + realUrl,
          })
        } else {
          wx.showLoading({
            title: '请稍后...',
          })
          wx.request({
            url: app.serverUrl + '/video/saveComment?fatherCommentId=' + fatherCommentId + "&toUserId=" + toUserId,
            method: 'POST',
            header: {
              'content-type': 'application/json', // 默认值
              'headerUserId': user.id,
              'headerUserToken': user.userToken
            },
            data: {
              fromUserId: user.id,
              videoId: me.data.videoInfo.id,
              comment: content
            },
            success: function(res) {
              console.log(res.data)
              wx.hideLoading();
    
              me.setData({
                contentValue: "",
                commentsList: []
              });
    
              me.getCommentsList(1);
            }
          })
        }
      },
    
    // commentsPage: 1,
    //   commentsTotalPage: 1,
    //   commentsList: []
    
        getCommentsList: function(page) {
          var me = this;
    
          var videoId = me.data.videoInfo.id;
    
          wx.request({
            url: app.serverUrl + '/video/getVideoComments?videoId=' + videoId + "&page=" + page + "&pageSize=5",
            method: "POST",
            success: function(res) {
              console.log(res.data);
    
              var commentsList = res.data.data.rows;
              var newCommentsList = me.data.commentsList;
    
              me.setData({
                commentsList: newCommentsList.concat(commentsList),
                commentsPage: page,
                commentsTotalPage: res.data.data.total
              });
            }
          })
        },
    

     

  • 相关阅读:
    菜鸟教程《Python 3 教程》笔记(15):数据结构
    大量短信群发?不妨来看看这几个平台
    记一次RestTemplate消息类型不匹配的BUG定位
    382. 链表随机节点
    Ansible数组同步至Shell脚本数组中
    【评论送书】十本架构师成长和软件架构技术相关的好书(可以任选)
    QSystemTrayIcon——实现系统托盘
    【广州华锐互动】AR远程连接专家进行协同管理,解放双手让协同更便捷
    【操作系统学习笔记】文件管理3.5
    SegNeXt Rethinking Convolutional Attention Design for Semantic Segmentation
  • 原文地址:https://blog.csdn.net/xiao297328/article/details/126162530