更新中
service-edu:教学相关api接口服务⭐
前端模板的登陆改造
### POST 退出登录
直接返回成功
### GET 获取用户信息接口
传入token,直接返回角色值、用户名和头像地址
### POST 用户登录接口
直接返回成功和写死的token
讲师管理⭐
这个都很简单
POST 添加讲师✅
POST /edu/teacher/addTeacher
POST 修改讲师✅
POST /edu/teacher/updateTeacher
- 传入讲师对象,直接用mybatis-plus的service.save()
GET 所有讲师列表✅
GET /edu/teacher/getTeacherList
GET 根据Id查询讲师✅
GET /edu/teacher/findByIdTeacher/{id}
DELETE 逻辑删除讲师✅
DELETE /edu/teacher/{id}
GET 分页查询讲师✅
GET /edu/teacher/pageTeacher/{page}/{limit}
POST 分页条件查询讲师✅
POST /edu/teacher/pageTeacherQuery/{page}/{limit}
课程管理⭐
POST 通过上传excel添加课程分类✅
- 引入easyexcel,添加分类对应实体类及注解@ExcelProperty
- 编写监听器,其中invoke方法实现一行一行读取内容;第一个为一级分类,第二个是二级分类
- 编写两个方法,用于判断数据库中是否已经存在一级分类(parent_id为0)、二级分类(parent_id为一级分类的id);
- 若有,则不添加,否则新建对象,set父id和课程名添加
- 获取文件输入流,调用EasyExcel.read()方法进行读取,其中三个参数为流、实体类类型,监听器
在监听器使用service对象访问数据库,需要使用构造器注入没因为这是自己new的对象,不属于spring管理
GET 获取课程分类集合✅
- 创建SubjectNestedVo,包含id、课程名、子节点集合
- 查询出所有一级分类和二级分类课程(因为只有两级,一级通过parent_id==0查询,其余的去那是二级)
- 遍历一级课程,使用BeanUtils拷贝属性给SubjectNestedVo(id,title),每遍历一个都会遍历(foreach)所有二级分类,比较id和parent_id
- 若相等,使用BeanUtils拷贝属性给SubjectVo(其中不包含子节点集合),然后set进子节点集合;不相等便继续遍历
- 遍历完二级分类,将子节点集合set进SubjectNestedVo;最后将SubjectNestedVo add到要返回的finalList集合
- 遍历完一级分类课程,将finalList集合返回
可以考虑使用Stream优化,减少请求数据库的次数
课程详情⭐
后台
DELETE根据课程id删除章节小节课程
GET根据课程id查询课程信息
GET根据课程id查询课程信息
POST根据课程id查询课程信息
POST根据课程id查询课程信息
PUT根据课程id查询课程信息
POST根据课程id查询课程信息
PUT根据课程id查询课程信息
课程小节⭐
DELETE根据课程小节ID删除课程小节信息✅
- 前端传入id,根据id查询到video对象
- 根据video.getVideoSourceId()判断小节中是否还有视频
- 如果有,利用openfeign调用service-vod服务中的deleteAliyunVideo接口方法删除视频
- 如果没有,利用mybatis-plus的Service.removeById()方法直接删除小节
GET根据课程小节ID获取课程小节信息✅
- 前端传入id,从数据库查询出video对象
- 利用BeanUtils拷贝到到videoInfoVo
- 根据isFree字段判断是否免费,然后再set到videoInfoVo的free字段
- 返回videoInfoVo对象数据
优化:是否可以修改下前端,免去这两个免费字段的相互转换(free和isfree),前端vo对象也用isfree对象,为1时显示免费…
GET获取某日视频播放量✅
- 前端传入日期
- 根据日期查询playcount(播放量),偶尔可以用下xml,回顾一下
- 用mybatis-plus:构造条件,字段为date(gmt_create),因为表中时间还有时分秒。
baseMapper.selectCount(Wrapper.eq("date(gmt_create)",day))
- 用xml:
select sum(play_count) from edu_video where date(gmt_modified) = #{day}
- 用mybatis-plus:构造条件,字段为date(gmt_create),因为表中时间还有时分秒。
- 返回的count如果不大于0,便设为0;然后作为data返回
POST添加课程小节信息✅
- 前端传入VideoInfoVo对象
- 利用BeanUtils拷贝到video对象,根据VideoInfoVo.getFree判断是否免费
- 免费,则video.setIsFree(1),否则设为0
- 将video对象添加到数据库
PUT增加视频播放量✅
- 前端传入视频id
- 根据id修改播放量,
- xml方式:
update edu_video set play_count = play_count +1, gmt_modified = now() where video_source_id = #{videoSourceId}
- 使用mybatis-plus:
- xml方式:
- 若返回值大于0,返回成功;否则返回失败
POST根据课程小节ID修改课程小节信息✅
- 前端传入videoInfoVo对象
- 利用BeanUtils拷贝到video对象,根据VideoInfoVo.getFree判断是否免费,免费,则video.setIsFree(1),否则设为0
- 利用mybatis-plus的Service.updateById()方法直接修改小节
课程章节⭐
DELETE✅
- 前端传入章节id
- 当章节中还有小节信息时不允许删除,所以先根据id,用videoService查询是否有章节id和这个相等的,如果count>0,则抛出错误异常,返回失败
- 没有小节信息,则根据传入的id删除对应章节
GET根据课程章节ID获取章节信息接口✅
- 前端传入课程章节id
- 利用mybatis-plus的Service.getById得到章节信息,返回
GET获取课程章节和小节信息✅
- 前端传入课程id
- 先查询出全部章节信息,再查询出所有小节信息,
- 章节vo中包含一个存放小节的list集合,遍历章节,利用Beanutils将查询出的章节信息拷贝到章节vo对象
- 内层进行小节遍历,将小节中的章节id与正在遍历的这一章节的id比较,若相等,利用Beanutils将查询出的小节信息拷贝到小节vo对象,并add到videolist集合中
- 内层遍历完后,将videolist set到章节属性中的小节集合,将章节vo对象add到要返回的集合中;
- 外层遍历完后,返回集合
POST添加课程章节信息接口✅
- 前端传入章节信息对象
- 利用mybatis-plus的Service.save()方法添加
POST修改章节信息接口✅
- 前端传入章节信息对象
- 利用mybatis-plus的Service.updateById()方法修改
课程评论⭐
GET 根据id分页查询所有评论✅
- 前端传入课程id,当前页数和分页数
- 根据课程id查询到课程分页对象后,可以直接返回
- 或者取出所有属性,put进map集合,自己给属性命名,或者在添加一些属性(如hasNext…),返回map集合
POST 添加评论✅
- 前端传入comment对象,
- 从请求头获得token再根据token得到userId
- 如果userId为空,则返回错误,未登录
- 然后利用openfeign调用service_user模块的接口:
ucenterClient.getUserInfo(userId).getData().get("ucenterMember");
得到用户信息 - 然后一次set进传入的comment对象
- 使用mybatis-plus的service.save()添加
DELETE 删除评论✅
- 前端传入评论id
- 从请求头获得token再根据token得到userId
- 如果userId为空,则返回错误,未登录
- 若不为空,删除
感觉需要优化,只可以删除自己的评论(得到userId后,判断是否和评论的memberId是否相等),或者管理员拥有删除所有评论的权限
前台首页⭐
GET获取首页(热门)课程前八讲师前四✅
- 编写indexList方法,返回一个map集合
- 方法中,讲师条件构造器
Wrapper.orderByDesc("sort").last("limit 4")
,课程构造器Wrapper.orderByDesc("view_count").last("limit 8")
- 将返回的list集合pu进map
- 返回result,data为map集合
- 优化:添加缓存
@Cacheable(value = "indexList",key = "'selectIndexList'")
前台讲师⭐
GET 分页查询讲师接口✅
GET /edu/teacherFront/pageTeacherFront/{page}/{limit}
- 前端传入当前页数和每页个数
- 编写pageTeacherFront方法,构造Page对象,根据sort字段排序
baseMapper.selectPage(pageParam,wrapper)
- 因为还需要hasnext、hasprevious属性,所以不能直接返回pageParam(没有前面两个属性,有那个方法)对象,而是把所有属性put进map集合返回
GET 根据讲师id获取讲师信息和讲师所授课程接口✅
GET /edu/teacherFront/getTeacherInfoById/{id}
- 前端传入讲师id
- 编写getTeacherInfoById方法,先根据id查询出teacher对象
- 再编写条件构造器,根据id查出所教课程,按购买数量排序
- 将教师信息和课程集合list封装成map返回
前台课程⭐
CourseFrontController
GET获取课程每日的浏览量,购买量,新增课程数✅
- 前端传入日期
- 利用mybatis-plus的baseMapper.selectCount(wrapper)查询到三者的数量,然后put进map集合返回
GET 根据课程id获取课程信息✅*
-
前端传入课程id,分别获取CourseInfoVo(课程信息表单对象)、List< ChapterVo >(章节信息,其中包含了小节课时信息)
-
先获取课程信息:待更新
-
再获取章节信息:先查询出全部章节信息,再查询出所有小节信息,
-
章节vo中包含一个存放小节的list集合,遍历章节,利用Beanutils将查询出的章节信息拷贝到章节vo对象
-
内层进行小节遍历,将小节中的章节id与正在遍历的这一章节的id比较,若相等,利用Beanutils将查询出的小节信息拷贝到小节vo对象,并add到videolist集合中
-
内层遍历完后,将videolist set到章节属性中的小节集合,将章节vo对象add到要返回的集合中;
-
外层遍历完后,返回集合
POST 分页查询课程章节信息
service-oss:阿里云oss api接口服务⭐
POST头像上传✅
- 开通OSS服务,设置 endpoint、keyId、keySecret、bucketName
- 获取文件上传MultipartFile,编写pictureUpload方法
- 参考官方文档,实现上传,其中最好添加文件名路径,按上传时间对文件分类
- tip:上传文件、图片之类,前端一般用element-ui封装好的组件,其中:action属性,值为请求的全路径名,便可直接发送请求
POST轮播图上传✅
同上
POST课程封面上传✅
同上上
service-vod:视频点播api接口服务⭐
视频也是基于OSS的,所以使用相同的acesskey和secret
DELETE根据id删除视频✅
- 前端传入视频id,参考阿里云文档删除
DELETE批量删除上传的视频✅
- 传入视频id集合,参考阿里云文档删除
- request.setVideoIds(videoIds) 参数可以为多个
GET根据id获取视频凭证✅
- 前端传入视频id,参考阿里云文档获取视频凭证
POST视频上传接口✅
- 前端上传视频,返回videoId
service-acl:用户权限管理api接口服务
GET查询全部菜单
service-cms:cms Banner-api接口服务⭐
后台管理banner表⭐
DELETE根据id删除banner✅
- 根据前端传入id,直接mybatis-plus提供的
service.removeById(bannerId)
GET根据id查询✅
- 根据前端传入id,直接mybatis-plus提供的
service.getById(bannerId)
POST分页条件查询banner✅
1.前端传入page、limit和BannerVo(条件可为null)
2.构造条件orderByDesc("gmt_create","sort")
;如果条件bannerVo为空,直接selectPage,return
3.如果不为空,根据对象的属性一一构造条件,形如 queryWrapper.like(!StringUtils.isEmpty(title),"title", title);
,第一个参数为true时才构造
4.selectPage,return;然后将分页对象中的total和records(数据列表集合)封装进map集合,作为data返回。
POST添加banner✅
- 前端传入banner对象,直接mybatis-plus提供的
service.save(CrmBanner)
POST修改banner信息✅
- 根据前端传入id,直接mybatis-plus提供
service.updateById(CrmBanner)
首页banner表⭐
GET查询所有banner信息✅
- 编写getBannerList方法
- 构造条件
wrapper.orderByDesc("sort").last("limit 5");
返回list集合limit5,只显示五个轮播图
- 优化:添加缓存
@Cacheable(value = "banner",key = "'selectIndexList'")
service-msm:短信api接口服务⭐
GET发送短信✅
- 前端传入手机号码,根据它从redis中获取验证码,如果获取到,删除后重新生成
- 若没有,使用RandomUtil工具类,获取六位随机验证码
- 编写sendCode方法,整合阿里云短信服务,发送短信
- 如果发送成功,将code存入redis中并设置过期时间
- 否则返回失败
service-order:订单相关api接口服务⭐
订单管理⭐
服务描述:
1.课程支付说明
(1)课程分为免费课程和付费课程,如果是免费课程可以直接观看,如果是付费观看的课程,用户需下单支付后才可以观看
(2)如果是免费课程,在用户选择课程,进入到课程详情页面时候,直接显示 “立即观看”,用户点击立即观看,可以切换到播放列表进行视频播放
2、付费课程流程 (1)如果是付费课程,在用户选择课程,进入到课程详情页面时候,会显示 “立即购买”
(2)点击“立即购买”,会生成课程的订单,跳转到订单页面
(3)点击“去支付”,会跳转到支付页面,生成微信扫描的二维码
(4)使用微信扫描支付后,会跳转回到课程详情页面,同时显示“立即观看”
POST创建订单 返回订单号✅
- 前端传入courseId
- 从request对象中获取请求头中的token,利用JwtHelper得到token中的userId,如果为null,抛出未登录异常(在控制台打印的),返回错误
- 编写createOrder方法,传入userId和courseId
- 调用service-user中的getUserInfo接口,得到用户UcenterMember对象信息,
- 调用service-edu中的getCourseInfoFront接口,得到CourseInfoVo对象信息
- 封装order对象(包括courseId、userId、课程封面、会员用户昵称、课程名称、手机号、讲师名称(再courseInfoVo中有teacher信息)、价格(BigDecimal类型,单位:分)、订单状态、支付类型
- 将order对象存入数据库,然后返回订单id
GET根据id查询订单信息✅
- 前端传入订单id
- 使用mybatis-plus的Service.getById()查询出订单信息,直接将order对象作为data返回
GET根据id查询是否购买课程✅
- 前端传入userId和课程id
- 编写getOrderUser方法,参数为userId和课程id
- 构造条件
wrapper.eq("member_id",userId).eq("course_id",courseId).eq("status",1);
调用count(wrapper)方法 - 如果返回值大于0,则说明已购买,返回字符串"已支付",否则返回未支付
- 构造条件
- 将返回的字符串作为data返回
支付日志⭐
GET生成订单二维码✅*
- 前端传入订单id
- 编写createNative方法,
- 根据id查询出订单对象
- 封装生成二维码需要的参数(map集合)
- 通过HttpClient工具类发送Http请求,传递xml参数(微信支付的固定地址)
- 得到请求结果,封装为map,作为data返回
- 同时存入redis,设置过期时间(两小时)
GET查询订单是否支付成功✅*
service-statistics:统计报表api接口服务⭐
GET统计一天的网站数据
- 调用service-user模块的接口,
ucenterClient.countRegister(day)
,得到登录、注册数
定时任务:使用注解@Scheduled,利用cron表达式,每隔一个小时查询一次
GET
service-user:user接口服务⭐
微信登录⭐
GET微信扫描回调
GET获取微信二维码参数
人数统计⭐
GET查询某一天注册、登录人数✅
- 前端传入时间,因为登录、注册时间在数据库中有时分秒,所以要用到date(gmt_create)函数,截取到天
- 构造条件,查询日期相同的注册和登陆人数
- 若查询为null,则赋值为零;将这两个人数put进map集合返回数据
注册登录⭐
GET根据token获取用户信息✅
- 从request获取token
- 利用工具类得到用户id
- 再根据id查询出用户信息返回
GET根据id获取用户信息✅
- 前端传入id,使用mybatis-plus的service.getById得到用户信息,返回
POST用户登录✅
- 前端传入手机号、密码,用LoginVo接受,然后判空
- 利用手机后,查询是否存在用户;不存在,返回错误
- 若存在,判断密码使用MD5加密后,是否和数据库中的相等;若不相等,返回错误
- 若相等,在判断用户是否被禁用;禁用则返回用户不可用
- 然后更新数据库中的登录时间
- 利用JwtHelper工具类生成token(需要传入用户id、name)
- 将token和用户实体类put进map集合,返回
优化:
POST用户注册✅
- 前端传入昵称、手机号、密码、验证码,用RegisterVo接受,然后判空
- 从redis获取存入的验证码(发送短信那里存的),若和传入的不相等,返回验证码错误
- 相等,再查询数据库中是否有相同的手机号,若有 则返回手机号已注册
- 没有,则新建用户实体类,set这些属性(其中密码要加密,用户头像设置一个默认的),save进数据库
- 利用JwtHelper工具类生成token(需要传入用户id、nickname)
- 将token和用户实体类put进map集合,返回
优化:目前登录后不会过期,可以考虑将token存入redis,设置有效期,并且需要添加拦截器,每次请求需要登录的接口都会刷新有效期
登录之后,也可以考虑把userId存入Threadlocal中,这样在一次线程中可以直接从Threadlocal中取,不用每次需要获取用户信息时在从token解析