onlineSchool 项目课 八:个人中心部分的开发

本文详细介绍了在线学习平台个人中心的开发过程,包括学习记录的加载、创建或更新,课程详情控制器,个人信息和密码修改,以及查看收到的评论等功能。通过用户ID和课程ID查询学习记录,实现学习状态跟踪,并确保数据一致性。
摘要由CSDN通过智能技术生成

一,点击左边菜单栏的背景色
1,效果预览
在这里插入图片描述

2,将 curNav 和当前的点击对象添加到modal。

mv.addObject("curNav","uhome");
mv.addObject("curNav","uinfo");
mv.addObject("curNav","upassword");
mv.addObject("curNav","ucomment");

3,前台去判断 curNav 是否存在且是当前的点击对象,是就添加背景色,不是就维持原来的样式。

 <li class="<#if curNav?? && curNav =='uhome'>user-menu-nav-cur<#else>user-menu-nav</#if>">我的课程<span>&gt;</span></li>

二,学习记录的加载
1,只有登录的用户才有学习记录。
在这里插入图片描述

2,通过当前登录用户的 userId, 获取 user_course_section表 t 中当前登录的用户的学习记录,对数据做关联查询,关联course c 表,section s 表。查询对应的课程的名称和对应的章节的名称,通过t表的 courseId,t表的 sectionId 建立与 course表,courseSection表的关联。

<select id="queryUserCourse" parameterType="com.langshan.onlineschoollangshan.domain.UserCourseSection" resultMap="bean_map">
		SELECT t.id,t.courseId,t.sectionId,
		c.name as courseName,s.name as sectionName,
		t.updateAt
		FROM user_course_section t,course c,course_section s
		WHERE t.courseId = c.id
		AND t.sectionId = s.id
		AND t.userId = #{userId}
	</select>

3,返回的学习记录的 list 数据加载到modal中。前台去遍历就可以了。

 	@RequestMapping("uhome")
    public ModelAndView uhome(){
        ModelAndView mv = new ModelAndView("zY/user_home");
        mv.addObject("curNav","uhome");
        //获取当前登录用户的id
        Long userId = ShiroContext.getSessionUser().getId();
        //做关联查询 查出对应的课程名称和章节的名称
        UserCourseSection userCourseSection = new UserCourseSection();
        userCourseSection.setUserId(userId);
        List<UserCourseSection> list = userCourseSectionService.queryUserCourse(userCourseSection);
        mv.addObject("studyRecord",list);
        return mv;
    }

4,查询对应字段的意义
查询 t表 courseId:展示课程名称时,可以点击请求到课程详情页面。

 <a href="${base}/course/${item.courseId!}">${item.courseName!}</a>                  

查询 t表 sectionId:展示小节名称时,点击可以请求到课程学习页面。

  <a href="${base}/learn/${item.sectionId!}">
<span class="continue-btn"style="margin-left: 50px">继续学习</span>
  </a>

t表的updateAt:展示最近一次更新学习记录表数据的时间。最近一次学习该课程小节的时间。

 <span>${item.updateAt?string('yyyy-MM-dd')}</span>

5,关联查询要在返回的 resultMap 中 domain 中添加对应的字段,否则数据查询不出来。
在这里插入图片描述
在这里插入图片描述

三,学习记录的创建或更新 :学习页面与学习记录表的开发
1,学习记录表记录的是哪个登录的用户 userId,学习哪个课程 courseId,哪个小节的数据 sectionId,所以
在这里插入图片描述

当登录的用户在这里插入图片描述

点击哪个课程在这里插入图片描述

开始学习,学习课程的小节在这里插入图片描述

到这个页面,学习记录的数据才会被创建在这里插入图片描述
2,先根据当前登录的用户的 id 和小节数据的 courseId去查学习记录表。(章节数据共用一个数据库中的表,章节数据创建在同一个课程下,所以每一条章节的数据都有courseId)
在这里插入图片描述
为了避免查询学习记录时受到垃圾数据的影响,通过 id 降序排序,只查一条数据

<select id="queryUserCourseSection" parameterType="com.langshan.onlineschoollangshan.domain.UserCourseSection" resultMap="bean_map">
		SELECT
		<include refid="all_columns"  />
		FROM user_course_section
		WHERE userId = #{userId}
		AND courseId = #{courseId}
		ORDER BY id DESC
		LIMIT 0,1
	</select>

4,如果查得到学习记录说明该用户曾学过该课程,就去更新现学的对应的小节的数据。如果该用户没有该课程的学习记录,就去创建这条学习记录。设置不为空的字段 status 和 rate。

public void mergeUserCourseSection(CourseSection courseSection){
//去查登录用户的学习记录
        if (ShiroContext.isLogin()){
            Long userId = ShiroContext.getSessionUser().getId();
            UserCourseSection userCourseSection = new UserCourseSection();
            userCourseSection.setUserId(userId);
            userCourseSection.setCourseId(courseSection.getCourseId());
            UserCourseSection curUserCourseSection = userCourseSectionService.queryUserCourseSection(userCourseSection); 
        if (curUserCourseSection == null){
    //如果数据库中没有获取到该登录用户的课程学习记录
                //创建学习记录
         userCourseSection.setSectionId(courseSection.getId());
         userCourseSection.setStatus(0L);
         userCourseSection.setRate(0L);
         userCourseSectionService.create(userCourseSection);
         }else {
                //获取到学习记录,更新现学的小节的数据
             curUserCourseSection.setSectionId(courseSection.getId()); 
             userCourseSectionService.update(curUserCourseSection);
            }
        }

创建的是传入数据库中查询为空的对象。
更新的是从数据库中可以获取到学习记录的,更新现学的小节的数据。
名字长容易搞混

5,调用 service 中的create方法,update方法,设置updateAt,把当前时间设置为创建/更新学习记录的时间。这样,去加载学习记录的时间才有数据。

public void create(UserCourseSection entity){
		entity.setCreateAt(new Date());
		entity.setUpdateAt(new Date());
		entityDao.create(entity);
	}

	public void update(UserCourseSection entity){
		entity.setCreateAt(new Date());
		entity.setUpdateAt(new Date());
		entityDao.update(entity);
	}

在学习第四部分之前:

点击请求到课程的详情的controller在这里插入图片描述
课程详情的controller返回一个页面在这里插入图片描述
课程详情的controller,将sectionId对应的章节数据加载到modal中,在页面中遍历出来,点击请求到 learn controller在这里插入图片描述
返回 learn页面通过sectionId获取对应小节数据的videoUrl,播放视频
在这里插入图片描述

四,课程详情 controller 和 user_course_section表的开发:

对于已经登录的用户在这里插入图片描述如果学习过该课程,打开课程的详情页面在这里插入图片描述
点击开始学习在这里插入图片描述
应播放对应的小节数据的videoUrl
在这里插入图片描述

 CourseSection courseSection = null;
        if (ShiroContext.isLogin()){
            //登录的用户去查学习记录表,查得到就把对应的小节数据加载到modal,learn页面根据小节的数据的videoUrl去播放
            UserCourseSection userCourseSection = new UserCourseSection();
            userCourseSection.setUserId(ShiroContext.getSessionUser().getId());
            userCourseSection.setCourseId(courseId);
            UserCourseSection resultUserCourseSection = userCourseSectionService.queryUserCourseSection(userCourseSection);
            if (resultUserCourseSection != null){
                CourseSection curCourseSection = courseSectionService.getById(resultUserCourseSection.getSectionId());
                mv.addObject("curCourseSection",curCourseSection);
            }

2,如果用户没有登录,或者没有学习过该课程,就默认将遍历出来的第1章第1节的数据加载到model中。

 Map<Long, chapterSectionBean> chapterMap = courseSectionService.queryChapterSection(courseId);
        mv.addObject("chapterMap",chapterMap);
if (courseSection == null){
                Iterator<chapterSectionBean> it = chapterMap.values().iterator();
                if (it.hasNext()) {
                    chapterSectionBean firstChapter = it.next();
                    if (firstChapter != null) {
                        mv.addObject("curSection", firstChapter.getSections().get(0));
                    }
                }
            }

如何得知该用户有没有学习过该课程?queryUserCourseSection方法,传入登录用户的id和当前课程的id,查询数据库学习记录表的数据。在这里插入图片描述

<select id="queryUserCourseSection" parameterType="com.langshan.onlineschoollangshan.domain.UserCourseSection" resultMap="bean_map">
		SELECT
		<include refid="all_columns"  />
		FROM user_course_section
		WHERE userId = #{userId}
		AND courseId = #{courseId}
		ORDER BY id DESC
		LIMIT 0,1
	</select>

总结:如果查询登录用户的学习记录表,学习过该课程那么有返回的学习记录。就将对应的sectionId的章节数据加载到modal,前台去遍历小节数据的id并请求learn页面,再根据对应小节的videoUrl去播放,如果没有登录或者没有学习记录的用户,就默认学习课程的第一章第一节的数据。
如果登录的用户第一次学习该课程下的小节,学习记录也会被创建到数据库,并在我的课程页面加载出来。

五,修改个人信息
1,通过菜单栏的 a标签请求uinfo Controller返回一个页面,实现页面结构。通过当前登录用户的id,getById去数据库查询对应的用户的数据,加载到modal。
前台去遍历数据,处理图片数据。(有详细的讲处理图片的笔记,这里不讲了)

<a href="${base}/uinfo">
  <li class="<#if curNav?? && curNav =='uinfo'>user-menu-nav-cur<#else>user-menu-nav</#if>">个人信息<span>&gt;</span></li>
</a>
 @RequestMapping("uinfo")
    public ModelAndView uinfo(){
        ModelAndView mv = new ModelAndView("zY/user_info");
        mv.addObject("curNav","uinfo");
        //获取修改前的数据
        Long userId = ShiroContext.getSessionUser().getId();
        AuthUser authUser = authUserService.getById(userId);
        if (authUser != null){
            mv.addObject("authUser",authUser);
        }
        return mv;
    }

在这里插入图片描述
2,把修改后的数据ajaxSubmit提交到后台。个人数据更新成功或失败都通过id传入信息。

    function doSubmit() {
    $('#uinfoForm').ajaxSubmit({
        dataType:'json',
        success:function (resp) {
            if (resp.errcode == 0){
                _os.alertMsg("个人数据修改成功")
            }else {
                _os.alertMsg("个人数据修改失败")
            }
        }
    })
    }

3,后台根据当前用户的id去更新数据。

 @RequestMapping("saveInfo")
    @ResponseBody
    public String saveInfo(AuthUser authUser,String userHeader){
        //对图片数据的处理
        if (StringUtils.isNotEmpty(userHeader)){
            Long id = attachmentService.createAttachment("userHeader",userHeader);
            authUser.setHeader(id.toString());
        }
        //修改后的个人的数据通过当前用户的id去更新
        Long id = ShiroContext.getSessionUser().getId();
        authUser.setId(id);
        authUserService.update(authUser);
        return JsonView.successJson();
    }

4,mapper中去掉username动态的sql,username对于登录时要一致,注册时不可重复,查看时不可修改。

六,修改密码信息
1,通过菜单栏的a标签请求 upassword Controller返回一个页面,实现页面结构。

<a href="${base}/upassword">
 <li class="<#if curNav?? && curNav =='upassword'>user-menu-nav-cur<#else>user-menu-nav</#if>">修改密码<span>&gt;</span></li>
</a>
@RequestMapping("upassword")
    public ModelAndView upassword(){
        ModelAndView mv = new ModelAndView("zY/user_password");
        mv.addObject("curNav","upassword");
        return mv;
    }

在这里插入图片描述

2,前端:提交前旧密码不为空。新密码和确认密码要相同。(与注册时一样。)否则传入失败信息,数据回滚。
3个密码都经过64位的hash编码并设置到输入框,再提交到后台。
在点击提交的函数中处理,不要页面加载完成以后就处理。

function doSubmit() {
    let username = '${user.username}'
    let oldPassword = $('#oldPassword').val()
    let password = $('#password').val()
    let rePassword = $('#rePassword').val()

    if (_os.isEmpty(oldPassword)) {
        _os.alertMsg("旧密码不能为空")
        return;
    }
    if (password != rePassword) {
        _os.alertMsg("新密码于确认密码要相同")
        return;
    }

    oldPassword = sha256.hmac(username, oldPassword)
    $('#oldPassword').val(oldPassword)

    password = sha256.hmac(username, password)
    $('#password').val(password)

    rePassword = sha256.hmac(username, rePassword)
    $('#rePassword').val(rePassword)

    $('#passwordForm').ajaxSubmit({
        dataType: 'json',
        success: function (resp) {
            if (resp.errcode == 0) {
                _os.alertMsg("修改成功")
            } else {
                _os.alertMsg(resp.message)
            }
        }
    })

}

3,Controller中判断前端提交过来的3个密码不为空。
获取当前登录用户的数据库中的信息。
旧密码的密文与数据库的密文一致。新密码与确认密码一致。就将新密码的密文保存到数据库。

@RequestMapping("savePassword")
@ResponseBody
    public String savePassword(String oldPassword,String password,String rePassword){
        if(StringUtils.isEmpty(oldPassword)|| StringUtils.isEmpty(password)||StringUtils.isEmpty(rePassword)){
            return JsonView.failureJson("密码不能为空");
        }

        AuthUser authUser = ShiroContext.getSessionUser();
        authUser = this.authUserService.getById(authUser.getId());

        oldPassword = HashUtil.hmacSha256(oldPassword,authUser.getSalt());
        //旧密码的密文与数据库的密文一致。
        if(authUser.getPassword().equals(oldPassword)){
        //新密码与确认密码一致。
            if(password.equals(rePassword)){
            //将新密码的密文保存到数据库。
                password = HashUtil.hmacSha256(password,authUser.getSalt());
                authUser.setPassword(password);
                this.authUserService.update(authUser);
                return JsonView.successJson();
            }else{
                return JsonView.failureJson("新密码和确认密码不一致");
            }
        }else{
            return JsonView.failureJson("旧密码输入错误");
        }
    }

4,如果改密码改忘了,直接去数据库重置密码,文档中有。

七,发给我的评论
通过菜单栏的 a标签请求ucomment Controller返回一个页面。
获取当前登录用户的用户名,查询course comment表的toUsernane,查询发给我的评论。

<a href="${base}/ucomment">
 <li class="<#if curNav?? && curNav =='ucomment'>user-menu-nav-cur<#else>user-menu-nav</#if>">我的评论<span>&gt;</span></li>
</a>
 @RequestMapping("ucomment")
    public ModelAndView ucomment(){
        ModelAndView mv = new ModelAndView("zY/user_comment");
        mv.addObject("curNav","ucomment");
        String username = ShiroContext.getSessionUsername();
        List commentList = courseCommentService.queryUserCourseComment(username);
        mv.addObject("commentList",commentList);
        return mv;
    }

2,queryUserCourseComment方法,查询课程评论表中,发给我的评论。
在这里插入图片描述

<select id="queryUserCourseComment" parameterType="java.lang.String" resultMap="bean_map">
		SELECT
		<include refid="all_columns"  />
		FROM course_comment
		WHERE to_username = #{username}
		ORDER BY id DESC
</select>

3,实现页面结构
在这里插入图片描述

4,引用的内容也显示出来,先判断被引用的内容存在且不为空才显示。

 <#if item.refContent?? && item.refContent != ''>
 <div style="padding: 5px; background-color: #f6f6f6;">
         <span>${item.refContent!}</span>
 </div>
 </#if>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值