数据库设计

  • 创建数据库表(此处是为创表语句,插入数据见详细资料)
    ```sql #

    Structure for table “edu_chapter”

    #

CREATE TABLE edu_chapter ( id char(19) NOT NULL COMMENT ‘章节ID’, course_id char(19) NOT NULL COMMENT ‘课程ID’, title varchar(50) NOT NULL COMMENT ‘章节名称’, sort int(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘显示排序’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), KEY idx_course_id (course_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT=’课程’;

#

Structure for table “edu_comment”

#

CREATE TABLE edu_comment ( id char(19) NOT NULL COMMENT ‘讲师ID’, course_id varchar(19) NOT NULL DEFAULT ‘’ COMMENT ‘课程id’, teacher_id char(19) NOT NULL DEFAULT ‘’ COMMENT ‘讲师id’, member_id varchar(19) NOT NULL DEFAULT ‘’ COMMENT ‘会员id’, nickname varchar(50) DEFAULT NULL COMMENT ‘会员昵称’, avatar varchar(255) DEFAULT NULL COMMENT ‘会员头像’, content varchar(500) DEFAULT NULL COMMENT ‘评论内容’, is_deleted tinyint(1) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘逻辑删除 1(true)已删除, 0(false)未删除’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), KEY idx_course_id (course_id), KEY idx_teacher_id (teacher_id), KEY idx_member_id (member_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’评论’;

#

Structure for table “edu_course”

#

CREATE TABLE edu_course ( id char(19) NOT NULL COMMENT ‘课程ID’, teacher_id char(19) NOT NULL COMMENT ‘课程讲师ID’, subject_id char(19) NOT NULL COMMENT ‘课程专业ID’, subject_parent_id char(19) COMMENT ‘课程专业父级ID’, title varchar(50) NOT NULL COMMENT ‘课程标题’, price decimal(10,2) unsigned NOT NULL DEFAULT ‘0.00’ COMMENT ‘课程销售价格,设置为0则可免费观看’, lesson_num int(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘总课时’, cover varchar(255) CHARACTER SET utf8 NOT NULL COMMENT ‘课程封面图片路径’, buy_count bigint(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘销售数量’, view_count bigint(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘浏览数量’, version bigint(20) unsigned NOT NULL DEFAULT ‘1’ COMMENT ‘乐观锁’, status varchar(10) NOT NULL DEFAULT ‘Draft’ COMMENT ‘课程状态 Draft未发布 Normal已发布’, is_deleted tinyint(3) DEFAULT NULL COMMENT ‘逻辑删除 1(true)已删除, 0(false)未删除’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), KEY idx_title (title), KEY idx_subject_id (subject_id), KEY idx_teacher_id (teacher_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT=’课程’;

#

Structure for table “edu_course_collect”

#

CREATE TABLE edu_course_collect ( id char(19) NOT NULL COMMENT ‘收藏ID’, course_id char(19) NOT NULL COMMENT ‘课程讲师ID’, member_id char(19) NOT NULL DEFAULT ‘’ COMMENT ‘课程专业ID’, is_deleted tinyint(3) NOT NULL DEFAULT ‘0’ COMMENT ‘逻辑删除 1(true)已删除, 0(false)未删除’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT=’课程收藏’;

#

Structure for table “edu_course_description”

#

CREATE TABLE edu_course_description ( id char(19) NOT NULL COMMENT ‘课程ID’, description longtext COMMENT ‘课程简介’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’课程简介’;

#

Structure for table “edu_subject”

#

CREATE TABLE edu_subject ( id char(19) NOT NULL COMMENT ‘课程类别ID’, title varchar(10) NOT NULL COMMENT ‘类别名称’, parent_id char(19) NOT NULL DEFAULT ‘0’ COMMENT ‘父ID’, sort int(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘排序字段’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), KEY idx_parent_id (parent_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT=’课程科目’;

#

Structure for table “edu_teacher”

#

CREATE TABLE edu_teacher ( id char(19) NOT NULL COMMENT ‘讲师ID’, name varchar(20) NOT NULL COMMENT ‘讲师姓名’, intro varchar(500) NOT NULL DEFAULT ‘’ COMMENT ‘讲师简介’, career varchar(500) DEFAULT NULL COMMENT ‘讲师资历,一句话说明讲师’, level int(10) unsigned NOT NULL COMMENT ‘头衔 1高级讲师 2首席讲师’, avatar varchar(255) DEFAULT NULL COMMENT ‘讲师头像’, sort int(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘排序’, is_deleted tinyint(1) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘逻辑删除 1(true)已删除, 0(false)未删除’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), UNIQUE KEY uk_name (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’讲师’;

#

Structure for table “edu_video”

#

CREATE TABLE edu_video ( id char(19) NOT NULL COMMENT ‘视频ID’, course_id char(19) NOT NULL COMMENT ‘课程ID’, chapter_id char(19) NOT NULL COMMENT ‘章节ID’, title varchar(50) NOT NULL COMMENT ‘节点名称’, video_source_id varchar(100) DEFAULT NULL COMMENT ‘云端视频资源’, video_original_name varchar(100) DEFAULT NULL COMMENT ‘原始文件名称’, sort int(10) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘排序字段’, play_count bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘播放次数’, is_free tinyint(1) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘是否可以试听:0收费 1免费’, duration float NOT NULL DEFAULT ‘0’ COMMENT ‘视频时长(秒)’, status varchar(20) NOT NULL DEFAULT ‘Empty’ COMMENT ‘Empty未上传 Transcoding转码中 Normal正常’, size bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘视频源文件大小(字节)’, version bigint(20) unsigned NOT NULL DEFAULT ‘1’ COMMENT ‘乐观锁’, gmt_create datetime NOT NULL COMMENT ‘创建时间’, gmt_modified datetime NOT NULL COMMENT ‘更新时间’, PRIMARY KEY (id), KEY idx_course_id (course_id), KEY idx_chapter_id (chapter_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT=’课程视频’;

  1. - 注意:每张表都有gmt_creategmt_modified字段为创建时间和更新时间参照阿里的开发手册创建的,gmt为格林尼治时间。
  2. <a name="9cc18aec"></a>
  3. ## 工程创建
  4. <a name="0b111084"></a>
  5. ### 模块说明
  6. guli_parent:在线教学根目录(父工程),管理四个子模块:
  7. - canal_clientcanal数据库表同步模块(统计同步数据)
  8. - common:公共模块父节点
  9. - common_util:工具类模块,所有模块都可以依赖于它
  10. - service_baseservice服务的base包,包含service服务的公共配置类,所有service模块依赖于它
  11. - spring_security:认证与授权模块,需要认证授权的service服务依赖于它
  12. - infrastructure:基础服务模块父节点
  13. - api_gatewayapi网关服务
  14. - serviceapi接口服务父节点
  15. - service_acl:用户权限管理api接口服务(用户管理、角色管理和权限管理等)
  16. - service_cmscms api接口服务
  17. - service_edu:教学相关api接口服务
  18. - service_msm:短信api接口服务
  19. - service_order:订单相关api接口服务
  20. - service_oss:阿里云oss api接口服务
  21. - service_statistics:统计报表api接口服务
  22. - service_ucenter:会员api接口服务
  23. - service_vod:视频点播api接口服务
  24. <a name="5b964ac9"></a>
  25. ### 创建父工程
  26. - 使用spring initializr 创建工程方便修改
  27. - 修改打包方式为**pom**
  28. ```xml
  29. <groupId>com.atguigu</groupId>
  30. <artifactId>guli_parent</artifactId>
  31. <packaging>pom</packaging>
  • 修改spring-boot-start-parent版本

    1. <parent>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-parent</artifactId>
    4. <version>2.2.1.RELEASE</version>
    5. <relativePath/> <!-- lookup parent from repository -->
    6. </parent>
  • 配置properties标签做版本标志

    1. <properties>
    2. <java.version>1.8</java.version>
    3. <guli.version>0.0.1-SNAPSHOT</guli.version>
    4. <mybatis-plus.version>3.0.5</mybatis-plus.version>
    5. <velocity.version>2.0</velocity.version>
    6. <swagger.version>2.7.0</swagger.version>
    7. <aliyun.oss.version>2.8.3</aliyun.oss.version>
    8. <jodatime.version>2.10.1</jodatime.version>
    9. <poi.version>3.17</poi.version>
    10. <commons-fileupload.version>1.3.1</commons-fileupload.version>
    11. <commons-io.version>2.6</commons-io.version>
    12. <httpclient.version>4.5.1</httpclient.version>
    13. <jwt.version>0.7.0</jwt.version>
    14. <aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
    15. <aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
    16. <aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
    17. <aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
    18. <aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
    19. <fastjson.version>1.2.28</fastjson.version>
    20. <gson.version>2.8.2</gson.version>
    21. <json.version>20170516</json.version>
    22. <commons-dbutils.version>1.7</commons-dbutils.version>
    23. <canal.client.version>1.1.0</canal.client.version>
    24. <docker.image.prefix>zx</docker.image.prefix>
    25. <cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
    26. </properties>
  • 配置依赖,此处注意使用 dependencyManagement 才不会导入依赖,后续需要使用依赖自行导入,父工程只做版本控制

    1. <dependencyManagement>
    2. <dependencies>
    3. <!--Spring Cloud-->
    4. <dependency>
    5. <groupId>org.springframework.cloud</groupId>
    6. <artifactId>spring-cloud-dependencies</artifactId>
    7. <version>Hoxton.RELEASE</version>
    8. <type>pom</type>
    9. <scope>import</scope>
    10. </dependency>
    11. <dependency>
    12. <groupId>org.springframework.cloud</groupId>
    13. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    14. <version>${cloud-alibaba.version}</version>
    15. <type>pom</type>
    16. <scope>import</scope>
    17. </dependency>
    18. <!--mybatis-plus 持久层-->
    19. <dependency>
    20. <groupId>com.baomidou</groupId>
    21. <artifactId>mybatis-plus-boot-starter</artifactId>
    22. <version>${mybatis-plus.version}</version>
    23. </dependency>
    24. <!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
    25. <dependency>
    26. <groupId>org.apache.velocity</groupId>
    27. <artifactId>velocity-engine-core</artifactId>
    28. <version>${velocity.version}</version>
    29. </dependency>
    30. <!--swagger-->
    31. <dependency>
    32. <groupId>io.springfox</groupId>
    33. <artifactId>springfox-swagger2</artifactId>
    34. <version>${swagger.version}</version>
    35. </dependency>
    36. <!--swagger ui-->
    37. <dependency>
    38. <groupId>io.springfox</groupId>
    39. <artifactId>springfox-swagger-ui</artifactId>
    40. <version>${swagger.version}</version>
    41. </dependency>
    42. <!--aliyunOSS-->
    43. <dependency>
    44. <groupId>com.aliyun.oss</groupId>
    45. <artifactId>aliyun-sdk-oss</artifactId>
    46. <version>${aliyun.oss.version}</version>
    47. </dependency>
    48. <!--日期时间工具-->
    49. <dependency>
    50. <groupId>joda-time</groupId>
    51. <artifactId>joda-time</artifactId>
    52. <version>${jodatime.version}</version>
    53. </dependency>
    54. <!--xls-->
    55. <dependency>
    56. <groupId>org.apache.poi</groupId>
    57. <artifactId>poi</artifactId>
    58. <version>${poi.version}</version>
    59. </dependency>
    60. <!--xlsx-->
    61. <dependency>
    62. <groupId>org.apache.poi</groupId>
    63. <artifactId>poi-ooxml</artifactId>
    64. <version>${poi.version}</version>
    65. </dependency>
    66. <!--文件上传-->
    67. <dependency>
    68. <groupId>commons-fileupload</groupId>
    69. <artifactId>commons-fileupload</artifactId>
    70. <version>${commons-fileupload.version}</version>
    71. </dependency>
    72. <!--commons-io-->
    73. <dependency>
    74. <groupId>commons-io</groupId>
    75. <artifactId>commons-io</artifactId>
    76. <version>${commons-io.version}</version>
    77. </dependency>
    78. <!--httpclient-->
    79. <dependency>
    80. <groupId>org.apache.httpcomponents</groupId>
    81. <artifactId>httpclient</artifactId>
    82. <version>${httpclient.version}</version>
    83. </dependency>
    84. <dependency>
    85. <groupId>com.google.code.gson</groupId>
    86. <artifactId>gson</artifactId>
    87. <version>${gson.version}</version>
    88. </dependency>
    89. <!-- JWT -->
    90. <dependency>
    91. <groupId>io.jsonwebtoken</groupId>
    92. <artifactId>jjwt</artifactId>
    93. <version>${jwt.version}</version>
    94. </dependency>
    95. <!--aliyun-->
    96. <dependency>
    97. <groupId>com.aliyun</groupId>
    98. <artifactId>aliyun-java-sdk-core</artifactId>
    99. <version>${aliyun-java-sdk-core.version}</version>
    100. </dependency>
    101. <dependency>
    102. <groupId>com.aliyun.oss</groupId>
    103. <artifactId>aliyun-sdk-oss</artifactId>
    104. <version>${aliyun-sdk-oss.version}</version>
    105. </dependency>
    106. <dependency>
    107. <groupId>com.aliyun</groupId>
    108. <artifactId>aliyun-java-sdk-vod</artifactId>
    109. <version>${aliyun-java-sdk-vod.version}</version>
    110. </dependency>
    111. <dependency>
    112. <groupId>com.aliyun</groupId>
    113. <artifactId>aliyun-java-vod-upload</artifactId>
    114. <version>${aliyun-java-vod-upload.version}</version>
    115. </dependency>
    116. <dependency>
    117. <groupId>com.aliyun</groupId>
    118. <artifactId>aliyun-sdk-vod-upload</artifactId>
    119. <version>${aliyun-sdk-vod-upload.version}</version>
    120. </dependency>
    121. <dependency>
    122. <groupId>com.alibaba</groupId>
    123. <artifactId>fastjson</artifactId>
    124. <version>${fastjson.version}</version>
    125. </dependency>
    126. <dependency>
    127. <groupId>org.json</groupId>
    128. <artifactId>json</artifactId>
    129. <version>${json.version}</version>
    130. </dependency>
    131. <dependency>
    132. <groupId>commons-dbutils</groupId>
    133. <artifactId>commons-dbutils</artifactId>
    134. <version>${commons-dbutils.version}</version>
    135. </dependency>
    136. <dependency>
    137. <groupId>com.alibaba.otter</groupId>
    138. <artifactId>canal.client</artifactId>
    139. <version>${canal.client.version}</version>
    140. </dependency>
    141. </dependencies>
    142. </dependencyManagement>

创建子模块

  • 创建普通的maven模块,注意继承guli_parent
    image.png

    1. <parent>
    2. <artifactId>guli_parent</artifactId>
    3. <groupId>com.atguigu</groupId>
    4. <version>0.0.1-SNAPSHOT</version>
    5. </parent>
  • 修改打包方式为pom

    1. <artifactId>service</artifactId>
    2. <packaging>pom</packaging>
  • 导入依赖,此时 guli_parent 已做版本控制

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.cloud</groupId>
    4. <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    5. </dependency>
    6. <!--hystrix依赖,主要是用 @HystrixCommand -->
    7. <dependency>
    8. <groupId>org.springframework.cloud</groupId>
    9. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    10. </dependency>
    11. <!--服务注册-->
    12. <dependency>
    13. <groupId>org.springframework.cloud</groupId>
    14. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    15. </dependency>
    16. <!--服务调用-->
    17. <dependency>
    18. <groupId>org.springframework.cloud</groupId>
    19. <artifactId>spring-cloud-starter-openfeign</artifactId>
    20. </dependency>
    21. <dependency>
    22. <groupId>org.springframework.boot</groupId>
    23. <artifactId>spring-boot-starter-web</artifactId>
    24. </dependency>
    25. <!--mybatis-plus-->
    26. <dependency>
    27. <groupId>com.baomidou</groupId>
    28. <artifactId>mybatis-plus-boot-starter</artifactId>
    29. </dependency>
    30. <!--mysql-->
    31. <dependency>
    32. <groupId>mysql</groupId>
    33. <artifactId>mysql-connector-java</artifactId>
    34. </dependency>
    35. <!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
    36. <dependency>
    37. <groupId>org.apache.velocity</groupId>
    38. <artifactId>velocity-engine-core</artifactId>
    39. </dependency>
    40. <!--swagger-->
    41. <dependency>
    42. <groupId>io.springfox</groupId>
    43. <artifactId>springfox-swagger2</artifactId>
    44. </dependency>
    45. <dependency>
    46. <groupId>io.springfox</groupId>
    47. <artifactId>springfox-swagger-ui</artifactId>
    48. </dependency>
    49. <!--lombok用来简化实体类:需要安装lombok插件-->
    50. <dependency>
    51. <groupId>org.projectlombok</groupId>
    52. <artifactId>lombok</artifactId>
    53. </dependency>
    54. <!--xls-->
    55. <dependency>
    56. <groupId>org.apache.poi</groupId>
    57. <artifactId>poi</artifactId>
    58. </dependency>
    59. <dependency>
    60. <groupId>org.apache.poi</groupId>
    61. <artifactId>poi-ooxml</artifactId>
    62. </dependency>
    63. <dependency>
    64. <groupId>commons-fileupload</groupId>
    65. <artifactId>commons-fileupload</artifactId>
    66. </dependency>
    67. <!--httpclient-->
    68. <dependency>
    69. <groupId>org.apache.httpcomponents</groupId>
    70. <artifactId>httpclient</artifactId>
    71. </dependency>
    72. <!--commons-io-->
    73. <dependency>
    74. <groupId>commons-io</groupId>
    75. <artifactId>commons-io</artifactId>
    76. </dependency>
    77. <!--gson-->
    78. <dependency>
    79. <groupId>com.google.code.gson</groupId>
    80. <artifactId>gson</artifactId>
    81. </dependency>
    82. <dependency>
    83. <groupId>junit</groupId>
    84. <artifactId>junit</artifactId>
    85. <version>4.12</version>
    86. </dependency>
    87. </dependencies>

创建子子模块

  • 在service模块下创建子模块,继承service模块
    1. <parent>
    2. <artifactId>service</artifactId>
    3. <groupId>com.atguigu</groupId>
    4. <version>0.0.1-SNAPSHOT</version>
    5. </parent>

以后的功能模块都以此方式搭建。

Swagger

介绍

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

Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 Swagger 进行正确定义,用户可以理解远程服务并使用最少实现逻辑与远程服务进行交互。与为底层编程所实现的接口类似,Swagger 消除了调用服务时可能会有的猜测。

Swagger 的优势

  • 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。
  • 提供 Web 页面在线测试 API:光有文档还不够,Swagger 生成的文档还支持在线测试。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。

配置Swagger

  • 创建common模块,继承guli_parent,common工程用来实现功能模块通用的工具类,创建service_base模块继承common模块
    image.png
  • common模块导入依赖

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-web</artifactId>
    5. <scope>provided </scope>
    6. </dependency>
    7. <!--mybatis-plus-->
    8. <dependency>
    9. <groupId>com.baomidou</groupId>
    10. <artifactId>mybatis-plus-boot-starter</artifactId>
    11. <scope>provided </scope>
    12. </dependency>
    13. <!--lombok用来简化实体类:需要安装lombok插件-->
    14. <dependency>
    15. <groupId>org.projectlombok</groupId>
    16. <artifactId>lombok</artifactId>
    17. <scope>provided </scope>
    18. </dependency>
    19. <!--swagger-->
    20. <dependency>
    21. <groupId>io.springfox</groupId>
    22. <artifactId>springfox-swagger2</artifactId>
    23. <scope>provided </scope>
    24. </dependency>
    25. <dependency>
    26. <groupId>io.springfox</groupId>
    27. <artifactId>springfox-swagger-ui</artifactId>
    28. <scope>provided </scope>
    29. </dependency>
    30. <!-- redis -->
    31. <dependency>
    32. <groupId>org.springframework.boot</groupId>
    33. <artifactId>spring-boot-starter-data-redis</artifactId>
    34. </dependency>
    35. <!-- spring2.X集成redis所需common-pool2
    36. <dependency>
    37. <groupId>org.apache.commons</groupId>
    38. <artifactId>commons-pool2</artifactId>
    39. <version>2.6.0</version>
    40. </dependency>-->
    41. </dependencies>
  • 在service_basem模块下创建SwaggerConfig配置类

    1. @Configuration
    2. @EnableSwagger2
    3. public class SwaggerConfig {
    4. @Bean
    5. public Docket webApiConfig(){
    6. return new Docket(DocumentationType.SWAGGER_2)
    7. .groupName("webApi")
    8. .apiInfo(webApiInfo())
    9. .select()
    10. .paths(Predicates.not(PathSelectors.regex("/admin/.*")))
    11. .paths(Predicates.not(PathSelectors.regex("/error.*")))
    12. .build();
    13. }
    14. private ApiInfo webApiInfo(){
    15. return new ApiInfoBuilder()
    16. .title("网站-课程中心API文档")
    17. .description("本文档描述了课程中心微服务接口定义")
    18. .version("1.0")
    19. .contact(new Contact("peanut", "http://atguigu.com", "1009703142@qq.com"))
    20. .build();
    21. }
    22. }
  • 此时以后功能模块需要使用swagger测试时只需要导入依赖,扫描配置类即可使用

    1. <dependency>
    2. <groupId>com.atguigu</groupId>
    3. <artifactId>service-base</artifactId>
    4. <version>0.0.1-SNAPSHOT</version>
    5. </dependency>
  • 为了防止找不到SwaggerConfig配置类,需要在功能模块的主启动类上加上扫描注解,注意包名一致

    1. @SpringBootApplication
    2. @ComponentScan("com.atguigu") // 扫描common工程下的配置文件
    3. public class EduApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(EduApplication.class, args);
    6. }
    7. }
  • 测试时需要访问swagger测试主页
    http://localhost:8001/swagger-ui.html 注意修改工程端口号

定义接口说明和参数说明

通俗来说,就是在测试时界面上会显示你注释的内容,提高可读性。

例如:

  • 定义在类上:@Api (tags = “讲师管理”)
  • 定义在方法上:@ApiOperation (value = “所有讲师列表”)
  • 定义在参数上:@ApiParam (name = “id”, value = “讲师id”, required = true)
    image.png

返回结果实体类模块

介绍

由于项目是前后端分离,返回json数据,为了使前端处理数据更轻松,我们将所有接口的数据格式统一。一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容。

创建实体类

  • 创建commonutils模块继承common模块
    image.png
  • 在commonutils包下创建接口用来定义返回码,可以是使用常量类或者枚举类

    1. /**
    2. * 此接口用来定义返回码
    3. */
    4. public interface ResultCode {
    5. public static Integer SUCCESS = 20000;
    6. public static Integer ERROR = 20001;
    7. }
  • 创建返回结果实体类
    注意返回this的方法表示此类可以使用链式编程,与spring security类似。

    1. @Data
    2. public class ResultEntity {
    3. @ApiModelProperty(value = "是否成功")
    4. private Boolean success;
    5. @ApiModelProperty(value = "返回码")
    6. private Integer code;
    7. @ApiModelProperty(value = "返回消息")
    8. private String message;
    9. @ApiModelProperty(value = "返回数据")
    10. private Map<String, Object> data = new HashMap<String, Object>();
    11. // 无参构造为私有方法,不能直接new对象
    12. private ResultEntity() {
    13. }
    14. public static ResultEntity ok() {
    15. ResultEntity resultEntity = new ResultEntity();
    16. resultEntity.setSuccess(true);
    17. resultEntity.setCode(ResultCode.SUCCESS);
    18. resultEntity.setMessage("成功");
    19. return resultEntity;
    20. }
    21. public static ResultEntity error() {
    22. ResultEntity resultEntity = new ResultEntity();
    23. resultEntity.setSuccess(false);
    24. resultEntity.setCode(ResultCode.ERROR);
    25. resultEntity.setMessage("失败");
    26. return resultEntity;
    27. }
    28. public ResultEntity success(Boolean success) {
    29. this.setSuccess(success);
    30. return this;
    31. }
    32. public ResultEntity message(String message) {
    33. this.setMessage(message);
    34. return this;
    35. }
    36. public ResultEntity code(Integer code) {
    37. this.setCode(code);
    38. return this;
    39. }
    40. // 保存数据
    41. public ResultEntity data(String key, Object value) {
    42. this.data.put(key, value);
    43. return this;
    44. }
    45. // 保存数据
    46. public ResultEntity data(Map<String, Object> map) {
    47. this.setData(map);
    48. return this;
    49. }
    50. }
  • 同样以后的功能模块需要导入依赖才可以使用实体类

    1. <!-- 继承common_utils工具类 -->
    2. <dependency>
    3. <groupId>com.atguigu</groupId>
    4. <artifactId>common_utils</artifactId>
    5. <version>0.0.1-SNAPSHOT</version>
    6. </dependency>

异常处理

我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。

统一异常处理

  • 统一异常处理类,在service_base模块下创建com.atguigu.servicebase.exception包作为异常处理器
    ```java /**

    • 统一异常处理 */ @RestControllerAdvice public class GlobalExceptionHandler {

      @ExceptionHandler(Exception.class) public ResultEntity error(Exception exception) { exception.printStackTrace(); return ResultEntity.error().message(“执行了全局异常处理”); }

}

  1. - 此时service需要依赖service_utils,才能使用ResultEntity
  2. ```xml
  3. <!-- 继承common_utils工具类 -->
  4. <dependencies>
  5. <dependency>
  6. <groupId>com.atguigu</groupId>
  7. <artifactId>common_utils</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. </dependency>
  10. </dependencies>

特定异常处理

  • 将处理映射修改为特定异常即可
    1. // 特定异常
    2. @ExceptionHandler(ArithmeticException.class)
    3. public ResultEntity error(ArithmeticException arithmeticException) {
    4. arithmeticException.printStackTrace();
    5. return ResultEntity.error().message("执行了ArithmeticException异常处理");
    6. }

自定义异常处理

  • 创建自定义异常类,注意需要继承RuntimeException

    1. @Data
    2. @AllArgsConstructor
    3. @NoArgsConstructor
    4. public class GuliException extends RuntimeException{
    5. private Integer code; // 异常状态码
    6. private String msg; // 异常信息
    7. }
  • 创建异常映射

    1. // 自定义异常
    2. @ExceptionHandler(GuliException.class)
    3. public ResultEntity error(GuliException guliException) {
    4. guliException.printStackTrace();
    5. // 将异常信息设置到结果集中
    6. return ResultEntity.error().code(guliException.getCode()).message(guliException.getMsg());
    7. }
  • 但此时我们程序不会自动抛出GuliException,需要我们手动抛出,实例如下

    1. try {
    2. int i = 10/0;
    3. } catch (Exception exception) {
    4. throw new GuliException(2000,"执行了异常处理!");
    5. }

统一日志处理

常见日志级别:INFO DEBUG WARN ERROR

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

  • 注释掉application.yml中的日志配置,例如

    1. #mybatis-plus: # mybatis-plus日志
    2. # configuration:
    3. # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 创建 logback-spring.xml 文件
    现在启动项目会同时把日志输出到你设置的文件路径中
    image.png ```xml <?xml version=”1.0” encoding=”UTF-8”?>

    logback

  1. <!--输出到控制台-->
  2. <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  3. <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
  4. <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
  5. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  6. <level>INFO</level>
  7. </filter>
  8. <encoder>
  9. <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
  10. <!-- 设置字符集 -->
  11. <charset>UTF-8</charset>
  12. </encoder>
  13. </appender>
  14. <!--输出到文件-->
  15. <!-- 时间滚动输出 level为 INFO 日志 -->
  16. <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  17. <!-- 正在记录的日志文件的路径及文件名 -->
  18. <file>${log.path}/log_info.log</file>
  19. <!--日志文件输出格式-->
  20. <encoder>
  21. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  22. <charset>UTF-8</charset>
  23. </encoder>
  24. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  25. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  26. <!-- 每天日志归档路径以及格式 -->
  27. <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  28. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  29. <maxFileSize>100MB</maxFileSize>
  30. </timeBasedFileNamingAndTriggeringPolicy>
  31. <!--日志文件保留天数-->
  32. <maxHistory>15</maxHistory>
  33. </rollingPolicy>
  34. <!-- 此日志文件只记录info级别的 -->
  35. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  36. <level>INFO</level>
  37. <onMatch>ACCEPT</onMatch>
  38. <onMismatch>DENY</onMismatch>
  39. </filter>
  40. </appender>
  41. <!-- 时间滚动输出 level为 WARN 日志 -->
  42. <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  43. <!-- 正在记录的日志文件的路径及文件名 -->
  44. <file>${log.path}/log_warn.log</file>
  45. <!--日志文件输出格式-->
  46. <encoder>
  47. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  48. <charset>UTF-8</charset> <!-- 此处设置字符集 -->
  49. </encoder>
  50. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  51. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  52. <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  53. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  54. <maxFileSize>100MB</maxFileSize>
  55. </timeBasedFileNamingAndTriggeringPolicy>
  56. <!--日志文件保留天数-->
  57. <maxHistory>15</maxHistory>
  58. </rollingPolicy>
  59. <!-- 此日志文件只记录warn级别的 -->
  60. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  61. <level>warn</level>
  62. <onMatch>ACCEPT</onMatch>
  63. <onMismatch>DENY</onMismatch>
  64. </filter>
  65. </appender>
  66. <!-- 时间滚动输出 level为 ERROR 日志 -->
  67. <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  68. <!-- 正在记录的日志文件的路径及文件名 -->
  69. <file>${log.path}/log_error.log</file>
  70. <!--日志文件输出格式-->
  71. <encoder>
  72. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  73. <charset>UTF-8</charset> <!-- 此处设置字符集 -->
  74. </encoder>
  75. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  76. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  77. <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  78. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  79. <maxFileSize>100MB</maxFileSize>
  80. </timeBasedFileNamingAndTriggeringPolicy>
  81. <!--日志文件保留天数-->
  82. <maxHistory>15</maxHistory>
  83. </rollingPolicy>
  84. <!-- 此日志文件只记录ERROR级别的 -->
  85. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  86. <level>ERROR</level>
  87. <onMatch>ACCEPT</onMatch>
  88. <onMismatch>DENY</onMismatch>
  89. </filter>
  90. </appender>
  91. <!--
  92. <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
  93. <logger>仅有一个name属性,
  94. 一个可选的level和一个可选的addtivity属性。
  95. name:用来指定受此logger约束的某一个包或者具体的某一个类。
  96. level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
  97. 如果未设置此属性,那么当前logger将会继承上级的级别。
  98. -->
  99. <!--
  100. 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
  101. 第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
  102. 第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
  103. -->
  104. <!--开发环境:打印控制台-->
  105. <springProfile name="dev">
  106. <!--可以输出项目中的debug日志,包括mybatis的sql日志-->
  107. <logger name="com.guli" level="INFO" />
  108. <!--
  109. root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
  110. level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
  111. 可以包含零个或多个appender元素。
  112. -->
  113. <root level="INFO">
  114. <appender-ref ref="CONSOLE" />
  115. <appender-ref ref="INFO_FILE" />
  116. <appender-ref ref="WARN_FILE" />
  117. <appender-ref ref="ERROR_FILE" />
  118. </root>
  119. </springProfile>
  120. <!--生产环境:输出到文件-->
  121. <springProfile name="pro">
  122. <root level="INFO">
  123. <appender-ref ref="CONSOLE" />
  124. <appender-ref ref="DEBUG_FILE" />
  125. <appender-ref ref="INFO_FILE" />
  126. <appender-ref ref="ERROR_FILE" />
  127. <appender-ref ref="WARN_FILE" />
  128. </root>
  129. </springProfile>

  1. - 如果程序出现异常,把异常信息输出到文件中
  2. 1. 在异常处理类加上注解 [**@Slf4j **](/Slf4j )** **
  3. 1. 此时使用slf4j的日志可以输出信息到文件中
  4. ```java
  5. // 自定义异常
  6. @ExceptionHandler(GuliException.class)
  7. public ResultEntity error(GuliException guliException) {
  8. log.error(guliException.getMessage());
  9. guliException.printStackTrace();
  10. // 将异常信息设置到结果集中
  11. return ResultEntity.error().code(guliException.getCode()).message(guliException.getMsg());
  12. }
  1. 此时出现错误会打印到log_error.log文件中,其他级别的日志也可以类似以上方式输出到各自的文件中

集成Redis

Redis介绍

Redis是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语言编写的key-value存储系统(区别于MySQL的二维表格的形式存储。)。和Memcache类似,但很大程度补偿了Memcache的不足。和Memcache一样,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。所以Memcache的应用场景适用于缓存无需持久化的数据。而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化。

Redis的特点:

1,Redis读取的速度是110000次/s,写的速度是81000次/s;

2,原子性 。Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

3,支持多种数据结构:string(字符串);list(列表);hash(哈希),set(集合);zset(有序集合)

4,持久化,集群部署

5,支持过期时间,支持事务,消息订阅

引入项目

一般来说,把不重要,经常查询,不经常修改的数据存储在redis中。

  • 在service_base模块下引入

    1. <!-- spring2.X集成redis所需common-pool2-->
    2. <dependency>
    3. <groupId>org.apache.commons</groupId>
    4. <artifactId>commons-pool2</artifactId>
    5. <version>2.6.0</version>
    6. </dependency>
    7. </dependencies>
  • 创建redis配置类

    1. @EnableCaching
    2. @Configuration
    3. public class RedisConfig extends CachingConfigurerSupport {
    4. @Bean
    5. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    6. RedisTemplate<String, Object> template = new RedisTemplate<>();
    7. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    8. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    9. ObjectMapper om = new ObjectMapper();
    10. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    11. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    12. jackson2JsonRedisSerializer.setObjectMapper(om);
    13. template.setConnectionFactory(factory);
    14. //key序列化方式
    15. template.setKeySerializer(redisSerializer);
    16. //value序列化
    17. template.setValueSerializer(jackson2JsonRedisSerializer);
    18. //value hashmap序列化
    19. template.setHashValueSerializer(jackson2JsonRedisSerializer);
    20. return template;
    21. }
    22. @Bean
    23. public CacheManager cacheManager(RedisConnectionFactory factory) {
    24. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    25. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    26. //解决查询缓存转换异常的问题
    27. ObjectMapper om = new ObjectMapper();
    28. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    29. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    30. jackson2JsonRedisSerializer.setObjectMapper(om);
    31. // 配置序列化(解决乱码的问题),过期时间600秒
    32. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    33. .entryTtl(Duration.ofSeconds(600))
    34. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
    35. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
    36. .disableCachingNullValues();
    37. RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
    38. .cacheDefaults(config)
    39. .build();
    40. return cacheManager;
    41. }
    42. }
  • 此时需要使用redis的模块需要引入依赖,并且配置application配置文件

    1. srping:
    2. redis:
    3. host: 192.168.241.130 # ip地址
    4. port: 6379 # 端口号
    5. database: 0
    6. timeout: 1800000 # 超时时间
    7. lettuce:
    8. pool:
    9. max-active: 20
    10. max-wait: -1 # 最大阻塞等待时间(负数表示没限制)
    11. max-idle: 5
    12. min-idle: 0

在接口中添加redis缓存

由于首页数据变化不是很频繁,而且首页访问量相对较大,所以我们有必要把首页接口数据缓存到redis缓存中,减少数据库压力和提高访问速度。

Spring Boot缓存注解

@Cacheable

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key

@CachePut

使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key

@CacheEvict

使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key
allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
beforeInvocation 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

Redis的启动

  • 启动redis服务

image.png

  • 连接redis服务可能遇到的问题

关闭liunx防火墙,找到redis配置文件, 注释一行配置

image.png

如果出现下面错误提示image.png修改 protected-mode yes 改为 protected-mode no