Java:86-分布式前端开发

前端门户系统

经过上一章的后端开发后,接下来我们来操作前端开发,页面不需要我们自己开发,使用提供的页面即可
对应的前端初始项目地址:
链接:https://pan.baidu.com/s/1iFui2WbE1mfmHWnb9Z8oGg
提取码:alsk
运行项目 npm run serve
接下来进行开发
但要注意:这里只会给出部分代码,需要自己去进行对比修改(记得启动对应的后端,且没有的自然自己写)
由于是部分,对应的代码可能不是全的
可以使用ctrl+f进行查找,或者ctrl+d进行找到一样的(虽然从上到下,循环的,直到找到自己)
进入首页组件Index.vue
<!--虽然组件里的样式基本只能操作组件(一般是设置的),但其本身却可以被使用-->
对应的js部分:
 created() {
    this.getCourseList() //组件使用时,就调用获取课程信息的方法
  },
  getCourseList(){ //去dubbo服务获取全部课程的数据
    return this.axios.get("http://localhost:8002/course/getAllCourse").then(res => {
      console.log(res)
    }).catch(err =>{
      this.$message.error("获取课程信息失败")
    })
    }
进行访问后,查询浏览器的检查,是否有对应数据,一般对应的data根据对应编码值来显示先后
实际上是因为对应的json操作返回的(后台的操作)
测试后,若有数据,那么接下来则编写具体代码,代码部分:
 data() {
    return {
      activeName: "allLesson",
      courseList:[] //课程集合
    };
  },
 getCourseList(){ //去dubbo服务获取全部课程的数据
    return this.axios.get("http://localhost:8002/course/getAllCourse").then(res => {
      console.log(res)
      this.courseList = res.data; //添加该代码
    }).catch(err =>{
      this.$message.error("获取课程信息失败")
    })
    }
<!-- 课程信息展示开始 -->
            <li class="course-li" v-for="(item,index) in courseList" :key="index"> 
                <!--循环课程集合-->
                <!--
:key一般使得v-for更加稳定
实际上:key的具体作用主要体现在如下:
赋值,在理解这两个字前,首先看如下
假设我们有三个数据
1=>好 点
2=>可 点
3=>看 点
当我们点击他们后面的"点"时,会使得他们进行删除(这个删除一般只会根据对应父节点来删除,比如上面的1,2,3)
那么有可能会出现如下:
假如父节点删除一般会使得子节点也删除,但只要对应节点存在,那么子节点数据任然对应,什么意思呢:
假如有1,2,3,我们删除2,那么变成了1,3,3到了2这个位置
但在vue里面,是说2变成了3,如2=3这样的赋值
那么节点存在,那么子节点数据任然对应(只是改变了2的数据而已,但存在)
所以根据上面的说明,假设我们点击第二个"点",那么数据就是:
1=>好 点
3=>可 点
发现"可"还在,但"看"没有了,为了不让他进行对应的赋值,则需要规定每个元素的位置
则使用:key,所以说,对应的:key的值最好是唯一的,否则可能会报错(一般的显示错误)
这样加上后,使得我们点击第二个"点"时,出现了:
1=>好 点
3=>看 点
这样就正常一点了
所以说:key是为了更加的稳定,实际上也最好不要绑定index,因为他的顺序可能也会使得出现前面的情况

上面只是一个假设的例子,实际上是可能会出现该情况的,而:key就是防止这种情况,或者说是防止vue的那个赋值
-->
                <!--记得找到对应代码进行修改-->
		 <img
                :src="item.courseImgUrl"
                class="teacher-portrait hover-pointer"
              />
<!--绑定对应的图片信息(item.courseImgUrl)-->
<!--:src代表v-bind:src,因为v-bind:可以简写成:-->
		<div
                    class="p-title"
                    style="text-align:left;"
                    @click="gotoDetail"
                  >
                    <span>
                      {{item.courseName}}
                        <!--对应的课程名-->
                    </span>
                  </div>
 <!-- 作者和职称 -->
                  <p class="p-title-buy text-overflow">
                    <span class="p-author-span">
                      {{item.teacher.teacherName}}
                    </span>
                    <span class="p-author-line" />
                    <span class="p-author-span">
                       {{item.teacher.position}}
                    </span>
                  </p>
 <!-- 课程简单描述 -->
                  <p class="p-describe" style="text-align:left;">
                    {{item.brief}}
                  </p>
 <span class="content-price-orange-sm"></span>
                    <span class="content-price-orange">{{item.discounts}}</span> 
<!--优惠价-->
                    <span class="current-price">
                      <span class="current-price-unite"></span>
                      {{item.price}} <!--原价-->
                    </span>
<span class="content-price-buy">{{item.sales}}人购买</span>
<!--item.sales销量-->
删掉对应的章节2的li标签,因为我们直接遍历即可
 <ul class="content-course" style="text-align:left;">
                  <!-- 章节1 一般只取得对应的章节的前两个课时信息-->
                   <li
                    class="content-course-lesson text-overflow"
                    style="width:300px" 
       v-for="(lesson,index) in item.courseSectionList[0].courseLessonList.slice(0,2)" :key="index"
                  >
                       <!--slice(0,2)截取数组中前两个,即这里是0,1,但不包括2-->
                      <!--循环课程里面的章节-->
                    <!-- 免费试看图标 -->
                    <img
                      src="@/assets/course-list/free-course.png"
                      class="free-label hover-pointer"
                    />
                    <span class="theme-span hover-pointer">
                        {{lesson.theme}} <!--对应的章节名里面的课时名称(主题)-->
                      </span>
                  </li>
                  
                 
                </ul>
现在对应的显示已经完成,现在我们操作登录
找到Header.vue:
//methods里面的  
login(){ //前去登录
      return this.axios.get("http://localhost:8002/user/login",{
        params:{
          phone:this.phone,
          password:this.password
        }
      }).then(res =>{
        
        console.log(res);
        this.userDTO = res.data;
          if(this.userDTO.content!=null){
        this.isLogin = true //更新登录状态,一般写在上面的设置后面,虽然写在前面也可(因为执行速度够快)
        //将登录成功的信息进行保存(本地),使得刷新界面时,可以继续得到信息,基本只与浏览器有关
        localStorage.setItem("user",JSON.stringify(this.userDTO)) //将字符串数据变过去
          }
          //初始化
        this.phone = "";
        this.password="";
      
        this.dialogFormVisible = false; // 不显示登录框
           this.$router.push("/" ); //防止其他界面路径操作时,出现问题,直接跳转到根目录,且刷新
        
          window.location.reload() //进行刷新,使得操作后面的已购,因为在当前相同的路径下
          //并不会有刷新,那么已购也就不会动态的出现了
      }).catch(err =>{
        this.$message.error("登录失败")
      })
    }
created(){
    
    //当刷新页面,组件创建成功之后,立刻检测本地储存中是否存在用户对象
    console.log(JSON.parse(localStorage.getItem("user")));
    //将得到的字符串变成对应的对象,也可以说是JSON对象,使得可以操作,即"对象.key"的获取值
     this.userDTO =JSON.parse(localStorage.getItem("user")); 
     console.log(this.userDTO)
     if( this.userDTO != null){
         this.isLogin = true //更新登录状态,表示已登录
     }
  },
操作完成后,就可以进行登录了,刷新也是一样
登出操作:
  logout(){ //登出
localStorage.setItem("user",null)
 this.isLogin = false
       this.$router.push("/" ); //防止其他界面路径操作时,出现问题,直接跳转到根目录,且刷新
      window.location.reload() //进行刷新,使得操作后面的已购,最好加上(),不加可能不会起作用
 alert("已登出")
    }
回到Index.vue:
 data() {
    return {
      activeName: "allLesson",
      courseList:[], //课程集合
        myCourseList:[], //我购买过的课程列表
      isLogin:false, //登录状态
      user:null //登录的用户对象信息
    };
  },
created() {

this.user = JSON.parse(localStorage.getItem("user"));   
//不为null代表登录了,因为登录了才会设置对应的值,没有登录会设置为null
//而JSON.parse操作null,返回的也是null
if(this.user != null){ 
  this.isLogin = true
     this.getMyCourseList(); //获得自己的课程,也就是购买过的课程
}

    this.getCourseList() //组件使用时,就调用获取课程信息的方法

  

  },
  getMyCourseList(){
      return this.axios.get("http://localhost:8002/course/getCourseByUserId/" + this.user.content.id).then(res =>{
 console.log(res)
      this.myCourseList = res.data;
      }).catch(err => {
 this.$message.error("获取课程信息失败")
      })
    }
<el-tab-pane label="已购" name="hasPay">
          <div v-if="!isLogin">
          <img
            src="@/assets/course-list/no-login@2x.png"
            class="no-data-icon"
          />
          <div class="no-data-title">您还没有登录</div>
          <div class="no-data-title">登录后即可查看已购课程</div>
          <div class="btn btn-yellow btn-center">立即登录</div>
          </div>
          <div v-if="isLogin">
            <ul class="course-ul-pc">
            <!-- 课程信息展示开始 这里循环的对象改成myCourseList-->
            <li class="course-li" v-for="(item,index) in myCourseList" :key="index">
              <!-- 课程封面图 -->
              <img
                :src="item.courseImgUrl"
                class="teacher-portrait hover-pointer"
              />
              <!-- 课程文字信息 -->
              <div class="content-main">
                <!-- 课程标题 -->
                <div class="content-title hover-pointer">
                  <div
                    class="p-title"
                    style="text-align:left;"
                    @click="gotoDetail"
                  >
                    <span>
                      {{item.courseName}}
                    </span>
                  </div>
                  <!-- 作者和职称 -->
                  <p class="p-title-buy text-overflow">
                    <span class="p-author-span">
                      {{item.teacher.teacherName}}
                    </span>
                    <span class="p-author-line" />
                    <span class="p-author-span">
                       {{item.teacher.position}}
                    </span>
                  </p>
                  <p></p>
                  <!-- 课程简单描述 -->
                  <p class="p-describe" style="text-align:left;">
                    {{item.brief}}
                  </p>
                </div>
                <!-- 课程前两个章节信息 -->
                <ul class="content-course" style="text-align:left;">
                  <!-- 章节1 -->
                  <li
                    class="content-course-lesson text-overflow"
                    style="width:300px" 
    v-for="(lesson,index) in item.courseSectionList[0].courseLessonList.slice(0,2)" :key="index"
                  >
                    <!-- 免费试看图标 -->
                    <img
                       src="@/assets/course-list/yanzhi_activity_modal_gift@2x.png"
                      class="free-label hover-pointer"
                    />
                    <span class="theme-span hover-pointer">
                      {{lesson.theme}}
                      </span>
                  </li>
                  
                 
                </ul>
                <!-- 价格信息 -->
                <div class="content-price" style="text-align:left;">
                  <p class="content-price-p">
                    <span class="content-price-orange-sm"></span>
                    <span class="content-price-orange">{{item.discounts}}</span>
                    <span class="current-price">
                      <span class="current-price-unite"></span>
                      {{item.price}}
                    </span>
                    <span class="activity-name">成就自己</span>
                    <span class="content-price-buy">{{item.sales}}人购买</span>
                  </p>
                  <div class="btn btn-yellow btn-offset">开始学习</div> 
                <!--样式修改成btn-yellow,且对应的名称修改成"开始学习",进行区别,表示已经购买的课程-->
                </div>
              </div>
            </li>
            <!-- 课程信息结束 -->
            
          </ul>
          </div>
        </el-tab-pane>
课程的显示已经完成,接下来我们来显示课程里面的信息
  <div
                    class="p-title"
                    style="text-align:left;"
                    @click="gotoDetail(item)"
                  >
                        <!--gotoDetail(item),传递当前课程信息(item就是)-->
gotoDetail(item) {
      this.$router.push({ name: "Course", params: { course: item } });
    },
到Course.vue组件:
 data() {
    return {
      activeName: "intro",
      course:null,
      totalLessons:0, //本门课程的总节数
    };
  },
//没有自然自己写
 created(){
    
this.course = this.$route.params.course //从路由中获得参数对象,赋值给本组件的参数
console.log(1)
console.log(this.course)
let x = 0;
for(let i = 0;i<this.course.courseSectionList.length;i++){
  let section = this.course.courseSectionList[i] //每一章
  for(let j = 0;j<section.courseLessonList.length;j++){
    x++;
  }
}
this.totalLessons = x; //得到对应所有的讲(也就是所有的课时)
  },
  <!-- 面包屑导航 -->
      <div class="nav-wrap">
        <p class="nav-p-pc" style="margin-top:-25px;text-align:left;">
          <a href="#">课程列表</a>
          <span class="sharp-content">&gt;</span>
          <span class="nav-sec">{{course.courseName}}</span>
        </p>
      </div>
<img
                      class="course-img"
                      :src="course.courseImgUrl"
                      alt="课程图片"
                    />
<div class="conent-wrap">
                      <div class="name" style="text-align:left;">
                        {{course.courseName}}
                      </div>
                      <div class="des text-omit" style="text-align:left;">
                        {{course.brief}}
                      </div>
                      <div class="title">
                        <div class="teacher-name text-omit">
                          讲师:{{course.teacher.teacherName}}
                          <span class="line"></span>
                          {{course.teacher.position}}
                        </div>
                      </div>
                      <div class="lesson-info">
                        <div class="boook-icon backgroun-img-set"></div>
                        <div class="time">{{totalLessons}}讲 / {{course.totalDuration}}课时</div>
                        <!--这里的该课时是时长(分钟单位)-->
                        <div class="person-icon backgroun-img-set"></div>
                        <div class="person">{{course.sales}}人已购买</div>
                      </div>
                    </div>
 <el-tab-pane label="课程信息" name="intro">
                   <div v-html="course.courseDescription" class="content-p pc-background">
                      <!--v-html:讲对应的结果当成html操作,会识别标签-->
                    </div>
                  </el-tab-pane>
.content-p {
  font-size: 0.373rem;
  color: #666;
  letter-spacing: 0;
  text-align: justify;
  line-height: 1.1rem;
}
 <div
      class="class-menu-contaniner list-page-container more-sections more-sections-padding"
                    v-for="(section,index) in course.courseSectionList" :key="index"
                 
                    >
.class-menu-contaniner.list-page-container {
  padding: 0px 15px;
  background: #fff;
}
   <div>
                        <div class="section-name single-line">
                         {{section.sectionName}}
                        </div>
                        <div class="class-menu-block">
                          <div
                            class="class-level-one over-ellipsis"
                            @click="watchCourse(1)"
                             v-for="(lesson,index) in section.courseLessonList" :key="index"
                          >
                            <div class="text-wrap">
                              <div class="content">{{lesson.theme}}</div>
                              <div
                                class="item-status-wrap item-status-wrap-list"
                              >
                                <div class="item-status test-watch">试看</div>
                              </div>
                            </div>
                          </div>
                       
                        </div>
                      </div>
 <span class="current-price" style="font-size:28px">
            <span class="current-price-unite" style="font-size:.347rem"></span
            >{{course.discounts}}
          </span>
          <span class="current-price price">
            <span class="current-price-unite"></span>
            {{course.price}}
          </span>
接下来我们操作留言(任然是Course.vue):
 created(){
    
this.course = this.$route.params.course //从路由中获得参数对象,赋值给本组件的参数
console.log(1)
console.log(this.course)
let x = 0;
for(let i = 0;i<this.course.courseSectionList.length;i++){
  let section = this.course.courseSectionList[i] //每一章
  for(let j = 0;j<section.courseLessonList.length;j++){
    x++;
  }
}
this.totalLessons = x; //得到对应所有的讲(也就是所有的课时)
this.getComment(); //这里是新加的
  },
 data() {
    return {
      activeName: "intro",
      course:null,
      totalLessons:0, //本门课程的总节数
      commentList:null //所有留言
    };
  },
  getComment(){
 return this.axios
     .get("http://localhost:8002/course/comment/getCourseCommentList/"+this.course.id+"/1/20")
     .then(res => {
      console.log(res)
      this.commentList = res.data;
    }).catch(err =>{
      this.$message.error("获取留言信息失败")
    })
    },
 <!-- 留言 开始 -->
    <div class="message-list" v-for="(comment , index) in commentList" :key="index">
                        <div class="message-list-title">
                          <div class="message-list-title-left">
                            <div class="message-list-title-left-name">{{comment.userName}}</div>
                            <div class="message-list-title-left-tag"></div>
                          </div>
                         <div @click="cancelzan(comment)"
                              v-if="JSON.stringify(comment.favoriteRecords)
                                    .indexOf( user.content.id ) >= 0" 
                              class="message-list-title-right">
                            <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAJFBMVEVHcEwAuI4AtIsAtIsAtIoAtYwAtIsAtYwAtowAx5kAtIsAs4qd4c1kAAAAC3RSTlMAGMfz3VGnbTYIhXtDq8EAAAETSURBVDjLldWhb8JAFAbwg8CGhGSGzNQtULNkWUioWbJkpmYKAQaBITPLLKZysmLz+xfolUL6/XM72msh9N2X8ImaX17vrq+vVeqU39XTuK/kdEMA01jGDY4ZyYWFIRPxp0S8u+8KeBJ+WDxIGFrMJbQm7qhVYSJgr8JUwNsKtYDtCiHgPavcsDVDstsuyDk7NeYDk6G8pM3bWXNawQUijWq8QyPPpQy+50ET9bF09go5pus3cMV0feFEc2DfieZRBU7Up7fjSkwZZgz3DA8MHxl6DP8YRgxjgokimDHcMdwyfGG4ZPjJMCKoY4KJIpgz3DHcMvQYFuPpk/005t1mffHlOs/ETvxXAA0Ul3oQHsp/xD93wxfHcC4VkwAAAABJRU5ErkJggg==" alt="">
                            <div class="message-list-title-right-praise">{{comment.likeCount}}</div>
                          </div>
                          <!-- 没点过赞 -->
                          <div @click="zan(comment)" v-else class="message-list-title-right">
                            <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAKlBMVEVHcExnZ2dzc3NmZmZqampmZmZmZmZnZ2dnZ2dnZ2dmZmZoaGhmZmZmZmZl+8SAAAAADXRSTlMA/AbsFtilbj5YwSqJPyESoQAAAZxJREFUOMt1lTtLA1EQha8xRhPTBEmhuKCCoNgoIlYLMcRKBG0sxIUgCDaBSDohEO0FEbQyIBZaBazERvAPWCwxPnP+i3tnrlGTmVPswn73NXNm7hrzq9m9kZ2ckTUUABifkOEBrK7liR7BMRFOA/uFc+BUgnV8mFisEW5IsIFi9FzBuwR91KJnAm8S9EIbxSBeBRZHk86MrBQJWjymJUC3nlugSyk+SQyhANfxos+s4krfM0DZvmbw2cuSCHNGi3PAfUygXYiU79ryyw1ibf0xZ9intBsz6SBadx24iiZXz8kPxCiTtYdLPzKTVFkkLQAZO/VikwYW/x/wHohcT/MiPQE8W9frxJrlbpiw4xvA0vbNmWyhj2Nrhmy+B7nEyTsN0rIaJAc0SDWqwX7rhAYfMa/Dui0bDZbwZAwUGNjWUWActnUUyN2hwDTaOkxRaSiwj6pRhjHKgTazSkWlwBK1jgIpBwrkHCgwyZ0oQ86BAjkHCjziG0KE8YBvCA/5KacOm6sgrHFAotouT6J23bkkLbsNDjM9yt7yP+IbQYga5De+eBMAAAAASUVORK5CYII=" alt="">
                            <div class="message-list-title-right-praise">{{comment.likeCount}}</div>
                          </div>
                        </div>
                        <div class="message-list-content">
                          {{comment.comment}}
                        </div>
                      
                      
                      </div>
                      <!-- 留言 结束 -->
在这之前,我们需要讲样式进行改变,删除原来的样式,复制如下地址的样式进行使用
链接:https://pan.baidu.com/s/16u-vPVF_tmokXNOKzZUjxQ
提取码:alsk
接下来我们了操作试看的状态:
任然是Course.vue:
  data() {
    return {
      activeName: "intro",
      course:null,
      totalLessons:0, //本门课程的总节数
      commentList:null, //所有留言
      isLogin:false, //false,未登录
      isBuy:false,//未购买
      user:null, //当前用户,可以","结尾
      myCourseList:[], //当前用户购买过的所有课程
    };
  },
created(){
    
this.course = this.$route.params.course //从路由中获得参数对象,赋值给本组件的参数
  if(this.course==null){ //防止自己刷新或者其他页面跳转出现错误,因为这时候的this.course是undefined
  //undefined==null返回的是true,因为他们操作==时,一般会变成false
      //因为只会比较这时候在判断的值(可以说看成了false)
//若要进行完全比较,则需要===,那么返回false
  this.$router.push("/"); //回到首页
}
//检测是否登录
this.user = JSON.parse(localStorage.getItem("user"))
if(this.user != null){
  this.isLogin = true //已登陆
  if(this.course!=null){  //防止出现没有值(这里是undefined),导致axios中then错误,那么catch也会错误
  this.getMyCourseList() //查询登录用户购买的所有课程
}
}

console.log(1)
console.log(this.course)
let x = 0;
for(let i = 0;i<this.course.courseSectionList.length;i++){
  let section = this.course.courseSectionList[i] //每一章
  for(let j = 0;j<section.courseLessonList.length;j++){
    x++;
  }
}
this.totalLessons = x; //得到对应所有的讲(也就是所有的课时)
this.getComment();
  },
getMyCourseList(){  ////查询登录用户购买的所有课程
  return this.axios.get("http://localhost:8002/course/getCourseByUserId/" + 
                        this.user.content.id).then(res =>{
 console.log(res)
      this.myCourseList = res.data;

    //检测当前的课程是否购买过
    for(let i = 0;i<this.myCourseList.length;i++){
      if(this.myCourseList[i].id == this.course.id){
        this.isBuy = true //这样就代表购买过该课程,自然其中的课程(如章节的课时的视频)都可以进行播放
        break;
      }
    }

      }).catch(err => {
 this.$message.error("获取课程信息失败")
      })
    },
   <div
                                class="item-status-wrap item-status-wrap-list"
                              >
                              <!--第一章前两节-->
                              <div v-if="index<2">
                                <!--没有登录,就是试看-->
                                <div class="item-status test-watch" v-if="!isLogin">试看</div>
                                <!--登录了,但没有购买,也是试看-->
                         <div class="item-status test-watch" v-else-if="isLogin && !isBuy">试看</div>
                                <!--登录了,且购买了,那就是播放-->
                                <div class="item-status test-watch"  v-else>播放</div>
                              </div>
                              
                                <!--第一章除了前两节的-->
                                <div v-if="index>1"> <!--优先于data里面的(因为上面有)-->
                                <!--没有登录,就是锁,lock样式就是锁的图片-->
                                <div class="item-status lock" v-if="!isLogin"></div>
                                <!--登录了,但没有购买,也是锁-->
                                <div class="item-status lock" v-else-if="isLogin && !isBuy"></div>
                                <!--登录了,且购买了,那就是播放-->
                                <div class="item-status test-watch"  v-else>播放</div>
                              </div>
                              </div>
修改对应的html(注意找到具体位置):
   <div
         class="class-menu-contaniner list-page-container more-sections more-sections-padding"
                   
                 
                    >
                    <!--第一章开始-->
          <div  v-for="(section,index) in course.courseSectionList.slice(0,1)" :key="index">
                        <div class="section-name single-line">
                         {{section.sectionName}}
                        </div>
                        <div class="class-menu-block">
                          <div
                            class="class-level-one over-ellipsis"
                            @click="watchCourse(1,index,lesson.courseMedia,lesson.id)"
                             v-for="(lesson,index) in section.courseLessonList" :key="index"
                          >
                            <div class="text-wrap">
                              <div class="content">{{lesson.theme}}</div>
                              <div
                                class="item-status-wrap item-status-wrap-list"
                              >
                              <!--第一章前两节-->
                              <div v-if="index<2">
                                <!--没有登录,就是试看-->
                                <div class="item-status test-watch" v-if="!isLogin">试看</div>
                                <!--登录了,但没有购买,也是试看-->
                       <div class="item-status test-watch" v-else-if="isLogin && !isBuy">试看</div>
                                <!--登录了,且购买了,那就是播放-->
                                <div class="item-status test-watch"  v-else>播放</div>
                              </div>
                              
                                <!--除了前两节的-->
                                <div v-if="index>1"> <!--优先于data里面的(因为上面有)-->
                                <!--没有登录,就是锁-->
                                <div class="item-status lock" v-if="!isLogin"></div>
                                <!--登录了,但没有购买,也是锁-->
                                <div class="item-status lock" v-else-if="isLogin && !isBuy"></div>
                                <!--登录了,且购买了,那就是播放-->
                                <div class="item-status test-watch"  v-else>播放</div>
                              </div>
                              </div>
                            </div>
                          </div>
                       
                        </div>
                      </div>
                       <!--第一章结束-->

                        <!--其他章开始,之所以需要其他章,是因为由于index是优先最近的,即使用课时的index
若没有其他章,那么基本上,只要是章节的前两节都会操作试看,实际上我们只需要第一章操作试看
-->
<div  v-for="(section,index) in course.courseSectionList.slice(1,course.courseSectionList.length)" 
     :key="index">
                        <div class="section-name single-line">
                         {{section.sectionName}}
                        </div>
                        <div class="class-menu-block">
                          <div
                            class="class-level-one over-ellipsis"
                            @click="watchCourse(2,index,lesson.courseMedia,lesson.id)"
                             v-for="(lesson,index) in section.courseLessonList" :key="index"
                          >
                            <div class="text-wrap">
                              <div class="content">{{lesson.theme}}</div>
                              <div
                                class="item-status-wrap item-status-wrap-list"
                              >
                              <!--其他章-->                   
                                <!--没有登录,就是锁-->
                                <div class="item-status lock" v-if="!isLogin"></div>
                                <!--登录了,但没有购买,也是锁-->
                                <div class="item-status lock" v-else-if="isLogin && !isBuy"></div>
                                <!--登录了,且购买了,那就是播放-->
                                <div class="item-status test-watch"  v-else>播放</div>
                           
                              </div>
                            </div>
                          </div>
                       
                        </div>
                      </div>
                      <!--其他章结束-->
                      
                      </div>
操作播放(任然是Course.vue):
//前面的
//watchCourse(1,index,lesson.courseMedia,lesson.id)
//watchCourse(2,index,lesson.courseMedia,lesson.id)
//已经写好了

   //播放视频
    //参数1:代表是否是第一章(1表示是第一章,2表示其他章)
    //参数2:对应的下标,也就是index的值,比如可以知道是否是前两节(对第一章来说)
    //参数3:代表视频地址
    watchCourse(status,index,courseMedia,lessonid) { 
//判断对应的视频是否有值
if(courseMedia == null){
  this.$message.error("播放失败,暂无视频")
}else{
 
    //试看的可以跳转播放页面,这里判断第一章的前两节,其余的没有试看
    //之所以可以这样一起判断,是因为这里是总数据status,index,courseMedia
    //直接操作课时的数据,而不是章节
    if(status == 1 && index<2){
this.$message.success("观看第【" + lessonid + "】节课程视频!" + courseMedia.fileEdk);
//lessonid代表课时对应的编号,一般也当成第几节,虽然可能在数据库里并不是从最小开始
//所以若为了好的正确观看,就可以不用lessonid而用index+1了,但是不好查看是哪个视频
  this.$router.push({
        name: "videoDetail",
        params: { course: this.course,lessonid: lessonid },
      });
        //params: { course: this.course,lessonid: lessonid ,a: courseMedia.fileEdk},
    }else{
    //锁上的先验证是否登录
    if(!this.isLogin){
      this.$message.success("请先登录")
    }else{
      //登录的,再验证是否购买过
      if(!this.isBuy){
this.$message.warning("请先购买后,进行解锁")
      }else{
        this.$message.success("观看第【" + lessonid + "】节课程视频!"+ courseMedia.fileEdk);
         this.$router.push({
        name: "videoDetail",
          params: { course: this.course,lessonid: lessonid },
      });
          //params: { course: this.course,lessonid: lessonid ,a: courseMedia.fileEdk},
      }

    }}
}

  
    },
接下来我们操作播放执行:
到videoDetail.vue
 data() {
    return {
      myvideo: null, // 播放器对象
      isplay: false, //是否在播放
      nowTime: "00:00", //当前播放时间
      totalTime: "00:00", //总时长
      course:null, //课程
      lessonid:0, //当前播放视频的课时id
        lessonName:null,//当前播放的视频名称
      //a:null
    };
  },
 created() {
    //从路由中得到对应的课程和课时id
    this.course = this.$route.params.course;
    this.lessonid = this.$route.params.lessonid
    //this.a=this.$route.params.a
  },
mounted() {
    this.myvideo = document.getElementById("myvideo");
    this.initplay() //初始化播放的视频,即当我到达这个页面,要播放的是对应的那个视频,基本不会是其他的视频
  },
 //初始化时播放的视频
    initplay(){
        //在课程信息中查找即将播放的小节视频的编号
      for(let i = 0 ;i<this.course.courseSectionList.length;i++){
        let section = this.course.courseSectionList[i]
        for(let j = 0;j<section.courseLessonList.length;j++){
          let lesson = section.courseLessonList[j]
          if(lesson.courseMedia!=null){
              if(this.lessonid==lesson.courseMedia.lessonId){
                  this.lessonName = lesson.theme
            console.log("视频地址:" + lesson.courseMedia.fileEdk)
            //将小节视频的地址赋值给播放器进行播放
            this.myvideo.src = lesson.courseMedia.fileEdk
            return;
            }
          }
        }
      }
       
      //上面的确可以进行操作,但实际上我们并不需要这么麻烦
      //因为在跳转到这个路由之前,我们就已经有对应的地址参数了,即并不需要进行循环判断使得相同id得到地址参数
        //因为之前就是同一个lesson
      //this.myvideo.src = this.a
        //但可能点击其他视频时,需要循环,所以为了后面的会出现的问题出发,加上循环并没有坏处
        //当然好像并没有什么作用
        
    },
至此我们进行点击试看或者播放,点击视频中间进行播放,发现视频的确进行播放,那么操作成功
在这之前,也可以点击地址看看是否可以播放
接下来操作播放的页面:
<span style="position:absolute;left:80px;">
            {{course.courseName}} > {{lessonName}}</span
          >
 <span class="progress-label">--</span>
 data() {
    return {
      myvideo: null, // 播放器对象
      isplay: false, //是否在播放
      nowTime: "00:00", //当前播放时间
      totalTime: "00:00", //总时长
      course:null, //课程
      lessonid:0, //当前播放视频的课时id
      lessonName:null,//当前播放的视频名称
       isLogin:false, //false,未登录
      isBuy:false,//未购买
      //a:null
    };
  },
我们从Course.vue里修改对应的如下代码:
//有两个
this.$router.push({
        name: "videoDetail",
        params: { course: this.course,lessonid: lessonid,isBuy:this.isBuy},
      });
回到videoDetail.vue:
created() {

//检测是否登录
this.user = JSON.parse(localStorage.getItem("user"))
if(this.user != null){
  this.isLogin = true //已登陆
  console.log(1)
}

    //从路由中得到对应的课程和课时id
    this.course = this.$route.params.course;
    this.lessonid = this.$route.params.lessonid
    this.isBuy = this.$route.params.isBuy
  },
   <div class="content-container">
              <!--第一章开始-->
              <div v-for="(section,index) in course.courseSectionList.slice(0,1)" :key="index">
                
                <div class="content-label">
                  <div class="content-label-title single-line">{{section.sectionName}}</div>
                  <img
                    class="arrow-icon"
                    src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII="
                    alt=""
                  />
                </div>


                
                <div class="content-sections">
                  <!-- 操作是否播放的视频,对应的样式设置为false代表不使用,true代表使用 -->
      <!--即注意:当操作:class时,对应的key-value的value一般是对应的false和true,来代表是否使用该class-->
                  <div :class="{
                    'content-section':lesson.id != lessonid,
                  'content-section content-section-choose':lesson.id == lessonid
                  }" 
                  v-for="(lesson,index) in section.courseLessonList" :key="index">
                  <!--lesson.id == lessonid为true时,操作对应的播放样式-->
                    
                    <!--第一章,前两节-->
                    <div v-if="index<2">
                    <div class="section-item clearfix">
                       <!--lesson.id == lessonid为true时,操作对应的按钮播放样式-->
                      <span :class="{
                    'kw-icon-video section-type-icon':lesson.id != lessonid,
                  'kw-icon-video section-type-icon lv':lesson.id == lessonid
                  }"
                        ><i class="el-icon-video-play"></i
                      ></span>
                       <!--lesson.id == lessonid为true时,操作对应的播放课时介绍(主题)字体样式-->
                       <span :class="{
                    'section-dec':lesson.id != lessonid,
                  'section-dec  lv':lesson.id == lessonid
                  }">
                     {{lesson.theme}}</span>
                      
                      <div v-if="lesson.id != lessonid">
                    <!--没有登录,就是试看-->
                      <span v-if="!isLogin" class="section-status-icon pause-play">试看</span>
                        <!--登录了,但没有购买,也是试看-->
       <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">试看</span>
                        <!--登录了,且购买了,那就是播放-->
                          <span v-else class="section-status-icon pause-play">播放</span>
                      </div>
                       <div v-if="lesson.id == lessonid">
                    <!--没有登录,就是试看-->
                      <span v-if="!isLogin" class="section-status-icon pause-play"></span>
                        <!--登录了,但没有购买,也是试看-->
       <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play"></span>
                        <!--登录了,且购买了,那就是播放-->
                          <span v-else class="section-status-icon pause-play"></span>
                      </div>
                    </div>
                    <div class="section-duration">
   <span v-if="lesson.courseMedia != null">时长:{{lesson.courseMedia.duration}}</span>
                            <span v-else>时长:无媒体文件</span>
                    </div>
                    </div>

            <!--第一章除了前两节-->
              <div v-if="index>1">
                    <div class="section-item clearfix">
                      <span :class="{
                    'kw-icon-video section-type-icon':lesson.id != lessonid,
                  'kw-icon-video section-type-icon lv':lesson.id == lessonid
                  }"
                        ><i class="el-icon-video-play"></i
                      ></span>
                      <span :class="{
                    'section-dec':lesson.id != lessonid,
                  'section-dec  lv':lesson.id == lessonid
                  }">{{lesson.theme}}</span>
                        <!--没有登录,就是锁-->
                      <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span>
                        <!--登录了,但没有购买,也是锁-->
        <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">未解锁</span>
                        <!--登录了,且购买了,那就是播放-->
       <span v-else-if="lesson.id != lessonid" class="section-status-icon pause-play">播放</span>
                          <span v-else class="section-status-icon pause-play"></span>
                    </div>
                    <div class="section-duration">
         <span v-if="lesson.courseMedia != null">时长:{{lesson.courseMedia.duration}}</span>
                            <span v-else>时长:无媒体文件</span>
                    </div>
                    </div>


                  </div>
                </div>
              </div>
              <!--第一章结束-->
                <!--其他章开始-->
<div v-for="(section,index) in course.courseSectionList.slice(1,course.courseSectionList.length)" 
     :key="index">
                
                <div class="content-label">
                  <div class="content-label-title single-line">{{section.sectionName}}</div>
                  <img
                    class="arrow-icon"
                    src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII="
                    alt=""
                  />
                </div>

                <div class="content-sections">
                  <!-- 操作是否播放的视频 -->
                
                     <div :class="{
                    'content-section':lesson.id != lessonid,
                  'content-section content-section-choose':lesson.id == lessonid
                  }" 
                  v-for="(lesson,index) in section.courseLessonList" :key="index">
                  <div>
        
                    <div class="section-item clearfix">
                       <span :class="{
                    'kw-icon-video section-type-icon':lesson.id != lessonid,
                  'kw-icon-video section-type-icon lv':lesson.id == lessonid
                  }"
                        ><i class="el-icon-video-play"></i
                      ></span>
                      <span :class="{
                    'section-dec':lesson.id != lessonid,
                  'section-dec  lv':lesson.id == lessonid
                  }">{{lesson.theme}}</span>
                        <!--没有登录,就是锁-->
                      <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span>
                        <!--登录了,但没有购买,也是锁-->
      <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">未解锁</span>
                        <!--登录了,且购买了,那就是播放-->
                    
        <span v-else-if="lesson.id != lessonid" class="section-status-icon pause-play">播放</span>
                          <span v-else class="section-status-icon pause-play"></span>
                    </div>
                    <div class="section-duration">
          <span v-if="lesson.courseMedia != null">时长:{{lesson.courseMedia.duration}}</span>
                            <span v-else>时长:无媒体文件</span>
                    </div>

                  </div>

                  </div>
                </div>
              </div>
              <!--其他章结束-->
            </div>
对应的样式地址,记得进行替换(是videoDetail.vue组件):
链接:https://pan.baidu.com/s/1AD141qyMnHyv3veJ06kwJw
提取码:alsk
至此对应的状态也操作完毕,自己运行看看吧
接下来操作点击跳转视频:
任然是videoDetail.vue组件
//所以章里面的的都加上@click="playlesson"进行操作(无论是第一章还是其他章),进行视频的切换
  <div :class="{
                    'content-section':lesson.id != lessonid,
                  'content-section content-section-choose':lesson.id == lessonid
                  }" 
                  v-for="(lesson,index) in section.courseLessonList" :key="index"
                  @click="playLesson(lesson)"
                  >
 //播放课程
    playLesson(lesson) {
      //将对应的播放视频变成我点击的视频
      this.lessonid = lesson.id; //修改对应的id,一般用来操作前面的样式
      this.myvideo.src = lesson.courseMedia.fileEdk //将地址进行改变,使得视频也改变
      //这里并不需要循环,就如循环里说的,使用现成的即可

    },
至此可以进行视频的切换了,虽然对应的按钮操作是特殊的,一般只能点击视频进行视频的观看
但是在观看切换时,可以点击按钮进行观看,而使得不会变化
这实际上并不是好的视频组件,因为并不是完全的根据按钮状态来执行,但这也并不需要操作,因为能看即可
实际上是因为每次的操作,都会进行取反(对应的播放,而切换时,并不会,所以使得出现上面的情况)
为了解决这样的问题,需要加上如下代码:
 //播放课程
    playLesson(lesson) {
      //将对应的播放视频变成我点击的视频
      this.lessonid = lesson.id; //修改对应的id,一般用来操作前面的样式
      this.myvideo.src = lesson.courseMedia.fileEdk //将地址进行改变,使得视频也改变
      //这里并不需要循环,就如循环里说的,使用现成的即可
      this.myvideo.play();
      this.isplay = true //呈现播放状态
        //使得重置为执行视频(只是对应的状态,即显示样式的确定),因为上面的就是需要执行视频
        //这一就可以操作了,具体可以看对应的代码
        

    },
对应的我们的显示控制面板可能是有问题的(位置与点击不同,如播放按钮)
若不使用这个面板,可以使得自带的控制面板,代码如下:
 mounted() {
    this.myvideo = document.getElementById("myvideo");
    this.myvideo.controls = true //显示对应的控制面板
    this.initplay() //初始化播放的视频,即当我到达这个页面,要播放的是对应的那个视频,基本不会是其他的视频
  },
接下来删除对应的面板:
找到对应的div,其他的代码删除掉即可,这一就使用对应的控制面板了(video自带的),而不是使用我们自己操作的
 <div
     id="player-video-vontainer"
        class="player-container video-container"
   >
              
                <video
                  style="width: 100%; height: 100%;"
                  id="myvideo"
  src="https://video.pearvideo.com/mp4/adshort/20200901/cont-1693694-15359233_adpkg-ad_hd.mp4"
                  @canplay="getInit"
                  @timeupdate="handlerNowTime"
      />
               
     </div>
可能对应的视频是没有的,所以需要判断:
 //播放课程
    playLesson(lesson) {
      if(lesson.courseMedia!=null){ //只要没有对应的视频,那么就不会有任何操作,并给出提示
          //之所以还需要判断,是因为虽然从课程那里过来时,不可点击
          //但可以点击其他的进入,所以需要判断,除非你进行验证删除,但是这时非常麻烦的
          //所以基本不做考虑,且不符合实际(因为我已经买了课,需要显示出来)
      //将对应的播放视频变成我点击的视频
      this.lessonid = lesson.id; //修改对应的id,一般用来操作前面的样式
      
      this.myvideo.src = lesson.courseMedia.fileEdk //将地址进行改变,使得视频也改变
      //这里并不需要循环,就如循环里说的,使用现成的即可
      this.myvideo.play();
      this.isplay = true
      }else{
        this.$message.warning("没有该视频")
    
      }
    },
但是虽然我们显示了状态,但是也要进行判断,使得对应状态真实起作用,代码如下:
//先修改对应的方法
//第一章的@click="playLesson(1,index,lesson)"
//第二章的@click="playLesson(2,index,lesson)"
最终的修改:
   //播放课程
    playLesson(status,index,lesson) {
      if(lesson.courseMedia!=null){

  //试看的可以跳转播放页面
  if(status == 1 && index<2){

      //将对应的播放视频变成我点击的视频
      this.lessonid = lesson.id; //修改对应的id,一般用来操作前面的样式
      
      this.myvideo.src = lesson.courseMedia.fileEdk //将地址进行改变,使得视频也改变
      //这里并不需要循环,就如循环里说的,使用现成的即可
      this.myvideo.play();
      this.isplay = true
  }else{
    //锁上的先验证是否登录
    if(!this.isLogin){
      this.$message.success("请先登录")
    }else{
      //登录的,再验证是否购买过
      if(!this.isBuy){
        this.$message.warning("请先购买后,进行解锁")
      }else{
         //将对应的播放视频变成我点击的视频
      this.lessonid = lesson.id; //修改对应的id,一般用来操作前面的样式
      
      this.myvideo.src = lesson.courseMedia.fileEdk //将地址进行改变,使得视频也改变
      //这里并不需要循环,就如循环里说的,使用现成的即可
      this.myvideo.play();
      this.isplay = true
          //可以将这个else里面的代码用一个方法包括起来,也可以不用,看你自己如何操作
      }
  }
  }
      }else{
        this.$message.error("播放失败,暂无视频")
    
      }
    },
至此播放的操作基本全部编写完毕
接下来我们继续操作留言:
但在这之前,我们需要操作一下后端
因为虽然前面编写后端时,操作了点赞以及点赞总数的操作,但并不能知道对应的赞是谁点的,所以我们需要联查
新增对应的entity项目的entity包下的类:
package com.lagou.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.Date;
import java.io.Serializable;

/**
 * 课程留言点赞表(CourseCommentFavoriteRecord)实体类
 *
 * @author makejava
 * @since 2022-07-23 20:26:35
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseCommentFavoriteRecord implements Serializable {
    private static final long serialVersionUID = 159062001487532233L;
    /**
     * 用户评论点赞j记录ID
     */
    private Integer id;
    /**
     * 用户ID
     */
    private Integer userId;
    /**
     * 用户评论ID
     */
    private Integer commentId;
    /**
     * 是否删除,0:未删除(已赞),1:已删除(取消赞状态)
     */
    private Integer isDel;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新时间
     */
    private Date updateTime;

}
修改对应的CourseComment类:
package com.lagou.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.Date;
import java.io.Serializable;

/**
 * 课程留言表(CourseComment)实体类
 *
 * @author makejava
 * @since 2022-07-15 19:48:04
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseComment implements Serializable {
    private static final long serialVersionUID = -11641570368573216L;
    
     //一条留言对应多个点赞
    private List<CourseCommentFavoriteRecord> favoriteRecords;
    
    /**
     * 主键
     */
    private Object id;
    /**
     * 课程id
     */
    private Integer courseId;
    /**
     * 章节id
     */
    private Integer sectionId;
    /**
     * 课时id
     */
    private Integer lessonId;
    /**
     * 用户id
     */
    private Integer userId;
    /**
     * 运营设置用户昵称
     */
    private String userName;
    /**
     * 父级评论id
     */
    private Integer parentId;
    /**
     * 是否置顶:0不置顶,1置顶
     */
    private Integer isTop;
    /**
     * 评论
     */
    private String comment;
    /**
     * 点赞数
     */
    private Integer likeCount;
    /**
     * 是否回复留言:0普通留言,1回复留言
     */
    private Integer isReply;
    /**
     * 留言类型:0用户留言,1讲师留言,2运营马甲 3讲师回复 4小编回复 5官方客服回复
     */
    private Integer type;
    /**
     * 留言状态:0待审核,1审核通过,2审核不通过,3已删除
     */
    private Integer status;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新时间
     */
    private Date updateTime;
    /**
     * 是否删除
     */
    private Integer isDel;
    /**
     * 最后操作者id
     */
    private Integer lastOperator;
    /**
     * 是否发送了通知,1表示未发出,0表示已发出
     */
    private Integer isNotify;
    /**
     * 标记归属
     */
    private Integer markBelong;
    /**
     * 回复状态 0 未回复 1 已回复
     */
    private Integer replied;


}


修改对应的dao层项目的接口(CourseCommentDao)对应的配置文件:
<!--修改部分的xml-->
    <resultMap type="com.lagou.entity.CourseComment" id="CourseCommentMap">
        <result property="id" column="id"/>
        <result property="courseId" column="course_id"/>
        <result property="sectionId" column="section_id"/>
        <result property="lessonId" column="lesson_id"/>
        <result property="userId" column="user_id"/>
        <result property="userName" column="user_name"/>
        <result property="parentId" column="parent_id"/>
        <result property="isTop" column="is_top"/>
        <result property="comment" column="comment"/>
        <result property="likeCount" column="like_count"/>
        <result property="isReply" column="is_reply"/>
        <result property="type" column="type"/>
        <result property="status" column="status"/>
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
        <result property="isDel" column="is_del"/>
        <result property="lastOperator" column="last_operator"/>
        <result property="isNotify" column="is_notify"/>
        <result property="markBelong" column="mark_belong"/>
        <result property="replied" column="replied"/>

         <collection property="favoriteRecords" 
                     ofType="com.lagou.entity.CourseCommentFavoriteRecord">
            <result property="id" column="ccfr_id"/>
            <result property="userId" column="ccfr_user_id"/>
            <result property="commentId" column="comment_id"/>
            <result property="isDel" column="ccfr_is_del"/>
            <result property="createTime" column="ccfr_create_time"/>
            <result property="updateTime" column="ccfr_update_time"/>
        </collection>
    </resultMap>

  <select id="getCommentsByCourseId" resultMap="CourseCommentMap">
      <!--
最好加上对应的别名,可能在idea里面会特殊的显示
但并不会真正的将该显示的别名作用到程序里面,具体以mysql为主
如idea显示对应的别名以对应表别名结合,但mysql却不会
-->
        SELECT
            cc.*,
            ccfr.id ccfr_id,ccfr.user_id ccfr_user_id,comment_id,
       ccfr.is_del ccfr_is_del,ccfr.create_time ccfr_create_time,
       ccfr.update_time ccfr_update_time
        FROM course_comment cc LEFT JOIN course_comment_favorite_record ccfr 
       ON cc.id = ccfr.`comment_id`
        WHERE cc.is_del = 0
          AND course_id = #{courseId}
        ORDER BY is_top DESC,like_count DESC,cc.create_time DESC
            LIMIT #{offset},#{pagesize}
    </select>

<!--进行修改即可,这里再分页查询时,进行关联,使得可以知道有那些用户给出点赞-->
添加对应dao层项目的TestCourse类里添加测试方法:
   @Test
    public void getCoument(){
        List<CourseComment> commentsByCourseId = courseCommentDao.getCommentsByCourseId(1, 0, 20);
        System.out.println(commentsByCourseId);
        for(CourseComment courseComment: commentsByCourseId ){
            System.out.println("\n"+courseComment.getUserName() +"=>留言:" + 
                               courseComment.getComment());
            for(CourseCommentFavoriteRecord favoriteRecord : courseComment.getFavoriteRecords()){
                System.out.println("-------------->" + favoriteRecord.getUserId() + "点过赞");
            }
        }
    }
进行测试,查看是否有对应的点赞数据,若有,且对应,那么操作完成
接下来我们操作赞:
回到Course.vue:
 <div class="message-list-title">
                          <div class="message-list-title-left">
                            <div class="message-list-title-left-name">{{comment.userName}}</div>
                            <div class="message-list-title-left-tag"></div>
                          </div>
                          <!--
                            indexOf查找对应出现的下标,若没有找到则返回-1,找到了则返回对应的下标
                          所以需要大于等于0(之所以是0,因为可能是第一个)

下面的v-if里面的逻辑是使得对应的用户是否对该留言点赞过,若点赞过,则使用对应的样式,否则就是其他样式
实际上只需要找userId即可,而不用"\"userId\":"+user.content.id
因为数据库的类型基本基本不能加上userId的值,当然了,下面的设置只是为了防止特殊情况
                          -->
                        
                         <!--点过赞的-->
     <div v-if='JSON.stringify(comment.favoriteRecords).indexOf("\"userId\":"+user.content.id) >=0 
                && JSON.stringify(comment.favoriteRecords).indexOf("\"isDel\":0") >=0  ' 
          class="message-list-title-right">
                          
                            <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAJFBMVEVHcEwAuI4AtIsAtIsAtIoAtYwAtIsAtYwAtowAx5kAtIsAs4qd4c1kAAAAC3RSTlMAGMfz3VGnbTYIhXtDq8EAAAETSURBVDjLldWhb8JAFAbwg8CGhGSGzNQtULNkWUioWbJkpmYKAQaBITPLLKZysmLz+xfolUL6/XM72msh9N2X8ImaX17vrq+vVeqU39XTuK/kdEMA01jGDY4ZyYWFIRPxp0S8u+8KeBJ+WDxIGFrMJbQm7qhVYSJgr8JUwNsKtYDtCiHgPavcsDVDstsuyDk7NeYDk6G8pM3bWXNawQUijWq8QyPPpQy+50ET9bF09go5pus3cMV0feFEc2DfieZRBU7Up7fjSkwZZgz3DA8MHxl6DP8YRgxjgokimDHcMdwyfGG4ZPjJMCKoY4KJIpgz3DHcMvQYFuPpk/005t1mffHlOs/ETvxXAA0Ul3oQHsp/xD93wxfHcC4VkwAAAABJRU5ErkJggg==" alt="">
                            <div class="message-list-title-right-praise">{{comment.likeCount}}</div>
                          </div>
                          <!--没点过赞的-->
        <div v-else class="message-list-title-right">
                            <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAKlBMVEVHcExnZ2dzc3NmZmZqampmZmZmZmZnZ2dnZ2dnZ2dmZmZoaGhmZmZmZmZl+8SAAAAADXRSTlMA/AbsFtilbj5YwSqJPyESoQAAAZxJREFUOMt1lTtLA1EQha8xRhPTBEmhuKCCoNgoIlYLMcRKBG0sxIUgCDaBSDohEO0FEbQyIBZaBazERvAPWCwxPnP+i3tnrlGTmVPswn73NXNm7hrzq9m9kZ2ckTUUABifkOEBrK7liR7BMRFOA/uFc+BUgnV8mFisEW5IsIFi9FzBuwR91KJnAm8S9EIbxSBeBRZHk86MrBQJWjymJUC3nlugSyk+SQyhANfxos+s4krfM0DZvmbw2cuSCHNGi3PAfUygXYiU79ryyw1ibf0xZ9intBsz6SBadx24iiZXz8kPxCiTtYdLPzKTVFkkLQAZO/VikwYW/x/wHohcT/MiPQE8W9frxJrlbpiw4xvA0vbNmWyhj2Nrhmy+B7nEyTsN0rIaJAc0SDWqwX7rhAYfMa/Dui0bDZbwZAwUGNjWUWActnUUyN2hwDTaOkxRaSiwj6pRhjHKgTazSkWlwBK1jgIpBwrkHCgwyZ0oQ86BAjkHCjziG0KE8YBvCA/5KacOm6sgrHFAotouT6J23bkkLbsNDjM9yt7yP+IbQYga5De+eBMAAAAASUVORK5CYII=" alt="">
                            <div class="message-list-title-right-praise">{{comment.likeCount}}</div>
                          </div>
                        </div>
至此通过对应的关联查询,就解决了对应的用户是否点赞的问题
接下来进行点赞和取消赞的操作:
 <div @click="zan(comment,$event)"
      v-if='JSON.stringify(comment.favoriteRecords).indexOf("\"userId\":"+user.content.id) >=0 
                && JSON.stringify(comment.favoriteRecords).indexOf("\"isDel\":0") >=0  ' 
          class="message-list-title-right">
 <div @click="zan(comment,$event)" v-else class="message-list-title-right">
 //取消赞和点赞一起的操作(取反)
    zan(comment,th){ 

let a = th.currentTarget.childNodes[0]
for(let i =0;i<comment.favoriteRecords.length;i++){
  let o = comment.favoriteRecords[i];
  if(o.userId == this.user.content.id && o.isDel == 0){

a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAKlBMVEVHcExnZ2dzc3NmZmZqampmZmZmZmZnZ2dnZ2dnZ2dmZmZoaGhmZmZmZmZl+8SAAAAADXRSTlMA/AbsFtilbj5YwSqJPyESoQAAAZxJREFUOMt1lTtLA1EQha8xRhPTBEmhuKCCoNgoIlYLMcRKBG0sxIUgCDaBSDohEO0FEbQyIBZaBazERvAPWCwxPnP+i3tnrlGTmVPswn73NXNm7hrzq9m9kZ2ckTUUABifkOEBrK7liR7BMRFOA/uFc+BUgnV8mFisEW5IsIFi9FzBuwR91KJnAm8S9EIbxSBeBRZHk86MrBQJWjymJUC3nlugSyk+SQyhANfxos+s4krfM0DZvmbw2cuSCHNGi3PAfUygXYiU79ryyw1ibf0xZ9intBsz6SBadx24iiZXz8kPxCiTtYdLPzKTVFkkLQAZO/VikwYW/x/wHohcT/MiPQE8W9frxJrlbpiw4xvA0vbNmWyhj2Nrhmy+B7nEyTsN0rIaJAc0SDWqwX7rhAYfMa/Dui0bDZbwZAwUGNjWUWActnUUyN2hwDTaOkxRaSiwj6pRhjHKgTazSkWlwBK1jgIpBwrkHCgwyZ0oQ86BAjkHCjziG0KE8YBvCA/5KacOm6sgrHFAotouT6J23bkkLbsNDjM9yt7yP+IbQYga5De+eBMAAAAASUVORK5CYII="
   break;
  }else{

    a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAJFBMVEVHcEwAuI4AtIsAtIsAtIoAtYwAtIsAtYwAtowAx5kAtIsAs4qd4c1kAAAAC3RSTlMAGMfz3VGnbTYIhXtDq8EAAAETSURBVDjLldWhb8JAFAbwg8CGhGSGzNQtULNkWUioWbJkpmYKAQaBITPLLKZysmLz+xfolUL6/XM72msh9N2X8ImaX17vrq+vVeqU39XTuK/kdEMA01jGDY4ZyYWFIRPxp0S8u+8KeBJ+WDxIGFrMJbQm7qhVYSJgr8JUwNsKtYDtCiHgPavcsDVDstsuyDk7NeYDk6G8pM3bWXNawQUijWq8QyPPpQy+50ET9bF09go5pus3cMV0feFEc2DfieZRBU7Up7fjSkwZZgz3DA8MHxl6DP8YRgxjgokimDHcMdwyfGG4ZPjJMCKoY4KJIpgz3DHcMvQYFuPpk/005t1mffHlOs/ETvxXAA0Ul3oQHsp/xD93wxfHcC4VkwAAAABJRU5ErkJggg=="
  }
 
}
        
        //前面在标签里的判断是为了初始化的显示,这里是为了点击赞或者取消赞时
        //进一步进行解决,因为初始化的判断后面的isDel是代表全部
        //实际上可以通过修改sql语句来进行改变,那样就更加方便了

        //alert("赞和取消赞")
         return this.axios.get("http://localhost:8002/course/comment/Favorite/"+comment.id+
                               "/"+this.user.content.id).then(res => {
        
           //重新获取本课程的全部留言,使得更新数据
     this.getComment()
    }).catch(err =>{
      this.$message.error("点赞失败")
    })
    },
至此可以通过点击赞进行操作了
对应的sql方式:
<select id="getCommentsByCourseId" resultMap="CourseCommentMap">
        SELECT
            cc.*,
            ccfr.id ccfr_id,ccfr.user_id ccfr_user_id,comment_id,
    ccfr.is_del ccfr_is_del,ccfr.create_time ccfr_create_time,ccfr.update_time ccfr_update_time
        FROM course_comment cc LEFT JOIN 
    (select * from course_comment_favorite_record where is_del =0) ccfr ON cc.id = ccfr.`comment_id`
        WHERE cc.is_del = 0
          AND course_id = #{courseId}
        ORDER BY is_top DESC,like_count DESC,cc.create_time DESC
            LIMIT #{offset},#{pagesize}
    
    <!--  (select * from course_comment_favorite_record where is_del =0)这一步是关键-->
    </select>
对应的html:
  <div @click="zan(comment)" 
       v-if='JSON.stringify(comment.favoriteRecords).indexOf("\"userId\":"+user.content.id) >=0'  
       class="message-list-title-right">
   <div @click="zan(comment)" v-else class="message-list-title-right">
 zan(comment){ 

        //alert("赞和取消赞")
         return this.axios.get("http://localhost:8002/course/comment/Favorite/"+comment.id+
                               "/"+this.user.content.id).then(res => {
        
           //重新获取本课程的全部留言,使得更新数据
     this.getComment()
    }).catch(err =>{
      this.$message.error("点赞失败")
    })
    },
发现,只需要改变一下sql,那么代码就省略了很多,实际上sql对数据的操作更加接近,而程序一般会通过很多逻辑进行改变
所以若可以使用sql进行优化的,最好考虑sql,即在优化前,sql最好优先考虑
点赞操作完成了,接下来我们操作留言的发表
<button class="message-edit-btn disableBg" @click="saveComment">发表留言</button>
 <div class="message-edit">
              
               <textarea rows="20" style="border:none;resize: none;" 
                contenteditable="true"
                placeholder="分享学习心得、思考感悟或者给自己一个小鼓励吧!"
                class="edit-div pcStyle"
                          v-model="comment"
              ></textarea>
              <div class="message-edit-count">
                <span class="message-edit-count-cur">0</span>
                <span class="message-edit-count-max">/2000</span>
              </div>
            </div>
data() {
    return {
      comment:null, //待发表的留言内容
      activeName: "intro",
      course:null,
      totalLessons:0, //本门课程的总节数
      commentList:null, //所有留言
      isLogin:false, //false,未登录
      isBuy:false,//未购买
      user:null, //当前用户,{}对象可以","结尾
      myCourseList:[], //当前用户购买过的所有课程
    };
  },
 //发表留言
    saveComment(){
 return this.axios.get("http://localhost:8002/course/comment/saveCourseComment",{
   params:{
     courseid:this.course.id,
     userid:this.user.content.id,
     username:this.user.content.name,
     comment:this.comment,
  


   }
 }).then(res => {     
      //重新获取本课程的全部留言,使得更新数据
     this.getComment()
    }).catch(err =>{
      this.$message.error("发表留言失败")
    })
    }
我们需要修改后端的代码:
 @GetMapping("comment/saveCourseComment")
    public Object saveCourseComment(Integer courseid,Integer userid,String username,String comment) 
        throws UnsupportedEncodingException {
        System.out.println(new String(username.getBytes("ISO-8859-1")));
     System.out.println(new String(comment.getBytes("ISO-8859-1")));

        username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
        comment = new String(comment.getBytes("ISO-8859-1"),"UTF-8");
        //解决get情况中,传递过来的乱码问题,因为get默认是ISO-8859-1的操作
        //一般来说,get请求会设置成识别中文,而post不会
        //假设若由于版本,服务器或者框架的影响,使得不能识别(一般是服务器问题,即版本问题)
        //也就是默认使用ISO-8859-1编码
        //一般tomcat8及其以后就不需要了
        //那时get会设置成对应的中文识别,也可以说,设置了UTF-8,但低版本的还是默认ISO-8859-1
        //这里好像使用的是tomcat7,所以是默认操作ISO-8859-1
        //即这时,我们需要使用ISO-8859-1进行变成对应的中文
        //然后设置操作UTF-8,虽然并不需要设置,好像的默认的,但也要防止默认识别不了中文
        //这里之所以会这样,与当前的框架或则版本,以及前端可能都有关系,因为一般的get不会出现乱码
        //而乱码主要是对应的编码方式不一致的缘故,无论是什么情况,只要编码一致即可


        CourseComment courseComment = new CourseComment();
        courseComment.setCourseId(courseid); //课程编号
        //这里写为0,因为我们的留言只操作对应的课程,章节和小节并没有操作
        //所以这样的操作,我们称为预留字段
        //即在后面的版本中(如更新版本)进行执行,现在默认写为0,虽然写其他的也可
        courseComment.setSectionId(0); //章节编号,预留字段
        courseComment.setLessonId(0); //小节编号,预留字段
        courseComment.setUserId(userid); //用户编号
        courseComment.setUserName(username); //用户昵称
        courseComment.setParentId(0); //没有父id,预留字段
        courseComment.setComment(comment); //留言内容
        courseComment.setType(0); //0:用户留言,预留字段
        courseComment.setLastOperator(courseid); //最后操作的用户编号
        Integer integer = commentService.saveComment(courseComment);
        return integer;



    }
这时我们进行发表留言,发现,的确有对应的数据了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值