现在开始我们需要学习一下Spring boot 和Vue3的前后端分离,增强全栈能力
关于Spring Boot 我们需要掌握的有很多东西,比如AOP、拦截器、过滤器、异步化、定时任务、websocket、多环境、缓存,消息队列等等

开发环境有下面这些:

  • ideaIU-2019.2.3.exe
  • Mysql8.0 / 5.7
  • Git-2.23.0-64-bit.exe
  • node-v12.10-0-x64.msi
  • jdk-8u221-windows-x64.exe / jdk-8u202-linux-x64.tar.gz

Spring Boot项目搭建

1. 两种方法创建Spring Boot

第一种方法就是到官网https://start.spring.io/ 去选择,然后下载到本地,解压后使用IDEA打开就行。
image.png

第二种方法就是打开IDEA然后创建一个spring项目,整个流程和你在官网选择几乎一样,但是IDEA2021没有创建spring boot项目这个选择。

2. Spring Boot目录结构

image.png

  • mvn-> wrapper:这个文件的好处就是你不需要提前去下载maven,但是我们一般本地环境用IDEA自带的Maven就可以了。
  • mvnw和mvnw.cmd都是和前面的mvn是一起的,前者是linux命令,后者是windows命令
  • src -> resources: 这里放的是一些前端的文件,js,css,如果是前后端分离的话一般用不到,可以将static和templates直接删掉
  • application.properties:spring boot的配置文件,我们后面还会仔细讲
  • HELP.md:功能类似于README.md
  • pom.xml:maven项目依赖文件

3. 启动Spring Boot项目

启动项目可以直接找到Application文件,然后右键运行即可

  1. @SpringBootApplication
  2. public class WikiApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(WikiApplication.class, args);
  5. }
  6. }

4. 总结知识点

  • SpringBoot不需要配置容器,是因为使用了嵌入式容器,可以在包当中看到项目本身有org.apache.tomcat.embed,所以也是默认使用tomcat启动。也可以使用传统的方式,打包成war包,放在单独的tomcat当中也是可以的。
  • SpringBoot的启动函数需要添加@SpringBootApplication注解

项目初始配置

1. 编码配置

image.png
一定要在设置后选择Apply进行应用。

2. JDK配置

在File -> Project Structure当中选择项目的Project SDK

3. Maven配置

因为使用IDEA打开项目之后就会去自动下载依赖,想要使用maven下载的快就要设置settings当中的Maven当中的User settings file选项,并且在配置好后点击后面的Override。我这里的值为:C:\Users\Administrator.m2\settings.xml,这个settings.xml是需要自己创建的,内容如下;

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  5. <!--本地仓库位置-->
  6. <localRepository>C:\Users\Administrator\.m2\repository</localRepository>
  7. <pluginGroups/>
  8. <proxies/>
  9. <servers>
  10. </servers>
  11. <mirrors>
  12. <!--阿里云的镜像-->
  13. <mirror>
  14. <id>alimaven</id>
  15. <name>aliyun maven</name>
  16. <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
  17. <mirrorOf>central</mirrorOf>
  18. </mirror>
  19. <!--中央仓库在中国的位置-->
  20. <mirror>
  21. <id> maven-net-cn</id>
  22. <name> Maven China Mirror</name>
  23. <url> http://maven.net.cn/content/groups/public/</url>
  24. <mirrorOf>central</mirrorOf>
  25. </mirror>
  26. </mirrors>
  27. <profiles>
  28. <!--配置jdk的版本-->
  29. <profile>
  30. <id>jdk-1.8</id>
  31. <activation>
  32. <activeByDefault>true</activeByDefault>
  33. <jdk>1.8</jdk>
  34. </activation>
  35. <properties>
  36. <maven.compiler.source>1.8</maven.compiler.source>
  37. <maven.compiler.target>1.8</maven.compiler.target>
  38. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  39. </properties>
  40. </profile>
  41. </profiles>
  42. </settings>

注意一定要将localRepository的路径配置正确。

4. Git配置

  • VCS -> Enable Version Control Intergration -> 选择Git
  • 在下方找到Git窗口,这里有所有信息,关于操作我们在IDEA项目实战当中已经讲解过,这里就不过多赘述。

5. 关联远程仓库

在github上创建一个新的项目,但是不需要README.md和.gitignore文件,然后回到本地项目当中,在命令行中输入:

  • git remote add origin git@gitee.com:taopoppy/wiki.git(这是我的项目地址)
  • git push -u origin master

这样就将本地项目和远程项目关联在了一起,前提是远程git仓库设置SSH秘钥,这个在IDEA项目实战当中已经讲述。

比如我们删除掉.gitignore当中的HELP.md选项,那么想要将HELP.md添加到版本管理,可以先Commit面板当中先刷新,然后将HELP.md文件右键选择add to VCS,然后在选择Commit或者Commit and push

启动日志优化

1. logback日志样式修改

在resources文件夹当中添加logback-spring.xml,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3. <!-- 修改一下路径-->
  4. <property name="PATH" value="./log"></property>
  5. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  6. <encoder>
  7. <!-- <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>-->
  8. <Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>
  9. </encoder>
  10. </appender>
  11. <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  12. <file>${PATH}/trace.log</file>
  13. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  14. <FileNamePattern>${PATH}/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
  15. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  16. <maxFileSize>10MB</maxFileSize>
  17. </timeBasedFileNamingAndTriggeringPolicy>
  18. </rollingPolicy>
  19. <layout>
  20. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
  21. </layout>
  22. </appender>
  23. <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  24. <file>${PATH}/error.log</file>
  25. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  26. <FileNamePattern>${PATH}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
  27. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  28. <maxFileSize>10MB</maxFileSize>
  29. </timeBasedFileNamingAndTriggeringPolicy>
  30. </rollingPolicy>
  31. <layout>
  32. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
  33. </layout>
  34. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  35. <level>ERROR</level>
  36. <onMatch>ACCEPT</onMatch>
  37. <onMismatch>DENY</onMismatch>
  38. </filter>
  39. </appender>
  40. <root level="ERROR">
  41. <appender-ref ref="ERROR_FILE" />
  42. </root>
  43. <root level="TRACE">
  44. <appender-ref ref="TRACE_FILE" />
  45. </root>
  46. <root level="INFO">
  47. <appender-ref ref="STDOUT" />
  48. </root>
  49. </configuration>

修改当中的内容:时间,级别,日志所在的类,行号,线程,信息,然后将ERROR, TRACE, INFO全部单独输出。全部输出到项目的log文件夹当中,然后可以在.gitignore当中添加/log/将其忽略。

2. 增加启动成功日志

我们现在来修改一下启动文件:

  1. @SpringBootApplication
  2. public class WikiApplication {
  3. private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
  4. public static void main(String[] args) {
  5. SpringApplication app = new SpringApplication(WikiApplication.class);
  6. Environment env = app.run(args).getEnvironment();
  7. LOG.info("启动成功");
  8. LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
  9. }
  10. }

其中我们需要在application.properties当中书写下面的代码:

  1. server.port=8080

这样说来,env.getProperty这个方法就是用来读取application.properties的某个属性的方法。

3. 修改启动图案

直接在resources文件夹当中添加banner.txt文件,然后在http://patorjk.com/software/taag/#p=display&f=Big&t=taopoppy当中选择你需要的好看的图案,然后保存到banner.txt文件当中。

编写和测试接口

1. hello world接口

我们在前后端分离的项目当中一定要在controller当中书写类,在类中书写接口,比如在src/java/com.taopoppy.wiki/controller/TestController.java当中:

  1. @RestController
  2. public class TestController {
  3. @GetMapping("/hello")
  4. // @PutMapping
  5. // @DeleteMapping
  6. // @PostMapping
  7. // @RequestMapping(value = "user/1", method = RequestMethod.GET)
  8. public String hello() {
  9. return "Hello World";
  10. }
  11. }
  • @RestController 这个注解是表示返回的是字符串或者JSON对象
  • @GetMapping表示该结构只能由get方法访问,同理@PutMapping、@DeleteMapping、@PostMapping都是如此
  • @RequestMapping()这个方法有两个参数,如果直接书写@RequestMapping(“/hello”)表示这个方法支持所有请求方式,但是@RequestMapping(value = “hello”, method = RequestMethod.GET)和@GetMapping(“/hello”)是一样的效果。

2. 修改启动位置

注意正常的启动文件会有@SpringBootApplication这样一个注解,表示启动注解,源码当中它是包含@ComponentScan的注解,这个是扫描的意思,启动类会自动扫描当前启动类所在的文件,将里面的接口文件全部扫描到。

但是现在如果直接把启动文件放在这样的一个位置,如下图:
image.png
那么WikiApplication实际上扫描不到TestController这个接口类的,因为不在一个文件内,所以要想让WikiApplicaiton扫描到接口文件就要修改@ComponentScan的扫描范围,因为config文件夹和controller文件夹都在com.taopoppy.wiki当中,所以书写@ComponentScan(“com.taopoppy”)或者@ComponentScan(“com.taopoppy.wiki”)都是可以的。

  1. @ComponentScan("com.taopoppy")
  2. @SpringBootApplication
  3. public class WikiApplication {
  4. private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
  5. public static void main(String[] args) {
  6. SpringApplication app = new SpringApplication(WikiApplication.class);
  7. Environment env = app.run(args).getEnvironment();
  8. LOG.info("启动成功");
  9. LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
  10. }
  11. }

如果扫描多个包可以这样书写:

  1. @ComponentScan("com.taopoppy","com.test")

配置文件介绍

1. 默认支持的配置文件

spring boot的配置项是在resources当中,但是下面三种都是可以的,只不过写法不同

  • resources/application.properties
  • resources/config/application.properties
  • resources/application.yml

两种不同的文件写法不一样,可以在https://toyaml.com/index.html进行转换:
image.png

2. 自定义配置项

自定义配置项就是在application.properties当中书写自己的一些自定义的配置项,然后在其他地方可以直接使用,比如我们在application.properties当中去书写一个这样的代码:

  1. author.name=taopoppy

然后在代码当中可以这样使用:

  1. @RestController
  2. public class TestController {
  3. @Value("${author.name: xiaoming}")
  4. private String name; // 通过@Value注解拿到author.name的值taopoppy,如果我们没有配置就取默认值xiaoming
  5. @GetMapping("/hello")
  6. public String hello() {
  7. return name; // 作为接口结果返回出去
  8. }
  9. }

集成热部署

1. 添加依赖

在pom.xml当中添加下面的代码,不需要带版本号,因为这个是spring内置的一个模块:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-devtools</artifactId>
  4. </dependency>

2. 开启静态编译

勾线下面图中的选项:
image.png

3. 开启动态编译

双击Shift进行搜索,搜索Registry,找到下面的图标,在红色方框处勾选即可。
image.png

这样我们在修改文件的时候,随时进行修改后,点击Ctrl+S或者Ctrl+F9(工具栏的小锤子按钮:Build project),项目就已经重新热启动了,速度要比自己重启快很多。

IDEA关联数据库

mysql和navicat的安装这里就不多说了,安装好之后,我们使用navicat连接好mysql之后,新建一个数据库,注意要选择utf8mb4,这个是真正的utf8,可以存放表情符号:
image.png

1. 新建用户

接下来我们要创建一个专属访问wiki这个数据库的用户,因为root的权限太大了,并不安全。
1642313806(1).png
1642313934(1).png
上面我输入的密码是123456,然后我们在配置一下权限
1642314127(1).png
然后返回到用户界面就可以看到wiki@localhost这个新的用户了,接着使用这个新的用户去连接本地的数据库,点击新建:
1642314374(1).png

2. 新建表

1642314533(1).png
1642314776(1).png
然后在点击保存后输入表名test即可,这样我们就新建了一个test的表。

3. 阿里云数据库的准备

阿里云的产品-> 数据库-> 云数据库 RDS MySql版,点击立即购买:
1642315304(1).png
1642315416(1).png
然后下一步的实例配置基本不用动,为默认配置,然后下单支付即可,但是要注意的是:后续还要购买服务器ECS,ECS和RDS之间的访问要配置成内网访问,需要购买在同一个地域

  • 接着我们进入到阿里云控制台首页
  • 找到产品与服务
  • 在最近使用产品当中找到云数据库 RDS版
  • 进入之后,在左边侧边栏当中找到实例列表,并在最上面导航栏里选择你刚买的RDS的地域,我买的是华北5(呼和浩特)
  • 然后显示出实例后,我们点击实例最右侧的管理
  • 进入后在左侧边栏当中选择账号管理,然后选择创建账号
    • 数据库账号:wiki
    • 账号类型:普通账号
    • 密码:tao3941319=-=
  • 然后在左侧边栏当中选择数据库管理,然后点击创建数据库:
    • 数据库(DB)名称:wiki
    • 支持字符集:utf8
    • 授权账号:wiki(普通账号)
    • 账号类型:读写
  • 然后在上面找到登录数据库,输入上面我们创建的数据库账号和密码,然后测试连接即可
  • 测试成功之后,我们回到实例,点击实例一栏最左侧的地址,进入之后有两个地址

    • 内网地址:生产环境的时候,ECS通过内网访问RDS
    • 外网地址:开发的时候本地连接阿里云应该使用外网地址

      4. IDEA数据库插件配置

      在IDEA里面配置数据库连接,相当于把IDEA当成一个MySql的客户端, 我们现在就说一下如何在IDEA当中配置Database Navigator:
  • 如果能从IDEA当中的plugins搜到最好,搜不到就要手动下载,我们去IDEA插件网搜索Database Navigator,下载下来,都放在G:\javaplugin当中,然后在IDEA的plugins配置当中去加载这个插件。

  • 然后需要驱动mysql-connector-java,所以我们到https://mvnrepository.com/去搜索,然后将对应的代码放在pom.xml当中,会自动到我们前面配的阿里云上拉取这个jar包(所有版本,除非你自己指定版本),我在IDEA当中配的是D:\apache-maven-3.8.1\maven-repo,默认是在C:\Users\Administrator.m2\repository
    1. <dependency>
    2. <groupId>mysql</groupId>
    3. <artifactId>mysql-connector-java</artifactId>
    4. </dependency>
    然后在view -> Tools Windows ->DB Browser,然后创建一个新的,特别注意我们这里只是配置了本地的,如果你配置阿里云的话,Host就要填外网地址。
    1642327712(1).png
    1642385557(1).png
    友情提示,在阿里云外网地址和内网地址默认是显示不出来的,必须先要设置白名单,白名单默认是127.0.0.1,即禁止一切其他访问,变成0.0.0.0/0才能允许其他一切访问。

集成Mybatis

1. 集成mybatis

简单的说:和数据库打交道的这一层就是持久层,常见的持久层有Mybatis、Hibernate、前者是半自动的,后者是全自动,半自动就是需要自己写sql,全自动就是不需要写sql。我们首先在pom.xml添加依赖:

  1. <!--集成mybatis-->
  2. <dependency>
  3. <groupId>org.mybatis.spring.boot</groupId>
  4. <artifactId>mybatis-spring-boot-starter</artifactId>
  5. <version>2.1.3</version>
  6. </dependency>
  7. <!--集成mysql连接-->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.22</version>
  12. </dependency>

添加了mybatis,我们需要到application.properties当中去配置数据源:

  1. # 增加数据库连接
  2. spring.datasource.url=jdbc:mysql://rm-hp3f05153598ck3e5vo.mysql.huhehaote.rds.aliyuncs.com/wiki?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai
  3. spring.datasource.username=wiki
  4. spring.datasource.password=***** # 这里是我自己的密码
  5. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2. 使用mybatis

特别注意:集成mybatis只需要下载jar包以及配置数据源,并不会真正去连接你配置的数据源,所以你即使是配错了也无所谓。那接下来我们看一下怎么使用:

(1)domain(实体类)

  • 在com.taopoppy.wiki下面新建一个domain的package(这一层实体类就是和数据库表一一映射
  • 在domain下面新建一个Test的class实体类,内容如下 ```java package com.taopoppy.wiki.domain;

public class Test { private Integer id;

  1. private String name;
  2. private String password;
  3. // 下面代码直接右键Genetater->Getter and Setter生成
  4. public Integer getId() {
  5. return id;
  6. }
  7. public void setId(Integer id) {
  8. this.id = id;
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public String getPassword() {
  17. return password;
  18. }
  19. public void setPassword(String password) {
  20. this.password = password;
  21. }

}

  1. <br />
  2. <a name="A702R"></a>
  3. #### (2)mapper(持久层)
  4. **持久层叫Mapper层,即广为人知的Dao层,因为后续要用官方代码生成器,其生成的代码就是XXXMapper**<br />所以我们现在来写一个接口:
  5. - 在com.taopoppy.wiki下面新建一个mapper的package
  6. - 在mapper下面新建一个interface:TestMapper,内容如下:
  7. ```java
  8. package com.taopoppy.wiki.mapper;
  9. import com.taopoppy.wiki.domain.Test;
  10. import java.util.List;
  11. public interface TestMapper {
  12. public List<Test> list();
  13. }
  • 然后我们去书写关于sql的xml文件:

    • 在resources下面创建mapper文件夹
    • 在mapper文件夹下面创建一个TestMapper.xml的文件,其中使用到了mybatis的语法: ```xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd“ >

  1. 接着我们需要做两个配置,因为你写了mapperxmlsql,但是项目不认识:
  2. - config/WikiApplication当中配置扫描mapper持久层文件
  3. ```java
  4. @ComponentScan("com.taopoppy")
  5. @SpringBootApplication
  6. @MapperScan("com.taopoppy.wiki.mapper") # 这里配置
  7. public class WikiApplication {
  8. private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
  9. public static void main(String[] args) {
  10. SpringApplication app = new SpringApplication(WikiApplication.class);
  11. Environment env = app.run(args).getEnvironment();
  12. LOG.info("启动成功");
  13. LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
  14. }
  15. }
  • 在resources/application.properties当中配置mybatis的xml路径,其中classpath就是resources,/*/.xml表示mapper文件夹下的所有xml文件。

    1. # 配置mybatics所有Mapper.xml所在的路径
    2. mybatis.mapper-locations=classpath:/mapper/**/*.xml

    (3)service(服务层)

  • 在com.taopoppy.wiki下面新建一个service的package

  • 在service下面创建一个Class叫做:TestService,代码如下: ```java package com.taopoppy.wiki.service;

import com.taopoppy.wiki.domain.Test; import com.taopoppy.wiki.mapper.TestMapper; import org.springframework.stereotype.Service;

import javax.annotation.Resource; import java.util.List;

@Service public class TestService { @Resource private TestMapper testMapper;

  1. public List<Test> list() {
  2. return testMapper.list();
  3. }

}

  1. <a name="G1Kof"></a>
  2. #### (4)controller(控制层)
  3. 最后我们就要在controller这个包下面创建:TestController,内容如下:
  4. ```java
  5. package com.taopoppy.wiki.controller;
  6. import com.taopoppy.wiki.domain.Test;
  7. import com.taopoppy.wiki.service.TestService;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import javax.annotation.Resource;
  11. import java.util.List;
  12. @RestController
  13. public class TestController {
  14. @Resource
  15. private TestService testService;
  16. @GetMapping("/test/list")
  17. public List<Test> list() {
  18. return testService.list();
  19. }
  20. }

整个接口调用的顺序是:

  • controller -> service ->mapper -> resources/mapper

此时,可以正常调用http://127.0.0.1:8081/test/list

Mybatis Generator使用

1. mybatis generator的集成

通过上面的代码可以看出来,写一个接口实在是太麻烦,然后我们可以使用mybitis的官方生成器,首先在pom.xml当中去粘贴下面的代码到plugins处:

  1. <!-- mybatis generator 自动生成代码插件 -->
  2. <plugin>
  3. <groupId>org.mybatis.generator</groupId>
  4. <artifactId>mybatis-generator-maven-plugin</artifactId>
  5. <version>1.4.0</version>
  6. <configuration>
  7. <configurationFile>src/main/resources/generator/generator-config.xml</configurationFile>
  8. <overwrite>true</overwrite>
  9. <verbose>true</verbose>
  10. </configuration>
  11. <dependencies>
  12. <dependency>
  13. <groupId>mysql</groupId>
  14. <artifactId>mysql-connector-java</artifactId>
  15. <version>8.0.22</version>
  16. </dependency>
  17. </dependencies>
  18. </plugin>

然后我们要自己生成一个src/main/resources/generator/generator-config.xml文件,注意复制粘贴后需要修改对应的东西:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6. <context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">
  7. <!-- 自动检查关键字,为关键字增加反引号 -->
  8. <property name="autoDelimitKeywords" value="true"/>
  9. <property name="beginningDelimiter" value="`"/>
  10. <property name="endingDelimiter" value="`"/>
  11. <!--覆盖生成XML文件-->
  12. <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
  13. <!-- 生成的实体类添加toString()方法 -->
  14. <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
  15. <!-- 不生成注释 -->
  16. <commentGenerator>
  17. <property name="suppressAllComments" value="true"/>
  18. </commentGenerator>
  19. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
  20. connectionURL="jdbc:mysql://rm-hp3f05153598ck3e5vo.mysql.huhehaote.rds.aliyuncs.com:3306/wikidev?serverTimezone=Asia/Shanghai"
  21. userId="wikidev"
  22. password="tao3941319=-=">
  23. </jdbcConnection>
  24. <!-- domain类的位置 -->
  25. <javaModelGenerator targetProject="src\main\java"
  26. targetPackage="com.taopoppy.wiki.domain"/>
  27. <!-- mapper xml的位置 -->
  28. <sqlMapGenerator targetProject="src\main\resources"
  29. targetPackage="mapper"/>
  30. <!-- mapper类的位置 -->
  31. <javaClientGenerator targetProject="src\main\java"
  32. targetPackage="com.taopoppy.wiki.mapper"
  33. type="XMLMAPPER"/>
  34. <table tableName="demo" domainObjectName="Demo"/>
  35. </context>
  36. </generatorConfiguration>

注意:上述文件当中的table里面写的demo,前提我们要在连接的数据库当中提前创建好这个demo的表。后面生成的文件全是关于这个demo表的,如果生成其他相关表的代码就要改这里的tableName的值。

在启动符号的左边下拉框当中找到:Edit Configurations,然后新增一个maven的configuration:
1642473364(1).png
然后我们去执行一下这个configuration:
1642476221(1).png
接着就会创建出响应的代码,在domain生成了Demo.java和DemoExample.java,在mapper下面生成了DemoMapper,在resources/mapper下面生成了DemoMapper.xml。请注意:这四个文件我们以后都不要动

2. mybatis generator的使用

现在我们先在sercvice下面创建一个DemoService文件,内容如下:

  1. package com.taopoppy.wiki.service;
  2. import com.taopoppy.wiki.domain.Demo;
  3. import com.taopoppy.wiki.mapper.DemoMapper;
  4. import org.springframework.stereotype.Service;
  5. import javax.annotation.Resource;
  6. import java.util.List;
  7. @Service
  8. public class DemoService {
  9. @Resource
  10. private DemoMapper demoMapper;
  11. public List<Demo> list() {
  12. // 传null表示查所有的表数据
  13. return demoMapper.selectByExample(null);
  14. }
  15. }

然后在controller当中创建DemoController.java,内容如下:

  1. package com.taopoppy.wiki.controller;
  2. import com.taopoppy.wiki.domain.Demo;
  3. import com.taopoppy.wiki.service.DemoService;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import javax.annotation.Resource;
  8. import java.util.List;
  9. @RestController
  10. @RequestMapping("/demo")
  11. public class DemoController {
  12. @Resource
  13. private DemoService demoService;
  14. @GetMapping("/list")
  15. public List<Demo> list() {
  16. return demoService.list();
  17. }
  18. }

这样的话,我们就可以在http/demo.http文件下书写这样的请求去测试:

  1. GET http://localhost:8081/demo/list

统一规范

1. 电子书列表查询开发

先执行一下下面的代码,在ebook表创造点数据:

  1. drop table if exists `ebook`;
  2. create table `ebook` (
  3. `id` bigint not null comment 'id',
  4. `name` varchar(50) comment '名称',
  5. `category1_id` bigint comment '分类1',
  6. `category2_id` bigint comment '分类2',
  7. `description` varchar(200) comment '描述',
  8. `cover` varchar(200) comment '封面',
  9. `doc_count` int comment '文档数',
  10. `view_count` int comment '阅读数',
  11. `vote_count` int comment '点赞数',
  12. primary key (`id`)
  13. ) engine=innodb default charset=utf8mb4 comment='电子数';
  14. insert into `ebook` (id, name, description) values (1, 'Spring Boot 入门教程','零基础入门Java开发,企业级应用开发最佳首选框架');
  15. insert into `ebook` (id, name, description) values (2, 'Vue 入门教程','零基础入门 Vue 开发,企业级应用开发最佳首选框架');
  16. insert into `ebook` (id, name, description) values (3, 'Python 入门教程','零基础入门 Python 开发,企业级应用开发最佳首选框架');
  17. insert into `ebook` (id, name, description) values (4, 'Mysql 入门教程','零基础入门 Mysql 开发,企业级应用开发最佳首选框架');

然后我们修改generator-config.xml文件,修改最下面的table标签:
1642756172(1).png
然后回到上面去执行一下我们之前生成的名字叫做mybatis-generator的configration,生成ebook相关的持久层代码。

然后就去书写service和controller层的代码(直接粘贴复制以前的代码,然后对应的关键词修改成为ebook或者Ebook即可):

  1. package com.taopoppy.wiki.service;
  2. import com.taopoppy.wiki.domain.Ebook;
  3. import com.taopoppy.wiki.mapper.EbookMapper;
  4. import org.springframework.stereotype.Service;
  5. import javax.annotation.Resource;
  6. import java.util.List;
  7. @Service
  8. public class EbookService {
  9. @Resource
  10. private EbookMapper ebookMapper;
  11. public List<Ebook> list() {
  12. // 传null表示查所有的表数据
  13. return ebookMapper.selectByExample(null);
  14. }
  15. }
  1. package com.taopoppy.wiki.controller;
  2. import com.taopoppy.wiki.domain.Ebook;
  3. import com.taopoppy.wiki.service.EbookService;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import javax.annotation.Resource;
  8. import java.util.List;
  9. @RestController
  10. @RequestMapping("/ebook")
  11. public class EbookController {
  12. @Resource
  13. private EbookService ebookService;
  14. @GetMapping("/list")
  15. public List<Ebook> list() {
  16. return ebookService.list();
  17. }
  18. }

然后我们去http/ebook.http当中测试GET http://localhost:8081/ebook/list即可

由于后端会有很多接口,为了让前端能够统一处理逻辑(比如登录校验,权限校验),需要统一后端的返回值,所以我们需要自己制作一个统一的类,在com.taopoppy.wiki.resp的CommonResp内容如下:

  1. package com.taopoppy.wiki.resp;
  2. public class CommonResp<T> {
  3. /**
  4. * 业务上的成功或失败
  5. */
  6. private boolean success = true;
  7. /**
  8. * 返回信息
  9. */
  10. private String message;
  11. /**
  12. * 返回泛型数据,自定义类型
  13. */
  14. private T content;
  15. public boolean isSuccess() {
  16. return success;
  17. }
  18. public void setSuccess(boolean success) {
  19. this.success = success;
  20. }
  21. public String getMessage() {
  22. return message;
  23. }
  24. public void setMessage(String message) {
  25. this.message = message;
  26. }
  27. public T getContent() {
  28. return content;
  29. }
  30. public void setContent(T content) {
  31. this.content = content;
  32. }
  33. }

然后我们在EbookController返回值当中就可以这样写(特别要注意泛型):

  1. @GetMapping("/list")
  2. public CommonResp list() {
  3. CommonResp<List<Ebook>> resp = new CommonResp<>();
  4. List<Ebook> list = ebookService.list();
  5. resp.setContent(list);
  6. return resp;
  7. }

2. 封装请求参数和返回参数

我们先来做一个模糊查询的功能,比如我们在EbookController.java当中修改一下代码:

  1. @GetMapping("/list")
  2. public CommonResp list(String name) { # 传递name参数进去
  3. CommonResp<List<Ebook>> resp = new CommonResp<>();
  4. List<Ebook> list = ebookService.list(name);
  5. resp.setContent(list);
  6. return resp;
  7. }

接着修改EbookService.java当中的代码:

  1. public List<Ebook> list(String name) {
  2. // 创建一个Ebookexample的查询实例
  3. EbookExample ebookExample = new EbookExample();
  4. // createCriteria相当于where条件
  5. EbookExample.Criteria criteria = ebookExample.createCriteria();
  6. criteria.andNameLike("%" + name + "%");
  7. // 根据ebookExample条件查询
  8. return ebookMapper.selectByExample(ebookExample);
  9. }

接着我们可以通过GET http://localhost:8081/ebook/list?name=Spring 这种方式进行模糊查询

但是由于我们还有其他参数需要传递,所以我们不可能每一个参数都要书写一遍,所以我们需要将请求参数封装成一个类,另外我们之前书写的Ebook类是和数据库一一对应的,比如说如果是用户登录,我们不能将User当中的所有属性返回,因为密码也在里面,所以应该只将部分属性返回,也就必须创建一个返回类:

  • EbookReq(用户请求的类)——-> Ebook(数据库对应的实体类)———-> EbookResp(服务器返回的类)

所以我们先创建req这个包,然后创建EbookReq.java,从用户的请求来看,只有可能需要传递id和name两个参数,所以内容如下(实际是拿Ebook类来做了剔除的工作):

  1. package com.taopoppy.wiki.req;
  2. public class EbookReq {
  3. private Long id;
  4. private String name;
  5. public Long getId() {
  6. return id;
  7. }
  8. public void setId(Long id) {
  9. this.id = id;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. @Override
  18. public String toString() {
  19. StringBuilder sb = new StringBuilder();
  20. sb.append(getClass().getSimpleName());
  21. sb.append(" [");
  22. sb.append("Hash = ").append(hashCode());
  23. sb.append(", id=").append(id);
  24. sb.append(", name=").append(name);
  25. sb.append("]");
  26. return sb.toString();
  27. }
  28. }

然后我们接着创建resp这个包,在此包下创建EbookResp这个类,这个类实际就是拷贝Ebook类,因为这个类的所有属性都可以暴露给用户,所以这里就不展示了。

然后我们EbookController文件就需要改一下了,这个时候返回的就是EbookResp的类型:

  1. @RestController
  2. @RequestMapping("/ebook")
  3. public class EbookController {
  4. @Resource
  5. private EbookService ebookService;
  6. @GetMapping("/list")
  7. public CommonResp list(EbookReq req) {
  8. // controller层尽量不要出现Ebook这个实体类
  9. // 因为实体类是和数据库一一对应的
  10. CommonResp<List<EbookResp>> resp = new CommonResp<>();
  11. List<EbookResp> list = ebookService.list(req);
  12. resp.setContent(list);
  13. return resp;
  14. }
  15. }

与此同时,我们要将从数据库查出的Ebook类型全部转换为EbookResp类型,所以EbookService.java内容如下:

  1. @Service
  2. public class EbookService {
  3. @Resource
  4. private EbookMapper ebookMapper;
  5. public List<EbookResp> list(EbookReq req) {
  6. EbookExample ebookExample = new EbookExample();
  7. // createCriteria相当于where条件
  8. EbookExample.Criteria criteria = ebookExample.createCriteria();
  9. criteria.andNameLike("%" + req.getName() + "%");
  10. // 根据ebookExample条件查询
  11. List<Ebook> ebooksList = ebookMapper.selectByExample(ebookExample);
  12. // 通过循环将通过Ebook类型查询的数据库数据 转换为 EbookResp类型数据转化出去
  13. List<EbookResp> respList = new ArrayList<>();
  14. for (Ebook ebook : ebooksList) {
  15. EbookResp ebookResp = new EbookResp();
  16. // 使用BeanUtils.copyProperties方法把对象属性拷贝到另一个里面
  17. BeanUtils.copyProperties(ebook, ebookResp);
  18. respList.add(ebookResp);
  19. }
  20. return respList;
  21. }
  22. }

3. 制作CopyUtil封装BeanUtils

通过上面的代码可以看到,对于Ebook和EbookResp转换的代码实际在后续很多地方都能用到,所以我们决定将其进行封装,创建一个util的包,然后创建CopyUtil.java,内容如下:

  1. package com.taopoppy.wiki.util;
  2. import org.springframework.beans.BeanUtils;
  3. import org.springframework.util.CollectionUtils;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. public class CopyUtil {
  7. /**
  8. * 单体复制
  9. */
  10. public static <T> T copy(Object source, Class<T> clazz) {
  11. if (source == null) {
  12. return null;
  13. }
  14. T obj = null;
  15. try {
  16. obj = clazz.newInstance();
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. return null;
  20. }
  21. BeanUtils.copyProperties(source, obj);
  22. return obj;
  23. }
  24. /**
  25. * 列表复制
  26. */
  27. public static <T> List<T> copyList(List source, Class<T> clazz) {
  28. List<T> target = new ArrayList<>();
  29. if (!CollectionUtils.isEmpty(source)){
  30. for (Object c: source) {
  31. T obj = copy(c, clazz);
  32. target.add(obj);
  33. }
  34. }
  35. return target;
  36. }
  37. }

上面的代码可以直接复制粘贴,因为是通用的,这样我们之前书写的代码就可以一行代替:

  1. public List<EbookResp> list(EbookReq req) {
  2. EbookExample ebookExample = new EbookExample();
  3. // createCriteria相当于where条件
  4. EbookExample.Criteria criteria = ebookExample.createCriteria();
  5. criteria.andNameLike("%" + req.getName() + "%");
  6. // 根据ebookExample条件查询
  7. List<Ebook> ebooksList = ebookMapper.selectByExample(ebookExample);
  8. // // 通过循环将通过Ebook类型查询的数据库数据 转换为 EbookResp类型数据转化出去
  9. // List<EbookResp> respList = new ArrayList<>();
  10. // for (Ebook ebook : ebooksList) {
  11. // // EbookResp ebookResp = new EbookResp();
  12. // // // 使用BeanUtils.copyProperties方法把对象属性拷贝到另一个里面
  13. // // BeanUtils.copyProperties(ebook, ebookResp);
  14. //
  15. // EbookResp ebookResp = CopyUtil.copy(ebook, EbookResp.class);
  16. //
  17. // respList.add(ebookResp);
  18. // }
  19. // 上面10-20的代码直接代替为这一行
  20. List<EbookResp> respList = CopyUtil.copyList(ebooksList, EbookResp.class);
  21. return respList;
  22. }

小技巧:如果代码改动了,但是出现莫名的错,可以试一下maven clean,比如:

  • 代码没错却编译出错
  • 测试结果和代码不符
  • 引入了jar包却没有反应