数据库|谷粒学院之讲师管理模块

第一个页面展示讲师数据,以及增删改操作(数据回显等)
数据库表是edu_teacher
数据库|谷粒学院之讲师管理模块
文章图片

service_edu模块
先代码生成器生成
然后在controller里@Autowired注入service,调用方法来实(@RestController,@RequestMapping在类上)
写application.properties配置文件
创建启动类@SpringBootApplication,内容为SpringApplication.run(当前类.class,args)
创建一个配置类@Configuration,加上@MapperScan("")扫描路径
细节
1.返回的json数据的时间和我们的时间差八小时,需要在配置文件设置

#返回json的全局时间格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8


2.需要获取路径中的值,要在xxxMapping("{xxx}")
在方法的参数里用@PathVariable来获取值

3.浏览器测试只能测get提交,其他方式比如post,delete得用测试工具比如swagger测

4.分页查询需要在路径里输入当前页和每页记录数,用@PathVariable来获取
条件组合查询带分页功能

先创建一个vo类,用来封装前端得到的条件。然后通过对象的方式传递给后端的接口
数据库|谷粒学院之讲师管理模块
文章图片

在对象前加@RequestBody会将条件都封装进一个json对象里来传递,而不加则是一个个单独的数据,required=false表示可以不填写,但是这种注解的方式必须是post提交。
//条件查询并分页,以对象形式得到条件 @PostMapping("pageTeacherCondition/{current}/{limit}")//用RequestBody传递json对象到对象中,需要使用post public R pageTeacherCondition(@PathVariable long current, @PathVariable long limit, @RequestBody(required = false) TeacherQuery teacherQuery) {//创建page对象 Page pageTeacher = new Page<>(current, limit); //构建条件 QueryWrapper wrapper = new QueryWrapper<>(); //多条件组合查询 //动态sql,判断条件值是否为空,不为空就拼接条件 String name = teacherQuery.getName(); Integer level = teacherQuery.getLevel(); String begin = teacherQuery.getBegin(); String end = teacherQuery.getEnd(); if (!StringUtils.isEmpty(name)) { wrapper.like("name", name); } if (!StringUtils.isEmpty(level)) { wrapper.eq("level", level); } if (!StringUtils.isEmpty(begin)) { wrapper.ge("gmt_create", begin); //大于等于 } if (!StringUtils.isEmpty(end)) { wrapper.le("gmt_create", end); //小于等于 }//排序,按时间降序 wrapper.orderByDesc("gmt_create"); //调用方法查询并分页 teacherService.page(pageTeacher, wrapper); long total = pageTeacher.getTotal(); //总记录数 List records = pageTeacher.getRecords(); //数据集合 return R.ok().data("total",total).data("rows",records); }


在实际开发中,这些具体的代码应该写在serviceimpl里,controller里不写具体代码,只是调用service的方法。

前端部分
框架默认的登录页面的登录请求访问的是config里的dev.env.js里的BASE_API加上src的api的login.js里的login方法的url。
在后端EduLoginController里写登录以及用户信息的接口,再在前端的api的login.js里调用接口
完成后会出现一个问题,跨域问题(一个地址去访问另一个地址,协议、ip、端口号任一不同都是跨域)
解决方法:
在controller上加@CrossOrigin,可以允许跨域访问
之后会通过gataway网关来解决这个问题

添加路由(模仿):
{ //这里是讲师管理菜单(路由) path: '/teacher', component: Layout, redirect: '/teacher/table',//默认是显示这个而不是save name: '讲师管理', meta: { title: '讲师管理', icon: 'example' },//icon是图标 children: [ { path: 'table', name: '讲师列表', component: () => import('@/views/edu/teacher/list'), meta: { title: '讲师列表', icon: 'table' } }, { path: 'save', name: '添加讲师', component: () => import('@/views/edu/teacher/save'),//引入路由对应的页面 ( @/相当于./) meta: { title: '添加讲师', icon: 'tree' } }, //隐藏路由,由修改按钮跳转 { path:'edit/:id', name:'EduTeacherEdit', component:() => import('@/views/edu/teacher/save'), meta: { title: '编辑讲师',noCache:true },//不缓存 hidden:true //隐藏路由 } ] }

调用接口(类似):
export default{//显示课程分类列表 getSubjectList(){ return request({ url: `/eduservice/subject/getAllSubject`,//用的是piao method: 'get', }) }}

页面.vue引入api的js文件
import xxx from ''export default{data:{}, //data可以写为data(){return{}}created(){},methods:{}}

分页接口
//1.讲师列表(条件分页) //current当前页,limit每页记录数,teacherQuery条件对象,通过对象获取类的全部参数 getTeacherListPage(current,limit,teacherQuery){ return request({ //方式一url: '/eduservice/teacher/pageTeacherCondition/'+current+"/"+limit, url: `/eduservice/teacher/pageTeacherCondition/${current}/${limit}`,//用的是piao method: 'post', //teacherQuery条件对象,由于后端使用requestbody获取数据 //要用到data,data表示把对象转换成json传递到接口(不是requestbody直接用params:参数) data:teacherQuery }) }


第二个页面根据文件添加课程分类,以树形显示
实体:
public class EduSubject implements Serializable {private static final long serialVersionUID = 1L; @ApiModelProperty(value = "https://www.it610.com/article/课程类别ID") @TableId(value = "https://www.it610.com/article/id", type = IdType.ID_WORKER_STR) private String id; @ApiModelProperty(value = "https://www.it610.com/article/类别名称") private String title; @ApiModelProperty(value = "https://www.it610.com/article/父ID") private String parentId; @ApiModelProperty(value = "https://www.it610.com/article/排序字段") private Integer sort; @ApiModelProperty(value = "https://www.it610.com/article/创建时间") @TableField(fill = FieldFill.INSERT)//自动填充 private Date gmtCreate; @ApiModelProperty(value = "https://www.it610.com/article/更新时间") @TableField(fill = FieldFill.INSERT_UPDATE)//自动填充 private Date gmtModified; }

//一级分类 @Data public class OneSubject { private String id; private String title; //一个一级分类里有多个二级分类 private List children = new ArrayList<>(); }

//二级分类 @Data public class TwoSubject {private String id; private String title; }

根据文件添加课程分类
//添加课程分类 @Override public void saveSubject(MultipartFile file,EduSubjectService subjectService) {try { //文件输入流 InputStream in = file.getInputStream(); //读取Excel EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(subjectService)).sheet().doRead(); } catch (Exception e) { e.printStackTrace(); } }

得到数据库的课程列表
//课程分类列表 @Override public List getAllOneTwoSubject() { //查询所有一级分类 parent_id=0,eq表示等于 QueryWrapper wrapperOne = new QueryWrapper<>(); wrapperOne.eq("parent_id", "0"); List oneSubjectList = baseMapper.selectList(wrapperOne); //查询所有二级分类,ne表示不等于 QueryWrapper wrapperTwo = new QueryWrapper<>(); wrapperTwo.ne("parent_id", "0"); List twoSubjectList = baseMapper.selectList(wrapperTwo); //创建list集合存储最终封装数据 List finalSubjectList = new ArrayList<>(); //封装一级分类 //把查询出来的一级分类的集合遍历,得到每个一级分类对象,放到最终集合里 for (int i = 0; i < oneSubjectList.size(); i++) { //得到oneSubjectList里的每个edusubject对象 EduSubject eduSubject = oneSubjectList.get(i); //把edusubject对象的值取出来放到oneSubject对象里面OneSubject oneSubject = new OneSubject(); //oneSubject.setId(eduSubject.getId()); //oneSubject.setTitle(eduSubject.getTitle()); //这个spring框架的工具作用和上面两行一样,但是当要设置的数据过多时,一个个写不现实用封装工具更便利 BeanUtils.copyProperties(eduSubject,oneSubject); //多个Onesubject对象放到finalSubjectList集合里 finalSubjectList.add(oneSubject); //封装二级分类 //把二级分类遍历放到一级分类集合中(二级分类的循环要放在一级分类的循环里) List twoFinalSubjectList = new ArrayList<>(); //遍历二级分类list集合 for (int m = 0; m < twoSubjectList.size(); m++) { EduSubject tSubject = twoSubjectList.get(m); //判断二级分类属于哪个一级分类 if (tSubject.getParentId().equals(eduSubject.getId())) { TwoSubject twoSubject = new TwoSubject(); //把tsubject的值放到twosubject里,再放到twoFinalSubjectList里 BeanUtils.copyProperties(tSubject,twoSubject); twoFinalSubjectList.add(twoSubject); }}//把二级分类放到一级分类里 oneSubject.setChildren(twoFinalSubjectList); } return finalSubjectList; }





eduvideocontroller里有一个删除小节同时删除视频
需要通过edu模块调用vod 模块的接口方法来实现
将两个服务都在nacos注册中心里注册,才能互相调用

依赖
org.springframework.cloud spring-cloud-starter-netflix-hystrix org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-openfeign



# 服务端口 server.port=8001 # 服务名 spring.application.name=service-edu

# nacos服务地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

#配置熔断器,开启熔断机制 feign.hystrix.enabled=true # 设置hystrix超时时间,默认1000ms hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000



启动类上加
@EnableDiscoveryClient//nacos注册

当服务启动,nacos里就会有这个服务名(账号密码都是nacos,8848端口)

@EnableFeignClients//服务调用

在调用方启动类加上这个注解
然后
import java.util.List; //调用的服务的名称,以及熔断后执行方法的类 @FeignClient(name="service-vod",fallback = VodClientDefeat.class) @Component public interface VodClient {//定义调用的方法的完全路径和方法 //根据视频id删除阿里云视频 @DeleteMapping("/eduvod/video/removeAlyVideo/{id}") public R removeAlyVideo(@PathVariable("id") String id); //删除章节的时候删除所属的多个视频 @DeleteMapping("/eduvod/video/delete-batch") public R deleteBatch(@RequestParam("videoIdList") List videoIdList); }

//当服务器故障导致熔断器起作用断开连接,就会执行这个实现类里的方法 @Component public class VodClientDefeat implements VodClient{ @Override public R removeAlyVideo(String id) { return R.error().message("删除视频出错"); }@Override public R deleteBatch(List videoIdList) { return R.error().message("删除多个视频出错"); } }


【数据库|谷粒学院之讲师管理模块】

    推荐阅读