尚硅谷_谷粒学苑-微服务+全栈在线教育实战项目(主后端部分)(待补充)

项目地址:尚硅谷_谷粒学苑-微服务+全栈在线教育实战项目

一、项目简介

(一)功能介绍

b2c模式

系统后台(管理员使用):

1、讲师管理模块

2、课程分类管理模块

3、课程管理模块

(1)视频

4、统计分析模块

5、订单管理

6、banner管理

7、权限管理

系统前台(普通用户使用):

1、首页数据显示

2、讲师列表和详情

3、课程列表和课程详情

(1)视频在线播放

4、登录和注册功能

5、微信扫码登录

6、微信扫码支付

(二)技术点介绍

后端技术

springboot、springcloud、MybatisPlus、spring security、redis、maven、easyExcel、jwt、OAuth2

前端技术:

vue +element-ui + axios + node.js

其他技术:

阿里云oss、阿里云视频点播服务、阿里云短信服务

微信支付和登录、docker、git、Jenkins

二、数据库设计

三、搭建项目工程

(一)父工程

在这里插入图片描述

1. 配置pom.xml

(1)修改版本
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/>
</parent>
(2)增加pom类型

在后面增加pom类型

<groupId>com.qzy</groupId>
<artifactId>guli_parent</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>guli_parent</name>
(3)添加依赖版本

删除pom.xml中的内容,之后添加 确定依赖的版本

<properties>
    <java.version>1.8</java.version>
    <guli.version>0.0.1-SNAPSHOT</guli.version>
    <mybatis-plus.version>3.0.5</mybatis-plus.version>
    <velocity.version>2.0</velocity.version>
    <swagger.version>2.7.0</swagger.version>
    <aliyun.oss.version>2.8.3</aliyun.oss.version>
    <jodatime.version>2.10.1</jodatime.version>
    <poi.version>3.17</poi.version>
    <commons-fileupload.version>1.3.1</commons-fileupload.version>
    <commons-io.version>2.6</commons-io.version>
    <httpclient.version>4.5.1</httpclient.version>
    <jwt.version>0.7.0</jwt.version>
    <aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
    <aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
    <aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
    <aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
    <aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
    <fastjson.version>1.2.28</fastjson.version>
    <gson.version>2.8.2</gson.version>
    <json.version>20170516</json.version>
    <commons-dbutils.version>1.7</commons-dbutils.version>
    <canal.client.version>1.1.0</canal.client.version>
    <docker.image.prefix>zx</docker.image.prefix>
    <cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
</properties>

配置锁定依赖的版本

<dependencyManagement>
    <dependencies>
        <!--Spring Cloud-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--mybatis-plus 持久层-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!--swagger ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!--aliyunOSS-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>${aliyun.oss.version}</version>
        </dependency>
        <!--日期时间工具-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>${jodatime.version}</version>
        </dependency>
        <!--xls-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <!--xlsx-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <!--文件上传-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${commons-fileupload.version}</version>
        </dependency>
        <!--commons-io-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <!--httpclient-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${httpclient.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>${gson.version}</version>
        </dependency>
        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        <!--aliyun-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>${aliyun-java-sdk-core.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>${aliyun-sdk-oss.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-vod</artifactId>
            <version>${aliyun-java-sdk-vod.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-vod-upload</artifactId>
            <version>${aliyun-java-vod-upload.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-sdk-vod-upload</artifactId>
            <version>${aliyun-sdk-vod-upload.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>${json.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>${commons-dbutils.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.otter</groupId>
            <artifactId>canal.client</artifactId>
            <version>${canal.client.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

(二)搭建service模块

1. 创建service模块

在父工程下面创建Module模块,选择maven类型

在这里插入图片描述

2. 配置pom.xml

2.1 增加pom类型

在后面增加pom类型

<artifactId>service</artifactId>
<packaging>pom</packaging>
2.2 添加项目需要的依赖
<dependencies>
    <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>-->
    <!--hystrix依赖,主要是用  @HystrixCommand -->
    <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>-->
    <!--服务注册-->
    <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>-->
    <!--服务调用-->
    <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>-->

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
    </dependency>
    <!--swagger-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </dependency>
    <!--lombok用来简化实体类:需要安装lombok插件-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--xls-->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
    </dependency>
    <!--httpclient-->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>
    <!--commons-io-->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
    </dependency>
    <!--gson-->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

四、讲师管理模块配置

(一) 创建service_edu模块

在service下面创建Module模块,选择maven类型

1. 配置文件application.properties

# 服务端口
server.port=8001

# 服务名
spring.application.name=service-edu

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

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

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2. 配置代码生成器

在这里插入图片描述

运行后:

在这里插入图片描述

(二)编写后台管理api接口

1. controller代码

package com.qzy.eduservice.controller;

import com.qzy.eduservice.entity.EduTeacher;
import com.qzy.eduservice.service.EduTeacherService;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * 讲师 前端控制器
 * @author testjava
 * @since 2022-06-15
 */
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

    @GetMapping("findAll")
    public List<EduTeacher> findAllTeacher() {
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }
}

2. springboot配置类

package com.qzy.eduservice.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.qzy.eduservice.mapper")
public class EduConfig {
}

3. springboot启动类

package com.qzy.eduservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class EduApplication {
    public static void main(String[] args) {
        SpringApplication.run(EduApplication.class, args);
    }
}

在这里插入图片描述

(三)讲师逻辑删除功能

1. 配置逻辑删除插件

在EduConfig中配置

/**
 * 逻辑删除插件
 */
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

2. 属性上添加注解@TableLogic

@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
@TableLogic
private Boolean isDeleted;

(四)配置swagger2

1. 创建common模块

(1)在service同目录下创建common模块,做为公共模块

(2)在common的xml中导入依赖

记得增加pom

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <scope>provided </scope>
    </dependency>

    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <scope>provided </scope>
    </dependency>

    <!--lombok用来简化实体类:需要安装lombok插件-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided </scope>
    </dependency>

    <!--swagger-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <scope>provided </scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <scope>provided </scope>
    </dependency>

    <!-- redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- spring2.X集成redis所需common-pool2
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>-->
</dependencies>

(3)在common中创建service_base模块

2. 在service_base中,创建swagger配置类

创建包com.qzy.servicebase.config,创建类SwaggerConfig

package com.qzy.servicebase;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration //配置类
@EnableSwagger2 //swigger注解
public class SwiggerConfig {
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.not(PathSelectors.regex("/admin/.*")))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();

    }

    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                .title("网站-课程中心API文档")
                .description("本文档描述了课程中心微服务接口定义")
                .version("1.0")
                .contact(new Contact("清蒸鱼", "http://atguigu.com", "482364541@qq.com"))
                .build();
    }
}

3. 在service中引入相关依赖

<dependency>
    <groupId>com.qzy</groupId>
    <artifactId>service_base</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

4. 在service_edu的启动类中添加注解

@ComponentScan(basePackages = {"com.qzy"})

5. 访问地址

http://localhost:8001/swagger-ui.html

6. 定义接口说明和参数说明

定义在类上:@Api

定义在方法上:@ApiOperation

定义在参数上:@ApiParam


@Api(description="讲师管理")
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

    //查询所有讲师
    @ApiOperation(value = "所有讲师列表")
    @GetMapping("findAll")
    public List<EduTeacher> findAllTeacher() {
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }

    //逻辑删除讲师
    @ApiOperation(value = "根据ID逻辑删除讲师")
    @DeleteMapping("{id}")
    public boolean removeTeacher(
            @ApiParam(name = "id", value = "讲师ID", required = true)
            @PathVariable String id) {
        boolean flag = eduTeacherService.removeById(id);
        return flag;
    }
}

在这里插入图片描述

(五)统一返回结果对象

1. 创建模块

在公共模块common下面创建模块common_utils

2. 编写统一返回结果对象

(1)编写interface

定义数据返回状态码

package com.qzy.commonutils;

public interface ResultCode {
    public static Integer SUCCESS = 20000; //成功
    public static Integer ERROR = 20001; //失败
}
(2)定义返回数据格式
package com.qzy.commonutils;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

//统一返回结果的类
@Data
public class R {

    @ApiModelProperty(value = "是否成功")
    private Boolean success;

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();

    private R(){} //构造方法私有化,别人不能直接new

    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    public R success(boolean success) {
        this.setSuccess(success);
        return this;
    }
    public R code(Integer code) {
        this.setCode(code);
        return this; 
    }
    public R message(String message) {
        this.setMessage(message);
        return this;
    }
    public R data(String key, Object value) {
        this.data.put(key,value);
        return this; //返回对象,之后可以采用链式编程,R.ok().data(...)
    }
    public R data(Map<String, Object> map) {
        this.setData(map);
        return this;
    }

}

3. 引入依赖

在service中引入该依赖

<dependency>
    <groupId>com.qzy</groupId>
    <artifactId>common_utils</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

4. 使用

//查询所有讲师
@ApiOperation(value = "所有讲师列表")
@GetMapping("findAll")
public R findAllTeacher() {
    List<EduTeacher> list = eduTeacherService.list(null);
    return R.ok().data("items", list);
}

//逻辑删除讲师
@ApiOperation(value = "根据ID逻辑删除讲师")
@DeleteMapping("{id}")
public R removeTeacher(
    @ApiParam(name = "id", value = "讲师ID", required = true)
    @PathVariable String id) {
    boolean flag = eduTeacherService.removeById(id);
    if(flag) {
        return R.ok();
    }else {
        return R.error();
    }
}

五、讲师管理模块功能

(一)分页功能

1. 配置分页插件

/**
     * 分页插件
     */
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

2. 编写讲师分页接口方法

//分页查询讲师
@ApiOperation(value = "分页查询讲师")
@GetMapping("pageTeacher/{page}/{limit}")
public R pageTeacher(
    @ApiParam(name = "page", value = "当前页码", required = true)
    @PathVariable Long page,
    @ApiParam(name = "limit", value = "每页记录数", required = true)
    @PathVariable Long limit) {

    Page<EduTeacher> teacherPage = new Page<>(page, limit);
    eduTeacherService.page(teacherPage, null);
    long total = teacherPage.getTotal();
    List<EduTeacher> records = teacherPage.getRecords();

    //方法1
    //return R.ok().data("total", total).data("rows", records);

    //方法2
    Map map = new HashMap();
    map.put("total", total);
    map.put("rows", records);
    return R.ok().data(map);
}

3. swagger中测试

(二)条件查询带分页功能

1. 把条件值传递到接口里面

把条件值封装到对象(vo)里,把对象传递到接口里面。

package com.qzy.eduservice.entity.vo;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
public class TeacherQuery {

    @ApiModelProperty(value = "教师名称,模糊查询")
    private String name;

    @ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
    private Integer level;

    @ApiModelProperty(value = "查询开始时间", example = "2022-01-01 10:10:10")
    private String begin; //注意,这里使用的是String类型,前端传过来的数据无需进行类型转换

    @ApiModelProperty(value = "查询结束时间", example = "2022-12-01 10:10:10")
    private String end;
}

2. 根据条件值进行判断,拼接条件

RequestBody:使用json传递数据,把json数据封装到对应对象里面(需要使用post提交方式)

ResponseBody:返回数据,返回json数据

@RequestBody(required = false) //参数值可以为空
//4. 条件查询带分页的方法
@ApiOperation(value = "带条件分页查询讲师")
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(
    @ApiParam(name = "current", value = "当前页码", required = true)
    @PathVariable long current,
    @ApiParam(name = "limit", value = "每页记录数", required = true)
    @PathVariable long limit,
    @ApiParam(name = "teacherQuery", value = "查询对象", required = false)
    @RequestBody TeacherQuery teacherQuery) {
    //1. 创建page对象
    Page<EduTeacher> pageTeacher = new Page<>(current, limit);
    //2. 构建条件
    QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
    //2.1 多条件组合查询
    String name = teacherQuery.getName();
    Integer level = teacherQuery.getLevel();
    String begin = teacherQuery.getBegin();
    String end = teacherQuery.getEnd();
    //2.2 判断条件值是否为空
    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);
    }
    //3. 调用方法实现条件查询分页
    eduTeacherService.page(pageTeacher, wrapper);

    List<EduTeacher> records = pageTeacher.getRecords();
    long total = pageTeacher.getTotal();
    return R.ok().data("total", total).data("rows", records);
}

(三)添加讲师

1. 增加注解

@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

2. 编写处理器来处理这个注解

common->service_base->src->main->java->com.qzy.servicebase->handle.MyMetaObjectHandler

详细步骤见mybatis-plus笔记中的自动填充部分

@Component
public class MyMetaObjectHandler 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. 编写controller

//5. 添加讲师
@ApiOperation(value = "添加讲师")
@PostMapping("addTeacher")
public R addTeacher(
    @ApiParam(name = "eduTeacher", value = "讲师对象", required = true)
    @RequestBody EduTeacher eduTeacher) {
    boolean save = eduTeacherService.save(eduTeacher);
    return save?R.ok():R.error();
}

(三)修改讲师

1. 根据讲师id进行查询

//6. 根据讲师id查询
@ApiOperation(value = "根据id查询讲师")
@GetMapping("getTeacher/{id}")
public R getTeacher(
    @ApiParam(name = "id", value = "讲师ID", required = true)
    @PathVariable String id) {
    EduTeacher teacher = eduTeacherService.getById(id);
    return R.ok().data("teacher", teacher);
}

2. 修改讲师

//7. 修改讲师
@PostMapping("updateTeacher")
public R updateTeacher(
    @ApiParam(name = "eduTeacher", value = "讲师对象", required = true)
    @RequestBody EduTeacher eduTeacher) {
    boolean update = eduTeacherService.updateById(eduTeacher);
    return update?R.ok():R.error();
}

(四)统一异常处理

1. 全局异常处理

在service_base中创建统一异常处理类

package com.qzy.servicebase.exceptionhandler;
/**
 * 统一异常处理类
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody //为了返回数据
    public R error(Exception e) {
        e.printStackTrace();
        return R.error().message("执行了全局异常处理...");
    }
}

2. 特定异常处理

(项目开发中用得不是特别多,因为无法提前预知是什么错误)

//指定特定异常
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e) {
    e.printStackTrace();
    return R.error().message("执行了ArithmeticException异常处理...");
}

3. 自定义异常处理

3.1 创建自定义异常类继承RuntimeException
@Data
@AllArgsConstructor //生成有参构造方法
@NoArgsConstructor//生成无参构造方法
public class QzyException extends RuntimeException {
    private Integer code;//状态码
    private String msg;//异常信息
}
3.2 在统一异常类添加规则
//自定义特定异常
@ExceptionHandler(QzyException.class)
@ResponseBody //为了返回数据
public R error(QzyException e) {
    e.printStackTrace();
    return R.error().code(e.getCode()).message(e.getMsg());
}
3.3 执行自定义异常
try{
    int i = 10/0;
}catch (Exception e) {
    throw new QzyException(20001,"执行了自定义异常");
}

4. 统一日志处理

4.1 日志级别

级别:ERROR、WARN、INFO、DEBUG

#设置日志级别
logging.level.root=WARN

把日志不仅输出到控制台,也可以输出到文件中,使用日志工具log4j或者Logback

4.2 Logback日志工具
4.2.1 删除appication.properties中的日志配置
#设置日志级别
#logging.level.root=INFO
#mybatis日志
#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4.2.2 创建logback-spring.xml

安装idea彩色日志插件:grep-console
resources中创建logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设
置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值
为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认
单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查
看logback运行状态。默认值为false。 -->
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入
    到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="D:/guli_log/edu" />
    <!-- 彩色日志 -->
    <!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level)
|%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或
        等于此级别的日志信息-->
        <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日
        志,也不会被输出 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level>
        </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
        <!-- 设置字符集 -->
        <charset>UTF-8</charset>
    </encoder>
    </appender>
    <!--输出到文件-->
    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level
            %logger{50} - %msg%n</pattern> <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM�dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM�dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
        	</timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM�dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--
    <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。<logger>仅有一个name属性,一个可选的level和一个可选的addtivity属性。
    name:用来指定受此logger约束的某一个包或者具体的某一个类。
    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和 OFF,如果未设置此属性,那么当前logger将会继承上级的级别。
    -->
    <!--
    使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想
    要查看sql语句的话,有以下两种操作:
    第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过
    2、将错误日志输出到文件
    GlobalExceptionHandler.java 中
    类上添加注解
    异常输出语句
    这样日志那边会出现很多其他消息
    第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打
    印,其他还是正常DEBUG级别:
    -->
    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <!--可以输出项目中的debug日志,包括mybatis的sql日志-->
        <logger name="com.guli" level="INFO" />
        <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR,
        ALL 和 OFF,默认是DEBUG
        可以包含零个或多个appender元素。
        -->
        <root level="INFO"> <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>
    <!--生产环境:输出到文件-->
    <springProfile name="pro"> <root level="INFO"> <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="ERROR_FILE" />
        <appender-ref ref="WARN_FILE" />
    </root>
    </springProfile>
</configuration>
4.2.3 把异常信息输出到文件中
(1)添加注解@Slf4j
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {}
(2)输出信息
@ExceptionHandler(QzyException.class)
@ResponseBody 
public R error(QzyException e) {
    log.error(e.getMsg()); //输出
    e.printStackTrace();
    return R.error().code(e.getCode()).message(e.getMsg());
}
(3)将日志堆栈信息输出到文件(即详细异常信息)

定义工具类
guli-framework-common下创建util包,创建ExceptionUtil.java工具类

public class ExceptionUtil {
    public static String getMessage(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 将出错的栈信息输出到printWriter中
            e.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }
}

调用:

//log.error(e.getMsg());
log.error(ExceptionUtil.getMessage(e));

QzyException中创建toString方法:

@Override
public String toString() {
    return "QzyException{" +
        "code=" + code +
        ", msg='" + this.getMsg() + '\'' +
        '}';
}

(五)上传讲师头像(阿里云OSS)

1. 创建service_oss模块

在这里插入图片描述

1.1 引入依赖
<dependencies>
     <!-- 阿里云oss依赖 -->
     <dependency>
         <groupId>com.aliyun.oss</groupId>
         <artifactId>aliyun-sdk-oss</artifactId>
     </dependency>

     <!-- 日期工具栏依赖 -->
     <dependency>
         <groupId>joda-time</groupId>
         <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>
1.2 配置文件
#服务端口
server.port=8002
#服务名
spring.application.name=service-oss

#环境设置:dev、test、prod
spring.profiles.active=dev

#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=
aliyun.oss.file.keyid=
aliyun.oss.file.keysecret=
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=edu-qzy

2. 读取配置文件

package com.qzy.serviceOss.utils;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//实现InitializingBean 
@Component
public class ConstantPropertiesUtils implements InitializingBean {

	//使用属性注解 读取配置文件的内容
    @Value("${aliyun.oss.file.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.file.keyid}")
    private String keyId;

    @Value("${aliyun.oss.file.keysecret}")
    private String keySecret;

    @Value("${aliyun.oss.file.bucketname}")
    private String bucketName;

	//公开静态常量
    public static String END_POINT;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String BUCKET_NAME;

    @Override
    public void afterPropertiesSet() throws Exception {
        END_POINT = endpoint;
        KEY_ID = keyId;
        KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}

3.创建controller/service,实现图像上传

controller

@RestController
@RequestMapping("/eduoss/fileoss")
@CrossOrigin
public class OssController {

    @Autowired
    private OssService ossService;

    //上传头像的方法
    @PostMapping
    public R ossUploadFile(MultipartFile file) {
        //返回上传到oss的路径
        String url = ossService.uploadFileAvatar(file);
        return R.ok().data("url", url);
    }
}

service

package com.qzy.serviceOss.service.impl;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.qzy.serviceOss.service.OssService;
import com.qzy.serviceOss.utils.ConstantPropertiesUtils;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

@Service
public class OssServiceImpl implements OssService {

    //上传头像到oss
    @Override
    public String uploadFileAvatar(MultipartFile file) {

        String endpoint = ConstantPropertiesUtils.END_POINT;
        String accessKeyId = ConstantPropertiesUtils.KEY_ID;
        String accessKeySecret = ConstantPropertiesUtils.KEY_SECRET;
        String bucketName = ConstantPropertiesUtils.BUCKET_NAME;

        try {
            //创建OSSClient实例
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            //上传文件流
            InputStream inputStream = file.getInputStream();

            //获取文件名
            String fileName = file.getOriginalFilename();
            //在文件名称中添加随机唯一的值
            //生成ssaf-afe-sar,去掉 ”-“
            String uuid = UUID.randomUUID().toString().replace("-", "");
            fileName = uuid + fileName;

            //把文件按照日期进行分类
            // 2020/12/1/
            String datePath = new DateTime().toString("yyyy/MM/dd");
            fileName = datePath + "/" + fileName;

            //调用oss实现上传
            ossClient.putObject(bucketName, fileName, inputStream);
            //关闭OSSClient
            ossClient.shutdown();

            //把上传之后的文件路径返回
            //路径 https://edu-qzy.oss-cn-beijing.aliyuncs.com/1.jpg
            String url = "https://" + bucketName + "." + endpoint + "/" + fileName;
            return url;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }
}

(六)Nginx安装和配置

作用:请求转发、负载均衡、动静分离

使用cmd启动nginx,直接关闭cmd窗口nginx不会停止,需手动停止
启动:nginx.exe
关闭:nginx.exe -s stop

1. 配置nginx,实现请求转发功能

D:\Software\nginx-1.23.3\conf目录中的nginx.conf

1.1 修改nginx默认端口
#修改默认端口 把80改成81
   server {
       listen       81;
       server_name  localhost;
1.2 配置nginx转发规则
server {
	listen       9001; #监听端口
	server_name	 localhost; #主机

	location ~ /eduservice/ { #匹配路径
		proxy_pass http://localhost:8001;#转发服务器地址
	}

	location ~ /eduoss/ { 
		proxy_pass http://localhost:8002;
	}
}
1.3 前端配置

在config文件夹中的dev.env.js文件进行修改地址

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  BASE_API: '"http://localhost:9001"',
})

(七)EasyExcel读写操作

1. 引入依赖

 <!-- 子工程xml -->
 <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>easyexcel</artifactId>
     <version>2.2.10</version>
 </dependency>
  <!-- 父工程xml 3.17版本 -->
  <!--xls-->
  <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>${poi.version}</version>
  </dependency>
  <!--xlsx-->
  <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>${poi.version}</version>
  </dependency>

2. 创建实体类与excel对应

//设置表头名称: @ExcelProperty("一级分类")
@Data
public class SubjectData {

    @ExcelProperty(value = "一级分类", index = 0)
    private String oneSubjectName;

    @ExcelProperty(value = "一级分类", index = 1)
    private String twoSubjectName;
}

3. 实现写入操作

例子:
实体类

@Data
public class Student {
    @ExcelProperty("学号")
    private Integer stuNo;

    @ExcelProperty("学生名称")
    private String stuName;
}

调用:

public class StudentExcelTest {
    public static void main(String[] args) {
        //实现excel写入操作
        String fileName = "D:\\学生列表.xlsx";
        //调用easyExcel里面的方法实现写入操作
        EasyExcel.write(fileName, Student.class).sheet("学生列表").doWrite(getData());
    }

    private static List getData() {
        List<Student> stuList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Student stu = new Student();
            stu.setStuNo(i);
            stu.setStuName("名字" + i);
            stuList.add(stu);
        }
        return stuList;
    }
}

报错:

Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:exec (default-cli) on project…

解决:pom.xml增加以下代码

 <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <classpathScope>test</classpathScope>
                </configuration>
            </plugin>
        </plugins>
    </build>

4. 实现读取操作

1. 创建读取监听器

继承AnalysisEventListener

public class ExcelListener extends AnalysisEventListener<Student> {
    //一行一行读取
    @Override
    public void invoke(Student student, AnalysisContext analysisContext) {
        System.out.println("***" + student);
    }

    //读取表头
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头:" + headMap);
    }

    //读取后操作
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}
2. 读取excel
 //实现读取操作
 EasyExcel.read(fileName, Student.class, new ExcelListener()).sheet().doRead();

控制台输出时中文乱码:设置JVM参数为-Dfile.encoding=UTF-8

5. 实现功能

5.1 编写controller
 //添加课程分类
 //获取上传过来的文件,把文件内容读取出来
 @PostMapping("addSubject")
 public R addSubject(MultipartFile file) {
     //上传过来excel文件
     subjectService.addSubject(file, subjectService);
     return R.ok();
 }
5.2 编写service实现
 //添加课程分类
  @Override
  public void addSubject(MultipartFile file, EduSubjectService subjectService) {
      try{
          //文件输入流
          InputStream in = file.getInputStream();
          //调用方法进行读取
          EasyExcel.read(in, SubjectData.class, new SubjectExcelListener(subjectService)).sheet().doRead();
      }catch (Exception e) {
          e.printStackTrace();
      }
  }
5.3 编写监听器
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

    //因为SubjectExcelListener不能交给spring进行管理,需要自己new,不能注入其他对象
    //因此需要用有参构造手动将subjectService传过来
    public EduSubjectService subjectService;
    public SubjectExcelListener() { }
    public SubjectExcelListener(EduSubjectService subjectService) {
        this.subjectService = subjectService;
    }

    //一行一行读取excel内容
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if(subjectData == null) {
            throw new QzyException(20001, "文件数据为空");
        }
        //一行一行读取,每次读取有两个值,第一个为一级分类,第二个为二级分类
        //添加一级分类
        //判断一级分类是否重复
        EduSubject existOneSubject = this.existOneSubject(subjectData.getOneSubjectName());
        if(existOneSubject == null) {//没有重复,进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0");
            existOneSubject.setTitle(subjectData.getOneSubjectName());
            subjectService.save(existOneSubject);
        }

        //添加二级分类
        String pid = existOneSubject.getId();
        EduSubject existTwoSubject = this.existTwoSubject(subjectData.getTwoSubjectName(), pid);
        if(existTwoSubject == null) {
            existTwoSubject = new EduSubject();
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());
            existTwoSubject.setParentId(pid);
            subjectService.save(existTwoSubject);
        }
    }

    //一级分类不能重复添加
    private EduSubject existOneSubject(String name) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", "0");
        EduSubject oneSubject = subjectService.getOne(wrapper);
        return oneSubject;
    }

    //二级分类不能重复添加
    private EduSubject existTwoSubject(String name, String pid) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", pid);
        EduSubject twoSubject = subjectService.getOne(wrapper);
        return twoSubject;
    }

    //读取表头
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
    }

    //读取完成后
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值