谷粒学苑项目前置知识

谷粒学苑项目前置知识

项目分为三篇
谷粒学苑项目前置知识
谷粒学苑项目前台界面
谷粒学苑后台管理系统

资料链接:谷粒学苑 提取码:p6er

视频教程:
尚硅谷-谷粒学苑

前端代码:前端代码
后端代码:后端代码

  • 谷粒学苑项目前置知识
    • 一、项目环境搭建
    • 二、讲师管理模块后端
      • 1.整合 Swagger
      • 2.统一返回数据格式
      • 3.分页查询
      • 4.增加讲师
      • 5.修改讲师
      • 6.逻辑删除讲师
      • 7.全局统一异常处理
      • 8.自定义异常
      • 9.统一日志处理
    • 三、前端基础知识
      • 1.VSCode 安装和使用
      • 2.ECMAScript 6 简介
      • 3.ES6基本语法
      • 4.Vue基础
      • 5.axios
      • 6.element-ui
      • 7.node.js
      • 8.Npm 包管理
      • 9.babel
      • 10.模块化
      • 11.webpack

项目模块介绍:

谷粒学苑项目前置知识_第1张图片

项目技术点:

后端: SpringBoot,SpringCloud,MyBatisPlus,Spring SECURITY,redis,maven,easyExcel,jwt,OAuth2

前端: Vue,element-ui,axios,node.js

其他技术: 阿里云oss,阿里云视频点播服务,阿里云短信服务,微信支付和登录,docker,git,Jenkins


有关 MyBatis-Plus 的学习笔记:https://blog.csdn.net/aetawt/article/details/126105008

学习视频: BV1VP4y1c7j7


一、项目环境搭建

前后端分离概念:

谷粒学苑项目前置知识_第2张图片

准备数据库表:

谷粒学苑项目前置知识_第3张图片

完整项目工程结构总览 :

谷粒学苑项目前置知识_第4张图片

创建父工程

父工程删除 src 文件夹,只留下 pom 文件。

谷粒学苑项目前置知识_第5张图片

父工程依赖:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.1.RELEASEversion>
        <relativePath/> 
    parent>

    
    <groupId>com.atguigugroupId>
    <artifactId>guli_parentartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>guli_parentname>

    <packaging>pompackaging>

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

    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Hoxton.SR1version>
                <type>pomtype>
                <scope>importscope>
            dependency>

            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                <version>2.2.2.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>3.5.1version>
            dependency>

            
            

            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>${swagger.version}version>
            dependency>
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>${swagger.version}version>
            dependency>

            
            <dependency>
                <groupId>com.aliyun.ossgroupId>
                <artifactId>aliyun-sdk-ossartifactId>
                <version>${aliyun.oss.version}version>
            dependency>

            
            <dependency>
                <groupId>joda-timegroupId>
                <artifactId>joda-timeartifactId>
                <version>${jodatime.version}version>
            dependency>

            
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poiartifactId>
                <version>${poi.version}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-ooxmlartifactId>
                <version>${poi.version}version>
            dependency>

            
            <dependency>
                <groupId>commons-fileuploadgroupId>
                <artifactId>commons-fileuploadartifactId>
                <version>${commons-fileupload.version}version>
            dependency>

            
            <dependency>
                <groupId>commons-iogroupId>
                <artifactId>commons-ioartifactId>
                <version>${commons-io.version}version>
            dependency>

            
            <dependency>
                <groupId>org.apache.httpcomponentsgroupId>
                <artifactId>httpclientartifactId>
                <version>${httpclient.version}version>
            dependency>

            <dependency>
                <groupId>com.google.code.gsongroupId>
                <artifactId>gsonartifactId>
                <version>${gson.version}version>
            dependency>

            
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwtartifactId>
                <version>${jwt.version}version>
            dependency>

            
            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-sdk-coreartifactId>
                <version>${aliyun-java-sdk-core.version}version>
            dependency>

            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-sdk-vodartifactId>
                <version>${aliyun-java-sdk-vod.version}version>
            dependency>

            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-vod-uploadartifactId>
                <version>${aliyun-java-vod-upload.version}version>
            dependency>

            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-sdk-vod-uploadartifactId>
                <version>${aliyun-sdk-vod-upload.version}version>
            dependency>

            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>${fastjson.version}version>
            dependency>
            <dependency>
                <groupId>org.jsongroupId>
                <artifactId>jsonartifactId>
                <version>${json.version}version>
            dependency>

            <dependency>
                <groupId>commons-dbutilsgroupId>
                <artifactId>commons-dbutilsartifactId>
                <version>${commons-dbutils.version}version>
            dependency>

            <dependency>
                <groupId>com.alibaba.ottergroupId>
                <artifactId>canal.clientartifactId>
                <version>${canal.client.version}version>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

关于 aliyun-java-vod-upload 无法依赖爆红的原因:

由于 aliyun-java-vod-upload没有开源,所以不能直接在pom文件中直接引入依赖。

因此需要在官网下载 jar 包 :

下载链接

下载解压之后进入 lib 目录,进入 cmd 命令行

谷粒学苑项目前置知识_第6张图片

安装 jar 包:

mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-java-vod-upload -Dversion=1.4.14 -Dpackaging=jar -Dfile=aliyun-java-vod-upload-1.4.14.jar

谷粒学苑项目前置知识_第7张图片

第二种方法:

解压我的 maven 仓库,将 jar 包拷贝到你的仓库

链接:https://pan.baidu.com/s/1_RVsyZI8PlCI_paf0XOOVg
提取码:v4wf

创建 service 子模块 :

  1. 删除 src,只留下 pom 文件
  2. 由于还没有用到微服务,先将依赖注释掉,否则会报错

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>guli_parentartifactId>
        <groupId>com.atguigugroupId>
        <version>0.0.1-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>serviceartifactId>
    <packaging>pompackaging>
    <modules>
        <module>service_edumodule>
    modules>

    <dependencies>


        


        


        


        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>

        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>

        


        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poiartifactId>
        dependency>

        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
        dependency>

        <dependency>
            <groupId>commons-fileuploadgroupId>
            <artifactId>commons-fileuploadartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.httpcomponentsgroupId>
            <artifactId>httpclientartifactId>
        dependency>
        
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
        dependency>
        
        <dependency>
            <groupId>com.google.code.gsongroupId>
            <artifactId>gsonartifactId>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
    dependencies>
project>

创建 service_edu 子子模块

依旧遵循五步走:

  • 建 model
  • 改 pom
    • pom 使用 service 的 pom,无需在修改
  • 写 yaml/properties
  • 启动类
  • 业务类

建 model:

谷粒学苑项目前置知识_第8张图片

写 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.username=root
spring.datasource.password=1234

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

我使用的是 MyBatisplusX 插件自动生成的代码,并没有使用老师提供的代码生成器。

  1. 首先在插件商店里下载 MyBatisX 插件:

    ​ Setting – Plugins – 搜索MyBatisX — 重启 IDEA

  2. 谷粒学苑项目前置知识_第9张图片

  3. 谷粒学苑项目前置知识_第10张图片

  4. 谷粒学苑项目前置知识_第11张图片

启动类:

@SpringBootApplication
@MapperScan("com.atguigu.demo.mapper")
public class EduTeacherApplication {
    public static void main(String[] args) {
        SpringApplication.run(EduTeacherApplication.class,args);
    }
}

业务类:

@RestController
@RequestMapping("eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

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

测试:

谷粒学苑项目前置知识_第12张图片

修改返回数据的时间格式:

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

到此步基本的模块结构

谷粒学苑项目前置知识_第13张图片

二、讲师管理模块后端

1.整合 Swagger

Swagger 是什么?

前后端分离开发模式中,api 文档是最好的沟通方式。

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务

特点:

  • 及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)
  • 规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)
  • 一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)
  • 可测性 (直接在接口文档上进行测试,以方便理解业务)

在 guli_parent 下创建 common 子模块,在 common 模块下创建 service_base 子子模块,方便其他服务都能使用 Swagger

common 子模块pom 文件:

删除 src 文件夹,只留下 pom 文件

 <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
            <scope>provided scope>
        dependency>
        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

        
    dependencies>

创建 service_base 模块:

  • 注意父模块和路径关系
  • 不用修改 pom ,使用 父模块 common 的依赖即可

谷粒学苑项目前置知识_第14张图片

创建配置类 SwaggerConfig 配置 Swagger:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @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("Helen", "http://atguigu.com", "[email protected]"))
                .build();
    }
}

谷粒学苑项目前置知识_第15张图片

在 service 模块中引入 service_base 依赖,使 service 模块下的所有模块都能够使用 Swagger:

        <dependency>
            <groupId>com.atguigugroupId>
            <artifactId>service_baseartifactId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>

配置启动类的包扫描:

由于我们在 service_base 模块中创建了 Swagger 配置类,需要在 service_edu 的中扫描 这个配置类

谷粒学苑项目前置知识_第16张图片

谷粒学苑项目前置知识_第17张图片

为什么不直接配置 com.atguigu.servicebase 包名呢?

这是因为 主启动类在 com.atguigu.demo 包下,ComponentScan 会覆盖 SpringBootApplication 的包扫描,因此会冲突。只好扫描他们的公共包了~~

访问:

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

定义接口和参数说明:

  1. 定义在类上:@Api
  2. 定义在方法上:@ApiOperation
  3. 定义在参数上:@ApiParam

谷粒学苑项目前置知识_第18张图片

总结:

  • 使用 Swagger 测试接口更加的方便,并且会生成测试API文档。
  • 使用 Swagger 步骤:
    • 在公共模块中增加依赖
    • 编写配置类
    • 在使用Swagger的模块中引入公共模块
    • 配置 公共模块的包扫描

2.统一返回数据格式

项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。

一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含 状态码、返回消息、数据 这几部分内容

统一定义返回结果:

{
"success": 布尔, //响应是否成功
"code": 数字, //响应码
"message": 字符串, //返回消息
"data": HashMap //返回数据,放在键值对中
}

在 common 模块下创建子模块 common_utils ,并 定义返回状态码以及返回数据格式

返回状态码:

public interface ResultCode {
    public static Integer SUCCESS = 20000; // 成功
    public static Integer ERROR = 20001; // 失败

}

返回数据格式:

@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>();

    // 把 构造方法私有化的作用: 除本类外不允许 new 本类
    private R (){}

    // 成功的返回方法
    // 加上 static 可通过 类名. 的方式调用
    public static R ok(){
        R r = new R();
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        r.setSuccess(true);
        return  r;
    }

    // 失败的返回方法
    // 加上 static 可通过 类名. 的方式调用
    public static R error(){
        R r = new R();
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        r.setSuccess(false);
        return  r;
    }

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }

谁调用 this ,this 就代表谁~~~

private R (){} 已经将 类 私有化了,外部无法 new R() 这个对象,只能通过 R. 的方式去调用方法。因此 this 代表当前对象,也就是 R 对象

在 service_edu 模块中使用公共返回结果:

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

    @Autowired
    private EduTeacherService eduTeacherService;

    @ApiOperation("查询所有教师")
    @GetMapping("/findAll")
    public R findAll() {

        List<EduTeacher> list = eduTeacherService.list();
        return list.isEmpty() ? R.error() : R.ok().data("items", list);

    }

    // 逻辑删除
    @ApiOperation("逻辑删除教师")
    @DeleteMapping("{id}")
    public R removeTeacher(
            @ApiParam(name = "id", value = "讲师ID", required = true)
            @PathVariable Integer id) {

        boolean flag = eduTeacherService.removeById(id);
        return flag ? R.ok() : R.error();

    }
}

R.ok().data("items", list); : 这种叫做 链式调用,返回对象都一样

**common_utils 目录结构 : **

谷粒学苑项目前置知识_第19张图片

结果测试:

谷粒学苑项目前置知识_第20张图片

3.分页查询

在配置类里配置分页插件

@Configuration
public class MyConfig {

    // 开启分页功能
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor (){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor() ;
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return  interceptor ;
    }
}

controller 层编写业务:

current : 当前页

size : 每一页显示内容条数

    @ApiOperation("普通分页功能")
    @GetMapping("/pageTeacher/{current}/{size}")
    public R pageTeacher(
            @PathVariable long current,
            @PathVariable long size
    ){
        // 创建分页对象
        Page<EduTeacher> page = new Page<>(current, size);
        eduTeacherService.page(page);
        // 返回总页数 和 分页数据
        return R.ok().data("rows",page.getRecords()).data("total",page.getTotal());
    }

多条件组合查询带分页

谷粒学苑项目前置知识_第21张图片

比如前端的页面, 有四个查询条件,这四个查询条件任意组合进行查询。

一般的做法是将 前端的参数封装到一个vo对象中,然后将对象传到接口中

vo : 表示 View Object ,视图层对象,用于前端 --》 后端

DTO : 表示Data Transfer Object,数据传输对象,用于后端 – 》前端。

在 service_edu 模块中创建 vo 对象:

@Api("封装讲师查询条件对象")
@Data
public class TeacherQuery {
    private static final long serialVersionUID = 1L;

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

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

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

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

目录结构:

谷粒学苑项目前置知识_第22张图片

controller 层业务编写:

    @ApiOperation("多条件组合查询分页功能")
    @PostMapping("/pageQuery/{current}/{size}")
    public R pageQuery(
            @PathVariable(required = false) long current,
            @PathVariable(required = false) long size,
            @RequestBody(required = false) TeacherQuery teacherQuery
    ) {
        // 创建分页对象
        Page<EduTeacher> pageTeacher = new Page<>(current, size);
        QueryWrapper<EduTeacher> queryWrapper = new QueryWrapper<>();
        // 获取条件
        String name = teacherQuery.getName();
        Integer level = teacherQuery.getLevel();
        // begin ~ end 课程创建时间
        String begin = teacherQuery.getBegin();
        String end = teacherQuery.getEnd();

        // 使用 condition 组装条件
        // 这种链式调用,MyBatisPlus 会自动使用 and 连接 SQL 语句,如果想用 or 连接,使用 .or() 方法
        queryWrapper.like(StringUtils.isNotBlank(name), "name", name)
                .eq(level != null, "level", level)
                .ge(StringUtils.isNotBlank(begin), "gmt_create", begin)
                .le(StringUtils.isNotBlank(end), "gmt_create", end);


        eduTeacherService.page(pageTeacher, queryWrapper);
        // 返回总页数 和 分页数据
        return R.ok().data("rows", pageTeacher.getRecords()).data("total", pageTeacher.getTotal());
    }

required = false : 这个属性表示这个参数不是必须要传的

@RequestBody : 获取请求体中的数据,只有POST 请求才会请求体。

@ResponseBody 区别:

@ResponseBody 是 返回 JSON数据到前端

condition 参数介绍:

谷粒学苑项目前置知识_第23张图片

在 QueryWrapper 里面每一个方法都有 condition 参数,是一个 boolean 值,它表示是否使用后边的参数。

比如:

queryWrapper.like(StringUtils.isNotBlank(name), "name", "王")

  • 如果 StringUtils.isNotBlank(name)为 true :
    • SQL 语句: select * from table where name like ‘%王%’ ;
  • 如果 StringUtils.isNotBlank(name)为 false :
    • SQL 语句: select * from table ;

使用Swagger 测试:

谷粒学苑项目前置知识_第24张图片

4.增加讲师

首先将 gmt_create、gmt_modified 俩个字段设置自动填充

  • 在 EduTeacher实体类中 增加 @TableField 注解
  • 增加自动填充配置类

谷粒学苑项目前置知识_第25张图片

在 service_base 模块下,com.atguigu.servicebase 包下,创建 handler 包,创建 配置类 :

@Api("自动填充配置类")
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // fieldName : 是实体类的属性名,不是字段名
        this.strictInsertFill(metaObject,"gmtCreate", Date.class,new Date());
        this.strictInsertFill(metaObject,"gmtModified", Date.class,new Date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject,"gmtModified", Date.class,new Date());
    }
}

5.修改讲师

  • 根据 ID 进行查询【用于页面回显数据】
  • 根据 ID 修改讲师

根据ID查询:

    @ApiOperation("根据ID查询讲师")
    @GetMapping("/getTeacher/{id}")
    public R getTeacher(@PathVariable Long id){
        EduTeacher teacher = eduTeacherService.getById(id);

        return  teacher != null ? R.ok().data("teacher",teacher) : R.error().message("您查询的讲师不存在");
    }

根据 ID 修改 :

@ApiOperation("根据修改讲师")
    @PostMapping("/updateTeacher")
    public R updateTeacher( @RequestBody EduTeacher eduTeacher){

        return eduTeacherService.updateById(eduTeacher) ? R.ok() : R.error();
    }

测试时,gmt_create、gmt_modified 俩个字段不要写。

6.逻辑删除讲师

在逻辑删除字段 is_delete 属性上增加:@TableLogic 注解

谷粒学苑项目前置知识_第26张图片

根据 ID 删除讲师:

    // 逻辑删除
    @ApiOperation("逻辑删除教师")
    @DeleteMapping("{id}")
    public R removeTeacher(
            @ApiParam(name = "id", value = "讲师ID", required = true)
            @PathVariable String id) {

        boolean flag = eduTeacherService.removeById(id);
        return flag ? R.ok() : R.error();

    }

7.全局统一异常处理

com.atguigu.servicebase.handler 包下,创建 GlobalExceptionHandler 处理全局异常:

@ControllerAdvice // 增强 Controller
public class GlobalExceptionHandler{

    @ExceptionHandler({Exception.class})
    @ResponseBody  //相应到浏览器上
    public R handlerException(Exception e) {
        e.printStackTrace();
        return R.error().message("全局处理异常~~~");
    }
}

service_base 中引入 common_utils 依赖,在 service 中可以把 common_utils 依赖删除。

演示结果:

谷粒学苑项目前置知识_第27张图片

特定异常处理:

    @ApiOperation("特定异常处理~")
    @ExceptionHandler({ArithmeticException.class})
    @ResponseBody  //响应到浏览器上
    public R error(ArithmeticException e) {
        e.printStackTrace();
        return R.error().message("ArithmeticException异常处理~~~");
    }

8.自定义异常

  • 创建类自定义异常,继承 RunTimeException
  • 全局统一异常处理自定义的异常
  • 手动抛出自定义异常

自定义异常:

@Api("自定义异常~")
@Data
@AllArgsConstructor // 有参构造
@NoArgsConstructor // 无参构造
public class GuliException extends RuntimeException{

    // 状态码
    private Integer code ;
    // 错误信息
    private String msg ;
}

GlobalExceptionHandler 中处理自定义异常:

    @ApiOperation("处理自定义异常~~")
    @ExceptionHandler({GuliException.class})
    @ResponseBody  //响应到浏览器上
    public R error(GuliException e) {
        e.printStackTrace();
        return R.error().code(e.getCode()).message(e.getMsg());
    }

手动抛出异常:

由于是我们自定义的,系统不会抛出该异常,需要我们自己手动抛出 !

谷粒学苑项目前置知识_第28张图片

service_base 目录结构:

谷粒学苑项目前置知识_第29张图片

9.统一日志处理

日志记录器(Logger)的行为是分等级的。如下表所示:

分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

后边的日志输出包含前面等级的日志输出

默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别

LogBack 和 log4j 类似,会比 log4j 有一些优点:https://blog.csdn.net/caisini_vc/article/details/48551287

  • 删除 application 配置文件中的日志配置

image-20220806215534123

  • 在 resources 目录下创建 logback-spring.xml ,并配置

<configuration  scan="true" scanPeriod="10 seconds">
    
    
    
    

    <contextName>logbackcontextName>
    
    <property name="log.path" value="C:/18_gulixueyuan/log_info" />

    
    
    
    
    
    
    
    <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">
        
        
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFOlevel>
        filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}Pattern>
            
            <charset>UTF-8charset>
        encoder>
    appender>


    

    
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_info.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset>
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFOlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_warn.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warnlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>


    
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_error.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERRORlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    
    
    <springProfile name="dev">
        
        <logger name="com.guli" level="INFO" />

        
        <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>

自动生成的日志文件

谷粒学苑项目前置知识_第30张图片

将错误信息打印到日志中去:

  • 在全局处理异常的类 GlobalExceptionHandler 上 增加 @Slf4j 注解

谷粒学苑项目前置知识_第31张图片

  • 使用 log.error() 方法将错误信息打印到日志中去

谷粒学苑项目前置知识_第32张图片

测试结果:

image-20220806220818908

如果想有更多的错误信息,使用以下的工具类:

  • 在 common_utils 模块创建 ExceptionUtil 用来保存详细的错误信息
  • 写完记得刷新一下调用该模块的 pom 文件,更新一下。
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();
	}
}

测试结果:

谷粒学苑项目前置知识_第33张图片

三、前端基础知识

1.VSCode 安装和使用

下载地址:Documentation for Visual Studio Code

安装中文界面:

  • 首先安装中文插件:Chinese (Simplified) Language Pack for Visual Studio Code
  • 右下角弹出是否重启vs,点击“yes”
  • 有些机器重启后如果界面没有变化,则 点击 左边栏Manage -> Command Paletet…【Ctrl+Shift+p】
  • 在搜索框中输入“configure display language”,回车
  • 打开locale.json文件,修改文件下的属性 “locale”:“zh-cn”

安装常用插件:

谷粒学苑项目前置知识_第34张图片

2.ECMAScript 6 简介

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)

3.ES6基本语法

3.1 如何定义一个变量

在 JS 中使用 var 在 ES6 中使用 let

俩个的区别:

  • var 没有局部作用域,let 有局部作用域
  • var 可以定义多次,let 只能定义一次
<script>
    
    { // 代码块

        var a = 1;
        let b = 2;

    }

    console.log(a)
	// // Uncaught ReferenceError: b is not defined
	// b 没有被声明
    console.log(b) 


    var m = 2 ;
    var m = 3 ;

    let n = 4 ;
    let n = 5 ;

    console.log(m)
	//Uncaught SyntaxError: Identifier 'n' has already been declared 
	// n 变量已经被定义过了
    console.log(n) 
</script>

3.2 定义一个常量

const a = xxx ;

  • 定义常量必须有初始值
  • 常量只能赋一次值
    const name = "李四"
    name = "王五"
    // ncaught TypeError: Assignment to constant variable.
    console.log(name)

    const sex ; 
    // Uncaught SyntaxError: Missing initializer in const declaration
    console.log(sex)

3.3 数组结构赋值

<script>
    // 传统方式
    var a = 1, b = 2, c = 3;
    console.log(a, b, c)


    // ES6 方式
    let [x, y, z] = [1, 2, 3];
    console.log(x, y, z) // 1,2,3 
    
</script>

3.4 对象结构赋值

<script>
    // 定义对象
    let user = { "name": "张三", "age": 20 };

    // 传统方式
    let name1 = user.name;
    let age1 = user.age
    console.log(name1 + "————" + age1)


    // ES6 方式
	// {} 里面的属性必须都是 user 对象的属性
    let {name,age} = user 
    console.log(name + "------" + age)

</script>

3.5 模板字符串

模板字符串 : ``

  • 支持换行
  • 可以镶嵌 ${ JavaScript代码 }
  • 可以调用函数 : ${ function() }
<script>

    // 1.模板字符串实现换行
    let v1 = `hello,world !!
    我是模板字符串~`
    console.log(v1)

    // 2. 模板字符串可以使用 ${} ,放入 Javascript 代码
    let name = "李四"
    let age = 20 ;
    let v2 = `my name is ${name}, my age is ${age+1} next year`

    console.log(v2)


    // 3. ${} 调用函数
    function a() {
        return "hello"
    }

    let v3 = `${a()},jack`
    console.log(v3)
</script>

3.6 定义方法

<script>

    // 定义一个对象 p
    const p = {
        // 传统方式
        method1: function () {
            console.log("method1")
        },

        // ES6 方式
        method2() {

        }
    }

    // 调用
    p.method1()
    p.method2()

</script>

3.7 对象拓展运算符

作用:

  • 拷贝对象
  • 合并对象
<script>
    // 1. 拷贝对象
    const user = { "name": "zhangsan", "age": 20 }

    const user1 = { ...user }
    console.log(user1)


    // 2.合并对象
    const book = { "bookName": "活着", "id": 1 }
    const book1 = { "bookName": "苏格拉底的申辩", "price": 100 }
    const books = { ...book, ...book1 }
    console.log(books)

</script>

当对象中有重复属性时,后面的会把前面的覆盖掉

谷粒学苑项目前置知识_第35张图片

3.8 箭头函数

语法: 参数 => 函数体

如果有多个参数使用 () 括起来,用 , 分割

<script>
    // 传统方式
    let m1 = function (a) {
        return a
    }
    console.log(m1(1))

    // 箭头函数
    let m2 = a => a;
    console.log(m2(2));


    //  多个参数
    let m3 = function (a, b) {
        return a + b
    }
    console.log(m3(2, 2));

    // 传统方式
    let m4 = (a, b) => a + b
    console.log(m4(2, 3));
</script>

4.Vue基础

Vue是 动态构建用户界面的渐进式 JavaScript 框架

特点:

  1. 遵循 MVVM 模式
  2. 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发3. 它本身只关注 UI, 也可以引入其它第三方库开发项目

下载地址:安装 — Vue.js (vuejs.org)

谷粒学苑项目前置知识_第36张图片

使用开发版本可以使用 Vue 插件调试,插件直接在浏览器插件商店中搜索 Vue.js devtools 安装即可

谷粒学苑项目前置知识_第37张图片

4.1 Vue 入门

  • 引入 Vue.js 文件
  • 编写案例
<body>
    
    <script src="js/vue.js">script>
    
    <div id="app">
        <h1>{{message}}h1>
    div>

    <script>
        // 创建 Vue 实例对象
        new Vue({
            el: '#app',
            data: {
                message: 'hello,world!!'
            },
            // data的第二种写法
            // data() {
            //     return {
            //         message: 'hello,world!!'
            //     }
            // },
            
        })
    script>
body>

关于 Vue 的一些基础知识:

  • 想让Vue工作,就必须创建一个Vue实例 【new Vue()】,且要传入一个配置对象
  • 容器里的代码称为 【Vue模板】
  • 真实开发中只有一个Vue实例,并且会配合着组件一起使用;
  • el : 指明当前Vue实例为哪个容器服务,值通常为 css 选择器字符串。
    • 类选择器:el:'.xxxx'
    • ID 选择器: el:'#xxxx'
    • 标签选择器:el:'xxxx'
  • data : 用于存储数据,数据供 el 所指定的容器使用
    • data 的第二种写法,return 返回的是需要的数据

4.2 抽取 Vue 公共的代码片段

Vue 实例的编写大多都是固定的,将固定的代码抽取出来设置快捷方式。

文件 => 首选项 => 用户代码片段 => 新建全局代码片段/或文件夹代码片段:vue-html.code-snippets, 后缀名不能变

复制以下内容,快捷键就是: vuehtm

{
	"vue htm": {
		"scope": "html",
		"prefix": "vuehtml",
		"body": [
			"DOCTYPE html>",
			"",
			"",
			"<head>",
			"    ",
			"    ",
			"    ",
			"    <title>Documenttitle>",
			"head>",
			"",
			"<body>",
			"    
", "", " div>", "

你可能感兴趣的:(谷粒学苑项目,java,spring,cloud,spring,boot)