• 【在线教育】课程科目入门


    文章目录

    2.0 分析

    2.1 环境搭建

    2.1.1 数据库

    2.1.2 后端:环境

    2.1.3 后端:基本模块

    2.1.4 前端

    2.2 查询所有

    2.2.1 后端实现

    2.2.2 前端接口

    2.2.3 前端实现

    2.3 导入科目

    2.3.1 需求

    2.3.2 前端

    2.3.2 前端:完整版

    2.3.4 后端

    2.0 分析

     

    2.1 环境搭建

    2.1.1 数据库

    CREATE DATABASE zx_edu_course;
    USE zx_edu_course;
    ​
    CREATE TABLE `edu_subject`  (
      `id` VARCHAR(32) NOT NULL PRIMARY KEY COMMENT '课程科目ID',
      `title` VARCHAR(10) NOT NULL COMMENT '科目名称',
      `parent_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '父ID',
      `sort` INT(10)  NOT NULL DEFAULT 0 COMMENT '排序字段',
      `gmt_create` DATETIME NOT NULL COMMENT '创建时间',
      `gmt_modified` DATETIME NOT NULL COMMENT '更新时间'
    ) COMMENT = '课程科目';
    ​
    INSERT INTO `edu_subject` VALUES ('1', '云计算', '0', 0, '2020-06-26 09:41:21', '2020-02-20 23:25:58');
    INSERT INTO `edu_subject` VALUES ('2', '系统/运维', '0', 0, '2020-02-20 23:29:59', '2020-02-20 23:29:59');
    INSERT INTO `edu_subject` VALUES ('3', '数据库', '0', 0, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
    INSERT INTO `edu_subject` VALUES ('4', '服务器', '0', 0, '2020-02-20 23:30:19', '2020-02-20 23:30:19');
    ​
    INSERT INTO `edu_subject` VALUES ('5', 'MySQL', '3', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
    INSERT INTO `edu_subject` VALUES ('6', 'Oracle', '3', 2, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
    INSERT INTO `edu_subject` VALUES ('7', 'Tomcat', '4', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
    INSERT INTO `edu_subject` VALUES ('8', 'Nginx ', '4', 2, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
    ​
    INSERT INTO `edu_subject` VALUES ('9', 'MySQL优化', '5', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');

    2.1.2 后端:环境

    • 项目名:zx-service-course

    • pom文件

      
              
              
                  org.springframework.boot
                  spring-boot-starter-web
              
              
              
                  com.alibaba.nacos
                  nacos-client
              
      ​
              
              
                  com.alibaba.cloud
                  spring-cloud-starter-alibaba-nacos-discovery
              
      ​
              
              
                  io.springfox
                  springfox-swagger2
              
              
                  io.springfox
                  springfox-swagger-ui
              
      ​
              
              
                  org.springframework.cloud
                  spring-cloud-starter-openfeign
              
      ​
              
              
                  org.springframework.boot
                  spring-boot-starter-test
              
      ​
              
              
                  com.baomidou
                  mybatis-plus-boot-starter
                  ${mybatis.plus.version}
              
              
              
                  mysql
                  mysql-connector-java
              
              
              
                  com.czxy.zx
                  zx-common31
              
              
                  com.czxy.zx
                  zx-domain31
              
      ​
              
              
                  org.springframework.boot
                  spring-boot-starter-data-redis
              
              
              
                  org.springframework.boot
                  spring-boot-starter-mail
              
              
              
                  org.springframework.boot
                  spring-boot-starter-amqp
              
      ​
              
              
                  com.alibaba
                  fastjson
              
      ​
              
              
                  org.springframework.boot
                  spring-boot-devtools
                  true
              
      ​
              
                  com.alibaba
                  easyexcel
                  3.0.5
              
      ​
          

    • yml文件

      # 服务端口号
      server:
        port: 9020
      # 服务名
      spring:
        application:
          name: course-service
        datasource:
          driverClassName: com.mysql.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/zx_edu_course?useUnicode=true&characterEncoding=utf8
          username: root
          password: 1234
          druid:    #druid 连接池配置
            initial-size: 1       #初始化连接池大小
            min-idle: 1           #最小连接数
            max-active: 20        #最大连接数
            test-on-borrow: true  #获取连接时候验证,会影响性能
        cloud:
          nacos:
            discovery:
              server-addr: 127.0.0.1:8848   #nacos服务地址
        redis:
          database: 0       #数据库索引,取值0-15,表示16个库可选择
          host: 127.0.0.1   #服务器地址
          port: 6379        #服务器连接端口号
        mail:
          host: smtp.126.com          #发送邮件服务器
          username: itcast_lt@126.com #账号
          password: 1qaz2wsx          #密码
          default-encoding: UTF-8     #默认编码时
        rabbitmq:
          host: 127.0.0.1
          port: 5672
          username: guest
          passowrd: guest
          virtualHost: /
        devtools:
          restart:
            enabled: true  #设置开启热部署
            additional-paths: src/main/java #重启目录
            exclude: WEB-INF/**
        freemarker:
          cache: false    #页面不加载缓存,修改即时生效
      ​
      #开启log4j打印SQL语句
      logging:
        level:
          com:
            czxy:
              mapper: debug
      ​
      # mp日志打印
      mybatis-plus:
        configuration:
          log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      ​
      ​

    • 启动类

      package com.czxy.zx;
      ​
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
      import org.springframework.cloud.openfeign.EnableFeignClients;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      public class CourseServiceApplication {
          public static void main(String[] args) {
              SpringApplication.run(CourseServiceApplication.class,args);
          }
      }
      ​
    • 拷贝配置

       

    2.1.3 后端:基本模块

    • 创建JavaBean

      package com.czxy.zx.domain;
      ​
      import com.baomidou.mybatisplus.annotation.IdType;
      import com.baomidou.mybatisplus.annotation.TableField;
      import com.baomidou.mybatisplus.annotation.TableId;
      import com.baomidou.mybatisplus.annotation.TableName;
      import com.fasterxml.jackson.annotation.JsonFormat;
      import lombok.Data;
      import org.springframework.format.annotation.DateTimeFormat;
      ​
      import java.util.ArrayList;
      import java.util.Date;
      import java.util.List;
      ​
      /**
       * 课程科目(EduSubject)表实体类
       *
       * @author 桐叔
       */
      @Data
      @TableName("edu_subject")
      public class EduSubject{
          @TableId(type = IdType.ASSIGN_UUID)
          //课程科目ID
          private String id;
          //科目名称
          private String title;
          //父ID
          private String parentId;
          //排序字段
          private Integer sort;
          //创建时间
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
          private Date gmtCreate;
          //更新时间
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
          private Date gmtModified;
      ​
          @TableField(exist = false)
          @JsonInclude(JsonInclude.Include.NON_EMPTY)     //生成json数据,不包含空元素
          private List children = new ArrayList<>();
      ​
      }

    • 创建mapper

       

      package com.czxy.zx.course.mapper;
      ​
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.czxy.zx.domain.EduSubject;
      import org.apache.ibatis.annotations.Mapper;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      @Mapper
      public interface EduSubjectMapper extends BaseMapper {
      }
      ​

    • 创建service

       

      • 接口

        package com.czxy.zx.course.service;
        ​
        import com.baomidou.mybatisplus.extension.service.IService;
        import com.czxy.zx.domain.EduSubject;
        ​
        /**
         * @author 桐叔
         * @email liangtong@itcast.cn
         */
        public interface EduSubjectService extends IService {
        }
        ​

      • 实现类

        package com.czxy.zx.course.service.impl;
        ​
        import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
        import com.czxy.zx.course.mapper.EduSubjectMapper;
        import com.czxy.zx.course.service.EduSubjectService;
        import com.czxy.zx.domain.EduSubject;
        import org.springframework.stereotype.Service;
        import org.springframework.transaction.annotation.Transactional;
        ​
        /**
         * @author 桐叔
         * @email liangtong@itcast.cn
         */
        @Service
        @Transactional
        public class EduSubjectServiceImpl extends ServiceImpl implements EduSubjectService {
        }
        ​

    • 创建controller

       

      package com.czxy.zx.course.controller;
      ​
      import com.czxy.zx.course.service.EduSubjectService;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      ​
      import javax.annotation.Resource;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      @RestController
      @RequestMapping("/subject")
      public class EduSubjectController {
      ​
          @Resource
          private EduSubjectService eduSubjectService;
      ​
          
      }
      ​
      ​

    • 配置类

       

    2.1.4 前端

    • 创建路由模块

       

      /** When your routing table is too long, you can split it into small modules **/
      ​
      import Layout from '@/layout'
      ​
      const courseRouter = {
        path: '/course',           // 当前模块前缀路径,必须以/开头
        component: Layout,          // 采用布局组件显示当前模块【默认】
        redirect: '/course/subjectList',  // “教师管理”默认显示路由
        name: '课程管理',            // 路由名称
        meta: {
          title: '课程管理',         // 一级菜单名称,children.length==0 隐藏
          icon: 'table'             // 一级菜单图标,children.length==0 隐藏
        },
        children: [
          {
            path: 'subjectList',
            component: () => import('@/views/edu/course/subjectList.vue'),
            name: '科目列表',
            meta: { title: '科目列表', icon: 'list' }   //二级菜单名称
          }
        ]
      }
      export default courseRouter
      ​
    • 创建 subjectList.vue 页面

       

    • 配置路由

       

    2.2 查询所有

    • 以树形table展示数据

     

    2.2.1 后端实现

    • 修改 EduSubjectController

    package com.czxy.zx.course.controller;
    ​
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.czxy.zx.course.service.EduSubjectService;
    import com.czxy.zx.domain.EduSubject;
    import com.czxy.zx.vo.BaseResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    ​
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     */
    @RestController
    @RequestMapping("/subject")
    public class EduSubjectController {
    ​
        @Resource
        private EduSubjectService eduSubjectService;
    ​
        @GetMapping
        public BaseResult findAll() {
            //1 查询所有
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.orderByAsc("parent_id");
            List list = eduSubjectService.list(queryWrapper);
    ​
            //2 处理父子关系
            List resultList = new ArrayList<>();
            Map cache = new HashMap<>();
            list.forEach(eduSubject -> {
                // 获得父
                EduSubject parentEduSubject = cache.get(eduSubject.getParentId());
                // 如果没有父表示第一层,如果有父追加
                if(parentEduSubject != null) {
                    // 如果有孩子,判断父对象的集合
                    List temp = parentEduSubject.getChildren();
                    if(temp == null) {
                        parentEduSubject.setChildren(new ArrayList<>());
                    }
                    // 将孩子添加到父对象的集合中
                    parentEduSubject.getChildren().add(eduSubject);
                } else {
                    resultList.add(eduSubject);
                }
                // 缓存当前
                cache.put(eduSubject.getId(),eduSubject);
    ​
            });
    ​
            return BaseResult.ok("查询成功", resultList);
        }
    ​
    }
    ​

    2.2.2 前端接口

     

    import axios from '@/utils/request'
    ​
    // 查询所有课程科目
    export function findAllSub() {
      return axios.get('/course-service/subject');
    }

    2.2.3 前端实现

    • 修改 @/views/edu/course/subjectList.vue

       

    2.3 导入科目

    2.3.1 需求

     

    2.3.2 前端

    • 使用 upload组件

          
          
            点击上传
            
      只能上传xls或xlsx文件,且不超过500kb
         

    • 声明变量

        data() {
          return {
            fileList: [],     //上传文件列表
            updateUrl: process.env.VUE_APP_BASE_API + '/course-service/subject/upload',   //上传路径
          }
        },

    • 编写处理函数

      handleExceed(files, fileList) {   // 超出个数限制
            this.$message.warning(`当前选择1个文件`);
          },
          beforeUpload(file) {      // 上传文件之前
            // 是否是 xlsx 文件(2003)
            const isXlsx = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            // 是否是 xls 文件(2010)
            const isXls = file.type === 'application/vnd.ms-excel'
            const isLt2M = file.size / 1024 / 1024 < 2;
      ​
            if (!isXlsx && !isXls) {
              this.$message.error('上传文件不是excel文件!');
            }
            if (!isLt2M) {
              this.$message.error('上传文件大小不能超过 2MB!');
            }
            return (isXlsx || isXls) && isLt2M;
          },
          handleRemove(file, fileList) {  // 文件列表移除文件
            console.log(file, fileList);
          },
          handleSuccess(response, file, fileList) { // 文件上传成功
            // 成功提示
            this.$message.success(response.message)
            // 刷新
            this.findAllSubject()
          }

    2.3.2 前端:完整版

    2.3.4 后端

    1) 完善JavaBean

    package com.czxy.zx.domain;
    ​
    import com.baomidou.mybatisplus.annotation.*;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import lombok.Data;
    import org.springframework.format.annotation.DateTimeFormat;
    ​
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    ​
    /**
     * 课程科目(EduSubject)表实体类
     *
     * @author 桐叔
     */
    @Data
    @TableName("edu_subject")
    public class EduSubject{
        @TableId(type = IdType.ASSIGN_UUID)
        //课程科目ID
        private String id;
        //科目名称
        private String title;
        //父ID
        private String parentId;
        //排序字段
        private Integer sort;
        //创建时间
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
        @TableField(fill = FieldFill.INSERT)
        private Date gmtCreate;
        //更新时间
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
        @TableField(fill = FieldFill.INSERT)
        private Date gmtModified;
    ​
        @TableField(exist = false)
        private List children = new ArrayList<>();
    ​
    }

    2)填充数据处理类

     

    package com.czxy.zx.course.handler;
    ​
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    ​
    import java.util.Date;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     */
    @Component
    public class SubjectMetaObjectHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            // 创建时间
            this.setFieldValByName("gmtCreate",new Date(), metaObject);
            // 修改时间
            this.setFieldValByName("gmtModified",new Date() , metaObject);
        }
    ​
        @Override
        public void updateFill(MetaObject metaObject) {
            // 修改时,填充的内容
            this.setFieldValByName("gmtModified",new Date() , metaObject);
        }
    }
    ​

    3)service:通过title查询

     

    • 接口

      package com.czxy.zx.course.service;
      ​
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.czxy.zx.domain.EduSubject;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      public interface EduSubjectService extends IService {
          /**
           * 通过title查询
           * @param title
           * @return
           */
          EduSubject findByTitle(String title);
      }
      ​

    • 实现类

      package com.czxy.zx.course.service.impl;
      ​
      import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.czxy.zx.course.mapper.EduSubjectMapper;
      import com.czxy.zx.course.service.EduSubjectService;
      import com.czxy.zx.domain.EduSubject;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      @Service
      @Transactional
      public class EduSubjectServiceImpl extends ServiceImpl implements EduSubjectService {
          @Override
          public EduSubject findByTitle(String title) {
              QueryWrapper queryWrapper = new QueryWrapper();
              queryWrapper.eq("title", title);
      ​
              EduSubject eduSubject = baseMapper.selectOne(queryWrapper);
              return eduSubject;
          }
      }
      ​

    4)controller:上传

     /**
         * 文件上传
         * @param file
         * @return
         */
        @PostMapping("/upload")
        public BaseResult upload(MultipartFile file) {
            try {
                // 解析excel
                EasyExcel.read(file.getInputStream(), UploadSubjectVo.class, eduSubjectListener).sheet(0).doRead();
    ​
                return BaseResult.ok("上传成功");
            } catch (IOException e) {
                return BaseResult.error("上传失败");
            }
        }

    5)excel内容封装类

    package com.czxy.zx.course.upload;
    ​
    import com.alibaba.excel.annotation.ExcelProperty;
    import lombok.Data;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     */
    @Data
    public class UploadSubjectVo {
    ​
        @ExcelProperty("一级分类")
        private String oneLevel;
    ​
        @ExcelProperty("二级分类")
        private String twoLevel;
    ​
    ​
    }
    ​

    6)上传内容处理类

     

     

    package com.czxy.zx.course.upload;
    ​
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    import com.czxy.zx.course.service.EduSubjectService;
    import com.czxy.zx.domain.EduSubject;
    import org.springframework.stereotype.Component;
    ​
    import javax.annotation.Resource;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     */
    @Component
    public class EduSubjectListener extends AnalysisEventListener {
    ​
        @Resource
        private EduSubjectService eduSubjectService;
    ​
        @Override
        public void invoke(UploadSubjectVo uploadSubjectVo, AnalysisContext analysisContext) {
            // 1. 处理一级
            // 1.1 查询一级
            EduSubject oneSubject = eduSubjectService.findByTitle(uploadSubjectVo.getOneLevel());
            // 1.2 保存一级
            if(oneSubject == null) {
                oneSubject = new EduSubject();
                oneSubject.setTitle(uploadSubjectVo.getOneLevel());
                oneSubject.setSort(0);
                oneSubject.setParentId("0");        // 一级默认0
                eduSubjectService.save(oneSubject);
            }
    ​
            // 2. 处理二级
            // 2.1 查询二级
            EduSubject twoSubject = eduSubjectService.findByTitle(uploadSubjectVo.getTwoLevel());
            // 2.2 保存二级
            if(twoSubject == null) {
                twoSubject = new EduSubject();
                twoSubject.setTitle(uploadSubjectVo.getTwoLevel());
                twoSubject.setSort(0);
                twoSubject.setParentId(oneSubject.getId()); //二级的父ID为一级的ID
                eduSubjectService.save(twoSubject);
            }
    ​
        }
    ​
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    ​
        }
    }
    ​
  • 相关阅读:
    【AQS】概述、执行流程、体系架构、深⼊源码解读(加锁,解锁)、源码总结_JUC20
    基于springboot+vue.js+uniapp的房屋租赁系统附带文章源码部署视频讲解等
    vue移动端适配
    Hadoop3教程(十六):MapReduce中的OutputFormat
    210. 课程表 II(leetcode210,ArrayList类型的数组创建,拓扑排序)-------------------Java实现
    献给Nacos小白的一篇好文:集群环境搭建
    快解析助力解决局域网打印难题
    Python项目实战 - 简易计算器
    解密Prompt系列18. LLM Agent之只有智能体的世界
    太顶了,腾讯 T4 资深架构师梳理的 Java 核心宝典(框架 + 原理 + 笔记)
  • 原文地址:https://blog.csdn.net/weixin_45481821/article/details/126691180