谷粒学院项目
项目前台设计
一:搭建项目前台系统环境
使用NUXT搭建项目前台系统环境
(1)项目结构介绍
nuxt中页面加载过程
二:整合项目前台前端页面
1.安装幻灯片插件
2.配置幻灯片插件
3.复制项目使用的静态资源
4.定义布局
<template>
<div class="in-wrap">
<!-- 公共头引入 -->
<header id="header">
<section class="container">
<h1 id="logo">
<a href="#" title="谷粒学院">
<img src="~/assets/img/logo.png" width="100%" alt="谷粒学院">
</a>
</h1>
<div class="h-r-nsl">
<ul class="nav">
<router-link to="/" tag="li" active-class="current" exact>
<a>首页</a>
</router-link>
<router-link to="/course" tag="li" active-class="current">
<a>课程</a>
</router-link>
<router-link to="/teacher" tag="li" active-class="current">
<a>名师</a>
</router-link>
<router-link to="/article" tag="li" active-class="current">
<a>文章</a>
</router-link>
<router-link to="/qa" tag="li" active-class="current">
<a>问答</a>
</router-link>
</ul>
<ul class="h-r-login">
<li id="no-login">
<a href="/sing_in" title="登录">
<em class="icon18 login-icon"> </em>
<span class="vam ml5">登录</span>
</a>
|
<a href="/sign_up" title="注册">
<span class="vam ml5">注册</span>
</a>
</li>
<li class="mr10 undis" id="is-login-one">
<a href="#" title="消息" id="headerMsgCountId">
<em class="icon18 news-icon"> </em>
</a>
<q class="red-point" style="display: none"> </q>
</li>
<li class="h-r-user undis" id="is-login-two">
<a href="#" title>
<img src="~/assets/img/avatar-boy.gif" width="30" height="30" class="vam picImg" alt>
<span class="vam disIb" id="userName"></span>
</a>
<a href="javascript:void(0)" title="退出" onclick="exit();" class="ml5">退出</a>
</li>
<!-- /未登录显示第1 li;登录后显示第2,3 li -->
</ul>
<aside class="h-r-search">
<form action="#" method="post">
<label class="h-r-s-box">
<input type="text" placeholder="输入你想学的课程" name="queryCourse.courseName" value>
<button type="submit" class="s-btn">
<em class="icon18"> </em>
</button>
</label>
</form>
</aside>
</div>
<aside class="mw-nav-btn">
<div class="mw-nav-icon"></div>
</aside>
<div class="clear"></div>
</section>
</header>
<!-- /公共头引入 -->
<nuxt/>
<!-- 公共底引入 -->
<footer id="footer">
<section class="container">
<div class>
<h4 class="hLh30">
<span class="fsize18 f-fM c-999">友情链接</span>
</h4>
<ul class="of flink-list">
<li>
<a href="http://www.atguigu.com/" title="尚硅谷" target="_blank">尚硅谷</a>
</li>
</ul>
<div class="clear"></div>
</div>
<div class="b-foot">
<section class="fl col-7">
<section class="mr20">
<section class="b-f-link">
<a href="#" title="关于我们" target="_blank">关于我们</a>|
<a href="#" title="联系我们" target="_blank">联系我们</a>|
<a href="#" title="帮助中心" target="_blank">帮助中心</a>|
<a href="#" title="资源下载" target="_blank">资源下载</a>|
<span>服务热线:010-56253825(北京) 0755-85293825(深圳)</span>
<span>Email:info@atguigu.com</span>
</section>
<section class="b-f-link mt10">
<span>©2018课程版权均归谷粒学院所有 京ICP备17055252号</span>
</section>
</section>
</section>
<aside class="fl col-3 tac mt15">
<section class="gf-tx">
<span>
<img src="~/assets/img/wx-icon.png" alt>
</span>
</section>
<section class="gf-tx">
<span>
<img src="~/assets/img/wb-icon.png" alt>
</span>
</section>
</aside>
<div class="clear"></div>
</div>
</section>
</footer>
<!-- /公共底引入 -->
</div>
</template>
<script>
import "~/assets/css/reset.css";
import "~/assets/css/theme.css";
import "~/assets/css/global.css";
import "~/assets/css/web.css";
export default {};
</script>
5.定义首页面
<template>
<div>
<!-- 幻灯片 开始 -->
<!-- 幻灯片 结束 -->
<div id="aCoursesList">
<!-- 网校课程 开始 -->
<div>
<section class="container">
<header class="comm-title">
<h2 class="tac">
<span class="c-333">热门课程</span>
</h2>
</header>
<div>
<article class="comm-course-list">
<ul class="of" id="bna">
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img src="~/assets/photo/course/1442295592705.jpg" class="img-responsive" alt="听力口语">
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="听力口语" class="course-title fsize18 c-333">听力口语</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">9634人学习</i>
|
<i class="c-999 f-fA">9634评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img src="~/assets/photo/course/1442295581911.jpg" class="img-responsive" alt="Java精品课程">
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="Java精品课程" class="course-title fsize18 c-333">Java精品课程</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">501人学习</i>
|
<i class="c-999 f-fA">501评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img src="~/assets/photo/course/1442295604295.jpg" class="img-responsive" alt="C4D零基础">
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="C4D零基础" class="course-title fsize18 c-333">C4D零基础</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">300人学习</i>
|
<i class="c-999 f-fA">300评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img src="~/assets/photo/course/1442302831779.jpg" class="img-responsive" alt="数学给宝宝带来的兴趣">
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="数学给宝宝带来的兴趣" class="course-title fsize18 c-333">数学给宝宝带来的兴趣</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">256人学习</i>
|
<i class="c-999 f-fA">256评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img
src="~/assets/photo/course/1442295455437.jpg"
class="img-responsive"
alt="零基础入门学习Python课程学习"
>
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始
学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a
href="#"
title="零基础入门学习Python课程学习"
class="course-title fsize18 c-333"
>零基础入门学习Python课程学习</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">137人学习</i>
|
<i class="c-999 f-fA">137评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img
src="~/assets/photo/course/1442295570359.jpg"
class="img-responsive"
alt="MySql从入门到精通"
>
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始
学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="MySql从入门到精通" class="course-title
fsize18 c-333">MySql从入门到精通</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">125人学习</i>
|
<i class="c-999 f-fA">125评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img
src="~/assets/photo/course/1442302852837.jpg"
class="img-responsive"
alt="搜索引擎优化技术"
>
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始
学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="搜索引擎优化技术" class="course-title
fsize18 c-333">搜索引擎优化技术</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">123人学习</i>
|
<i class="c-999 f-fA">123评论</i>
</span>
</section>
</div>
</li>
<li>
<div class="cc-l-wrap">
<section class="course-img">
<img
src="~/assets/photo/course/1442295379715.jpg"
class="img-responsive"
alt="20世纪西方音乐"
>
<div class="cc-mask">
<a href="#" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" title="20世纪西方音乐" class="course-title
fsize18 c-333">20世纪西方音乐</a>
</h3>
<section class="mt10 hLh20 of">
<span class="fr jgTag bg-green">
<i class="c-fff fsize12 f-fA">免费</i>
</span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">34人学习</i>
|
<i class="c-999 f-fA">34评论</i>
</span>
</section>
</div>
</li>
</ul>
<div class="clear"></div>
</article>
<section class="tac pt20">
<a href="#" title="全部课程" class="comm-btn c-btn-2">全部课程</a>
</section>
</div>
</section>
</div>
<!-- /网校课程 结束 -->
<!-- 网校名师 开始 -->
<div>
<section class="container">
<header class="comm-title">
<h2 class="tac">
<span class="c-333">名师大咖</span>
</h2>
</header>
<div>
<article class="i-teacher-list">
<ul class="of">
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="姚晨">
<img alt="姚晨" src="~/assets/photo/teacher/1442297885942.jpg">
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="姚晨" class="fsize18 c-666">姚晨</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">北京师范大学法学院副教授</span>
</div>
<div class="mt15 i-q-txt">
<p
class="c-999 f-fA"
>北京师范大学法学院副教授、清华大学法学博士。自2004年至今已有9年
的司法考试培训经验。长期从事司法考试辅导,深知命题规律,了解解题技巧。内容把握准确,授课重
点明确,层次分明,调理清晰,将法条法理与案例有机融合,强调综合,深入浅出。</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="谢娜">
<img alt="谢娜" src="~/assets/photo/teacher/1442297919077.jpg">
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="谢娜" class="fsize18 c-666">谢娜</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">资深课程设计专家,专注10年AACTP美国培训协会认证导师</span>
</div>
<div class="mt15 i-q-txt">
<p
class="c-999 f-fA"
>十年课程研发和培训咨询经验,曾任国企人力资源经理、大型外企培训经
理,负责企业大学和培训体系搭建;曾任专业培训机构高级顾问、研发部总监,为包括广东移动、东莞
移动、深圳移动、南方电网、工商银行、农业银行、民生银行、邮储银行、TCL集团、清华大学继续教
育学院、中天路桥、广西扬翔股份等超过200家企业提供过培训与咨询服务,并担任近50个大型项目的
总负责人。</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="刘德华">
<img alt="刘德华" src="~/assets/photo/teacher/1442297927029.jpg">
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="刘德华" class="fsize18 c-666">刘德华</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">上海师范大学法学院副教授</span>
</div>
<div class="mt15 i-q-txt">
<p
class="c-999 f-fA"
>上海师范大学法学院副教授、清华大学法学博士。自2004年至今已有9年
的司法考试培训经验。长期从事司法考试辅导,深知命题规律,了解解题技巧。内容把握准确,授课重
点明确,层次分明,调理清晰,将法条法理与案例有机融合,强调综合,深入浅出。</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="周润发">
<img alt="周润发" src="~/assets/photo/teacher/1442297935589.jpg">
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="周润发" class="fsize18 c-666">周润发</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">考研政治辅导实战派专家,全国考研政
治命题研究组核心成员。</span>
</div>
<div class="mt15 i-q-txt">
<p
class="c-999 f-fA"
>法学博士,北京师范大学马克思主义学院副教授,专攻毛泽东思想概论、
邓小平理论,长期从事考研辅导。出版著作两部,发表学术论文30余篇,主持国家社会科学基金项目和
教育部重大课题子课题各一项,参与中央实施马克思主义理论研究和建设工程项目。</p>
</div>
</section>
</li>
</ul>
<div class="clear"></div>
</article>
<section class="tac pt20">
<a href="#" title="全部讲师" class="comm-btn c-btn-2">全部讲师</a>
</section>
</div>
</section>
</div>
<!-- /网校名师 结束 -->
</div>
</div>
</template>
<script>
export default {
}
</script>
6.整合幻灯片
Nuxt路由:
首页数据显示-banner接口:
1.创建service-cms模块
2.创建配置文件
# 服务端口
server.port=8004
# 服务名
spring.application.name=service-cms
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/cmsservice/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.创建数据库表,根据表使用代码生成器生成代码
4.后台对bannber管理的接口(crud操作)-----前台对bannber显示接口
(1)后台banner管理接口
package com.atguigu.educms.controller;
import com.atguigu.commonutils.R;
import com.atguigu.educms.entity.CrmBanner;
import com.atguigu.educms.service.CrmBannerService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 后台banner管理接口
* </p>
*
* @author testjava
* @since 2022-10-17
*/
@RestController
@RequestMapping("/educms/banneradmin")
@CrossOrigin
public class BannerAdminController {
@Autowired
private CrmBannerService crmBannerService;
// 1.分页查询banner
@GetMapping("pageBanner/{page}/{limit}")
public R pageBanner(@PathVariable long page, @PathVariable long limit) {
Page<CrmBanner> crmBannerPage = new Page<>(page, limit);
IPage<CrmBanner> crmBannerIPage = crmBannerService.page(crmBannerPage, null);
return R.ok().data("items", crmBannerIPage.getRecords()).data("total", crmBannerIPage.getTotal());
}
// 2.添加banner
@PostMapping("addBanner")
public R addBanner(@RequestBody CrmBanner crmBanner) {
crmBannerService.save(crmBanner);
return R.ok();
}
// 3.修改banner
@PostMapping("updateBanner")
public R updateBanner(@RequestBody CrmBanner crmBanner) {
crmBannerService.updateById(crmBanner);
return R.ok();
}
// 4.删除banner
@DeleteMapping("deleteBannerById/{id}")
public R deleteBanner(@PathVariable String id) {
crmBannerService.removeById(id);
return R.ok();
}
}
(2)前台banner管理接口
controller:
```
package com.atguigu.educms.controller;
import com.atguigu.commonutils.R;
import com.atguigu.educms.entity.CrmBanner;
import com.atguigu.educms.service.CrmBannerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前台banner显示接口
* </p>
*
* @author testjava
* @since 2022-10-17
*/
@RestController
@RequestMapping("/educms/bannerfront")
@CrossOrigin
public class BannerFrontController {
@Autowired
private CrmBannerService crmBannerService;
// 查询所有banner
@GetMapping("getAllBanner")
public R getAllBanner() {
// 根据id进行降序排序,显示排列之后前两条数据
QueryWrapper<CrmBanner> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
// last方法,拼接sql语句
wrapper.last("limit 2");
List<CrmBanner> list = crmBannerService.selectAllBanner();
return R.ok().data("list", list);
}
}
```
service:
package com.atguigu.educms.service.impl;
import com.atguigu.educms.entity.CrmBanner;
import com.atguigu.educms.mapper.CrmBannerMapper;
import com.atguigu.educms.service.CrmBannerService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 首页banner表 服务实现类
* </p>
*
* @author testjava
* @since 2022-10-17
*/
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {
// 查询所有banner
@Override
public List<CrmBanner> selectAllBanner() {
List<CrmBanner> crmBanners = baseMapper.selectList(null);
return crmBanners;
}
}
首页数据显示-热门课程和名师接口:
controller:
package com.atguigu.eduservice.controller.front;
import com.atguigu.commonutils.R;
import com.atguigu.eduservice.entity.EduCourse;
import com.atguigu.eduservice.entity.EduTeacher;
import com.atguigu.eduservice.service.EduCourseService;
import com.atguigu.eduservice.service.EduTeacherService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/eduservice/indexfront")
@CrossOrigin
public class IndexFrontController {
@Autowired
private EduCourseService eduCourseService;
@Autowired
private EduTeacherService eduTeacherService;
// 查询前8条热门课程,查询前4条名师
@GetMapping("index")
public R index() {
// 查询前8条热门课程
QueryWrapper<EduCourse> wrapperCourse = new QueryWrapper<>();
wrapperCourse.orderByDesc("view_count");
wrapperCourse.last("limit 8");
List<EduCourse> eduCourses = eduCourseService.list(wrapperCourse);
// 查询前4条名师
QueryWrapper<EduTeacher> wrapperTeacher = new QueryWrapper<>();
wrapperTeacher.orderByDesc("id");
wrapperTeacher.last("limit 4");
List<EduTeacher> teachers = eduTeacherService.list(wrapperTeacher);
return R.ok().data("eduCourses", eduCourses).data("teachers", teachers);
}
}
首页数据显示-banner显示(前端):
1.前端页面准备工作
(1)使用命令,下载axios依赖
cnpm install axios
(2)封装axios
import axios from 'axios'
// 创建axios实例
const service = axios.create({
baseURL: 'http://localhost:9001',
timeout: 20000
})
export default service
(3)具体开发
banner.js
import request from '@/utils/request'
export default {
// 查询前两条Banner的信息
getListBanner() {
return request({
url: `/educms/bannerfront/getAllBanner`,
method: 'get'
})
}
}
在index.vue中进行调用
在index.vue中进行显示
首页数据显示-热门课程和讲师显示(前端):
同上
Redis:
往项目中添加redis缓存:
执行过程:
添加注解:
第三步 启动Redis服务:
略
第四步 在service_cms配置文件中配置redis地址
登录业务介绍(单点登录)
古老方式:
单点登录:
单点登录实现方式:
session复制:其中一个模块登陆以后,将session复制到其它模块当中去(每个模块对应一个session)
缺点:当项目中有很多模块时,这种方式会造成资源的极大浪费.
JWT介绍:
JWT生成字符串介绍:
项目添加JWT工具类:
1:
2:JWT工具类
package com.atguigu.commonutils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author helen
* @since 2019/10/16
*/
public class JwtUtils {
// 常量
public static final long EXPIRE = 1000 * 60 * 60 * 24; // 设置token过期时间
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO"; // 密钥
// 生成token字符串的方法
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam( "alg", "HS256")
.setSubject("guli-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.claim("id", id)
.claim("nickname", nickname)
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token字符串获取用户信息
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken))
return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
阿里云短信服务介绍:
TODO:
登录功能(接口):
3、编写controller和service
// 登录方法
@Override
public String login(UcenterMember ucenterMember) {
// 获取登录手机号和密码(其实这里的手机号是邮箱,我们用邮箱来代替手机号)
String mobile = ucenterMember.getMobile();
String password = ucenterMember.getPassword();
// 手机号和密码非空判断
if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)) {
throw new GuliException(20001, "登陆失败");
}
// 判断手机号是否正确
QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", mobile);
UcenterMember member = baseMapper.selectOne(queryWrapper);
if (member == null) {
// 现在数据库中没有这个手机号
throw new GuliException(20001, "登陆失败");
}
// 判断密码
// 因为存储到数据库中的密码肯定是加密的
// 将前端传来的密码进行加密以后,在和数据库中的密码进行比较
// 加密方式:MD5
password = MD5.encrypt(password);
if (!password.equals(member.getPassword())) {
// 密码不一致
throw new GuliException(20001, "登陆失败");
}
// 判断用户是否禁用
if (member.getIsDisabled()) {
// 用户禁用
throw new GuliException(20001, "登陆失败");
}
// 登陆成功---使用jwt生成token字符串
// member中才有完成信息 ucenterMember只有手机号和密码
String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
return jwtToken;
}
注册功能(接口):
package com.atguigu.educenter.entity.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "注册对象", description = "注册对象")
public class RegisterVo {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
private String code;
}
3、编写service
// 注册方法
@Override
public void register(RegisterVo registerVo) {
String code = registerVo.getCode(); // 验证码
String email = registerVo.getMobile();// 手机号(其实是邮箱)
String nickname = registerVo.getNickname();// 昵称
String password = registerVo.getPassword();// 密码
// 非空判断
if (StringUtils.isEmpty(email) || StringUtils.isEmpty(code) || StringUtils.isEmpty(nickname) || StringUtils.isEmpty(password)) {
throw new GuliException(20001, "注册失败");
}
// 判断用户输入的验证码和我们发送的验证码是否相同
// 从redis中获取给用户发送的验证码
String redis_code = redisTemplate.opsForValue().get(email);
if (!code.equals(redis_code)) {
throw new GuliException(20001, "注册失败");
}
// 判断手机号(邮箱)是否重复,如果重复的话,我们就不往数据库中加入了
QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", email);
Integer count = baseMapper.selectCount(queryWrapper);
if (count >= 1) {
// 表里有相同的手机号
throw new GuliException(20001, "注册失败");
}
// 数据添加到数据库中
UcenterMember ucenterMember = new UcenterMember();
ucenterMember.setMobile(email);
ucenterMember.setNickname(nickname);
ucenterMember.setPassword(MD5.encrypt(password));
ucenterMember.setIsDisabled(false);
ucenterMember.setAvatar("https://guli-file-190513.oss-cn-beijing.aliyuncs.com/avatar/default.jpg");
baseMapper.insert(ucenterMember);
}
根据token获取用户信息(接口):
// 根据token获取用户信息
@GetMapping("getMemberInfo")
public R getMemberInfo(HttpServletRequest request) {
// 调用jwt工具类的方法,根据request对象获取头信息,返回用户id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
UcenterMember member = memberService.getById(memberId);
return R.ok().data("userInfo", member);
}
首页面登录和注册页面整合:
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
import VueQriously from 'vue-qriously'
import ElementUI from 'element-ui' //element-ui的全部组件
import 'element-ui/lib/theme-chalk/index.css'//element-ui的css
Vue.use(ElementUI) //使用elementUI
Vue.use(VueQriously)
Vue.use(VueAwesomeSwiper)
注册前端整合:
4、最终注册页面实现
<template>
<div class="main">
<div class="title">
<a href="/login">登录</a>
<span>·</span>
<a class="active" href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="params">
<el-form-item class="input-prepend restyle" prop="nickname" :rules="[{required: true, message: '请输入你的昵称', trigger: 'blur' }]">
<div>
<el-input type="text" placeholder="你的昵称" v-model="params.nickname"/>
<i class="iconfont icon-user"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="mobile"
:rules="[{ required: true, message: '请输入邮箱', trigger: 'blur' }]">
<div>
<el-input type="text" placeholder="邮箱" v-model="params.mobile"/>
<i class="iconfont icon-phone"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="code" :rules="
[{ required: true, message: '请输入验证码', trigger: 'blur' }]">
<div style="width: 100%;display: block;float: left;position: relative">
<el-input type="text" placeholder="验证码" v-model="params.code"/>
<i class="iconfont icon-phone"/>
</div>
<div class="btn" style="position:absolute;right: 0;top: 6px;width:
40%;">
<a href="javascript:" type="button" @click="getCodeFun()"
:value="codeTest" style="border: none;background-color: none">{{codeTest}}</a>
</div>
</el-form-item>
<el-form-item class="input-prepend" prop="password" :rules="[{ required:
true, message: '请输入密码', trigger: 'blur' }]">
<div>
<el-input type="password" placeholder="设置密码" v-model="params.password"/>
<i class="iconfont icon-password"/>
</div>
</el-form-item>
<div class="btn">
<input type="button" class="sign-up-button" value="注册" @click="submitRegister()">
</div>
<p class="sign-up-msg">
点击 “注册” 即表示您同意并愿意遵守简书
<br>
<a target="_blank" href="http://www.jianshu.com/p/c44d171298ce">用户协议</a>
和
<a target="_blank" href="http://www.jianshu.com/p/2ov8x3">隐私政策</a> 。
</p>
</el-form>
<!-- 更多注册方式 -->
<div class="more-sign">
<h6>社交帐号直接注册</h6>
<ul>
<li><a id="weixin" class="weixin" target="_blank"
href="http://huaan.free.idcfengye.com/api/ucenter/wx/login"><i
class="iconfont icon-weixin"/></a></li>
<li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont
icon-qq"/></a></li>
</ul>
</div>
</div>
</div>
</template>
<script>
import '~/assets/css/sign.css'
import '~/assets/css/iconfont.css'
import registerApi from '@/api/register'
export default {
layout: 'sign',
data() {
return {
params: { // 封装注册输入数据
mobile: '',
code: '', // 验证码
nickname: '',
password: ''
},
sending: true, //是否发送验证码
second: 60, //倒计时间
codeTest: '获取验证码'
}
},
methods: {
// 注册提交方法
submitRegister(){
registerApi.registerMember(this.parems)
.then(response =>{
// 提示信息
this.$message({
type: 'success',
message: '注册成功!'
});
// 跳转到登陆页面
this.$router.push({path:'/login'})
})
},
// 倒计时方法
timeDown() {
let result = setInterval(() => {
--this.second;
this.codeTest = this.second
if (this.second < 1) {
clearInterval(result);
this.sending = true;
//this.disabled = false;
this.second = 60;
this.codeTest = "获取验证码"
}
}, 1000);
},
// 通过输入的邮箱,发送验证码
getCodeFun(){
registerApi.sendCode(this.params.mobile)
.then(response =>{
this.sending = false
this.codeTest = 60
// 调用倒计时的方法
this.timeDown()
})
}
// checkPhone (rule, value, callback) {
// //debugger
// if (!(/^1[34578]\d{9}$/.test(value))) {
// return callback(new Error('手机号码格式不正确'))
// }
// return callback()
// }
}
}
</script>