现在开始我们需要学习一下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打开就行。
第二种方法就是打开IDEA然后创建一个spring项目,整个流程和你在官网选择几乎一样,但是IDEA2021没有创建spring boot项目这个选择。
2. Spring Boot目录结构
- 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文件,然后右键运行即可
@SpringBootApplication
public class WikiApplication {
public static void main(String[] args) {
SpringApplication.run(WikiApplication.class, args);
}
}
4. 总结知识点
- SpringBoot不需要配置容器,是因为使用了嵌入式容器,可以在包当中看到项目本身有org.apache.tomcat.embed,所以也是默认使用tomcat启动。也可以使用传统的方式,打包成war包,放在单独的tomcat当中也是可以的。
- SpringBoot的启动函数需要添加@SpringBootApplication注解
项目初始配置
1. 编码配置
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是需要自己创建的,内容如下;
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!--本地仓库位置-->
<localRepository>C:\Users\Administrator\.m2\repository</localRepository>
<pluginGroups/>
<proxies/>
<servers>
</servers>
<mirrors>
<!--阿里云的镜像-->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
<!--中央仓库在中国的位置-->
<mirror>
<id> maven-net-cn</id>
<name> Maven China Mirror</name>
<url> http://maven.net.cn/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<profiles>
<!--配置jdk的版本-->
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</settings>
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,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 修改一下路径-->
<property name="PATH" value="./log"></property>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>-->
<Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>
</encoder>
</appender>
<appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${PATH}/trace.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${PATH}/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
</layout>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${PATH}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${PATH}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="ERROR">
<appender-ref ref="ERROR_FILE" />
</root>
<root level="TRACE">
<appender-ref ref="TRACE_FILE" />
</root>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
修改
2. 增加启动成功日志
我们现在来修改一下启动文件:
@SpringBootApplication
public class WikiApplication {
private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
public static void main(String[] args) {
SpringApplication app = new SpringApplication(WikiApplication.class);
Environment env = app.run(args).getEnvironment();
LOG.info("启动成功");
LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
}
}
其中我们需要在application.properties当中书写下面的代码:
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当中:
@RestController
public class TestController {
@GetMapping("/hello")
// @PutMapping
// @DeleteMapping
// @PostMapping
// @RequestMapping(value = "user/1", method = RequestMethod.GET)
public String hello() {
return "Hello World";
}
}
- @RestController 这个注解是表示返回的是字符串或者JSON对象
- @GetMapping表示该结构只能由get方法访问,同理@PutMapping、@DeleteMapping、@PostMapping都是如此
- @RequestMapping()这个方法有两个参数,如果直接书写@RequestMapping(“/hello”)表示这个方法支持所有请求方式,但是@RequestMapping(value = “hello”, method = RequestMethod.GET)和@GetMapping(“/hello”)是一样的效果。
2. 修改启动位置
注意正常的启动文件会有@SpringBootApplication这样一个注解,表示启动注解,源码当中它是包含@ComponentScan的注解,这个是扫描的意思,启动类会自动扫描当前启动类所在的文件,将里面的接口文件全部扫描到。
但是现在如果直接把启动文件放在这样的一个位置,如下图:
那么WikiApplication实际上扫描不到TestController这个接口类的,因为不在一个文件内,所以要想让WikiApplicaiton扫描到接口文件就要修改@ComponentScan的扫描范围,因为config文件夹和controller文件夹都在com.taopoppy.wiki当中,所以书写@ComponentScan(“com.taopoppy”)或者@ComponentScan(“com.taopoppy.wiki”)都是可以的。
@ComponentScan("com.taopoppy")
@SpringBootApplication
public class WikiApplication {
private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
public static void main(String[] args) {
SpringApplication app = new SpringApplication(WikiApplication.class);
Environment env = app.run(args).getEnvironment();
LOG.info("启动成功");
LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
}
}
如果扫描多个包可以这样书写:
@ComponentScan("com.taopoppy","com.test")
配置文件介绍
1. 默认支持的配置文件
spring boot的配置项是在resources当中,但是下面三种都是可以的,只不过写法不同
- resources/application.properties
- resources/config/application.properties
- resources/application.yml
两种不同的文件写法不一样,可以在https://toyaml.com/index.html进行转换:
2. 自定义配置项
自定义配置项就是在application.properties当中书写自己的一些自定义的配置项,然后在其他地方可以直接使用,比如我们在application.properties当中去书写一个这样的代码:
author.name=taopoppy
然后在代码当中可以这样使用:
@RestController
public class TestController {
@Value("${author.name: xiaoming}")
private String name; // 通过@Value注解拿到author.name的值taopoppy,如果我们没有配置就取默认值xiaoming
@GetMapping("/hello")
public String hello() {
return name; // 作为接口结果返回出去
}
}
集成热部署
1. 添加依赖
在pom.xml当中添加下面的代码,不需要带版本号,因为这个是spring内置的一个模块:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
2. 开启静态编译
3. 开启动态编译
双击Shift进行搜索,搜索Registry,找到下面的图标,在红色方框处勾选即可。
这样我们在修改文件的时候,随时进行修改后,点击Ctrl+S或者Ctrl+F9(工具栏的小锤子按钮:Build project),项目就已经重新热启动了,速度要比自己重启快很多。
IDEA关联数据库
mysql和navicat的安装这里就不多说了,安装好之后,我们使用navicat连接好mysql之后,新建一个数据库,注意要选择utf8mb4,这个是真正的utf8,可以存放表情符号:
1. 新建用户
接下来我们要创建一个专属访问wiki这个数据库的用户,因为root的权限太大了,并不安全。
上面我输入的密码是123456,然后我们在配置一下权限
然后返回到用户界面就可以看到wiki@localhost这个新的用户了,接着使用这个新的用户去连接本地的数据库,点击新建:
2. 新建表
然后在点击保存后输入表名test即可,这样我们就新建了一个test的表。
3. 阿里云数据库的准备
在阿里云的产品-> 数据库-> 云数据库 RDS MySql版,点击立即购买:
然后下一步的实例配置基本不用动,为默认配置,然后下单支付即可,但是要注意的是:后续还要购买服务器ECS,ECS和RDS之间的访问要配置成内网访问,需要购买在同一个地域
- 接着我们进入到阿里云控制台首页
- 找到产品与服务
- 在最近使用产品当中找到云数据库 RDS版
- 进入之后,在左边侧边栏当中找到实例列表,并在最上面导航栏里选择你刚买的RDS的地域,我买的是华北5(呼和浩特)
- 然后显示出实例后,我们点击实例最右侧的管理
- 进入后在左侧边栏当中选择账号管理,然后选择创建账号
- 数据库账号:wiki
- 账号类型:普通账号
- 密码:tao3941319=-=
- 然后在左侧边栏当中选择数据库管理,然后点击创建数据库:
- 数据库(DB)名称:wiki
- 支持字符集:utf8
- 授权账号:wiki(普通账号)
- 账号类型:读写
- 然后在上面找到登录数据库,输入上面我们创建的数据库账号和密码,然后测试连接即可
测试成功之后,我们回到实例,点击实例一栏最左侧的地址,进入之后有两个地址
如果能从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
然后在view -> Tools Windows ->DB Browser,然后创建一个新的,特别注意我们这里只是配置了本地的,如果你配置阿里云的话,Host就要填外网地址。<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
友情提示,在阿里云外网地址和内网地址默认是显示不出来的,必须先要设置白名单,白名单默认是127.0.0.1,即禁止一切其他访问,变成0.0.0.0/0才能允许其他一切访问。
集成Mybatis
1. 集成mybatis
简单的说:和数据库打交道的这一层就是持久层,常见的持久层有Mybatis、Hibernate、前者是半自动的,后者是全自动,半自动就是需要自己写sql,全自动就是不需要写sql。我们首先在pom.xml添加依赖:
<!--集成mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--集成mysql连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
添加了mybatis,我们需要到application.properties当中去配置数据源:
# 增加数据库连接
spring.datasource.url=jdbc:mysql://rm-hp3f05153598ck3e5vo.mysql.huhehaote.rds.aliyuncs.com/wiki?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=wiki
spring.datasource.password=***** # 这里是我自己的密码
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;
private String name;
private String password;
// 下面代码直接右键Genetater->Getter and Setter生成
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<br />
<a name="A702R"></a>
#### (2)mapper(持久层)
**持久层叫Mapper层,即广为人知的Dao层,因为后续要用官方代码生成器,其生成的代码就是XXXMapper**<br />所以我们现在来写一个接口:
- 在com.taopoppy.wiki下面新建一个mapper的package
- 在mapper下面新建一个interface:TestMapper,内容如下:
```java
package com.taopoppy.wiki.mapper;
import com.taopoppy.wiki.domain.Test;
import java.util.List;
public interface TestMapper {
public List<Test> list();
}
然后我们去书写关于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“ >
接着我们需要做两个配置,因为你写了mapper和xml的sql,但是项目不认识:
- 在config/WikiApplication当中配置扫描mapper持久层文件
```java
@ComponentScan("com.taopoppy")
@SpringBootApplication
@MapperScan("com.taopoppy.wiki.mapper") # 这里配置
public class WikiApplication {
private static final Logger LOG = LoggerFactory.getLogger(WikiApplication.class);
public static void main(String[] args) {
SpringApplication app = new SpringApplication(WikiApplication.class);
Environment env = app.run(args).getEnvironment();
LOG.info("启动成功");
LOG.info("地址:\thttp://127.0.0.1:{}", env.getProperty("server.port"));
}
}
在resources/application.properties当中配置mybatis的xml路径,其中classpath就是resources,/*/.xml表示mapper文件夹下的所有xml文件。
# 配置mybatics所有Mapper.xml所在的路径
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;
public List<Test> list() {
return testMapper.list();
}
}
<a name="G1Kof"></a>
#### (4)controller(控制层)
最后我们就要在controller这个包下面创建:TestController,内容如下:
```java
package com.taopoppy.wiki.controller;
import com.taopoppy.wiki.domain.Test;
import com.taopoppy.wiki.service.TestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
public class TestController {
@Resource
private TestService testService;
@GetMapping("/test/list")
public List<Test> list() {
return testService.list();
}
}
整个接口调用的顺序是:
- controller -> service ->mapper -> resources/mapper
此时,可以正常调用http://127.0.0.1:8081/test/list
Mybatis Generator使用
1. mybatis generator的集成
通过上面的代码可以看出来,写一个接口实在是太麻烦,然后我们可以使用mybitis的官方生成器,首先在pom.xml当中去粘贴下面的代码到plugins处:
<!-- mybatis generator 自动生成代码插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<configurationFile>src/main/resources/generator/generator-config.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
</dependencies>
</plugin>
然后我们要自己生成一个src/main/resources/generator/generator-config.xml文件,注意复制粘贴后需要修改对应的东西:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- 自动检查关键字,为关键字增加反引号 -->
<property name="autoDelimitKeywords" value="true"/>
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!--覆盖生成XML文件-->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
<!-- 生成的实体类添加toString()方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<!-- 不生成注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://rm-hp3f05153598ck3e5vo.mysql.huhehaote.rds.aliyuncs.com:3306/wikidev?serverTimezone=Asia/Shanghai"
userId="wikidev"
password="tao3941319=-=">
</jdbcConnection>
<!-- domain类的位置 -->
<javaModelGenerator targetProject="src\main\java"
targetPackage="com.taopoppy.wiki.domain"/>
<!-- mapper xml的位置 -->
<sqlMapGenerator targetProject="src\main\resources"
targetPackage="mapper"/>
<!-- mapper类的位置 -->
<javaClientGenerator targetProject="src\main\java"
targetPackage="com.taopoppy.wiki.mapper"
type="XMLMAPPER"/>
<table tableName="demo" domainObjectName="Demo"/>
</context>
</generatorConfiguration>
注意:上述文件当中的table里面写的demo,前提我们要在连接的数据库当中提前创建好这个demo的表。后面生成的文件全是关于这个demo表的,如果生成其他相关表的代码就要改这里的tableName的值。
在启动符号的左边下拉框当中找到:Edit Configurations,然后新增一个maven的configuration:
然后我们去执行一下这个configuration:
接着就会创建出响应的代码,在domain生成了Demo.java和DemoExample.java,在mapper下面生成了DemoMapper,在resources/mapper下面生成了DemoMapper.xml。请注意:这四个文件我们以后都不要动
2. mybatis generator的使用
现在我们先在sercvice下面创建一个DemoService文件,内容如下:
package com.taopoppy.wiki.service;
import com.taopoppy.wiki.domain.Demo;
import com.taopoppy.wiki.mapper.DemoMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class DemoService {
@Resource
private DemoMapper demoMapper;
public List<Demo> list() {
// 传null表示查所有的表数据
return demoMapper.selectByExample(null);
}
}
然后在controller当中创建DemoController.java,内容如下:
package com.taopoppy.wiki.controller;
import com.taopoppy.wiki.domain.Demo;
import com.taopoppy.wiki.service.DemoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Resource
private DemoService demoService;
@GetMapping("/list")
public List<Demo> list() {
return demoService.list();
}
}
这样的话,我们就可以在http/demo.http文件下书写这样的请求去测试:
GET http://localhost:8081/demo/list
统一规范
1. 电子书列表查询开发
先执行一下下面的代码,在ebook表创造点数据:
drop table if exists `ebook`;
create table `ebook` (
`id` bigint not null comment 'id',
`name` varchar(50) comment '名称',
`category1_id` bigint comment '分类1',
`category2_id` bigint comment '分类2',
`description` varchar(200) comment '描述',
`cover` varchar(200) comment '封面',
`doc_count` int comment '文档数',
`view_count` int comment '阅读数',
`vote_count` int comment '点赞数',
primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='电子数';
insert into `ebook` (id, name, description) values (1, 'Spring Boot 入门教程','零基础入门Java开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (2, 'Vue 入门教程','零基础入门 Vue 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (3, 'Python 入门教程','零基础入门 Python 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (4, 'Mysql 入门教程','零基础入门 Mysql 开发,企业级应用开发最佳首选框架');
然后我们修改generator-config.xml文件,修改最下面的table标签:
然后回到上面去执行一下我们之前生成的名字叫做mybatis-generator的configration,生成ebook相关的持久层代码。
然后就去书写service和controller层的代码(直接粘贴复制以前的代码,然后对应的关键词修改成为ebook或者Ebook即可):
package com.taopoppy.wiki.service;
import com.taopoppy.wiki.domain.Ebook;
import com.taopoppy.wiki.mapper.EbookMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class EbookService {
@Resource
private EbookMapper ebookMapper;
public List<Ebook> list() {
// 传null表示查所有的表数据
return ebookMapper.selectByExample(null);
}
}
package com.taopoppy.wiki.controller;
import com.taopoppy.wiki.domain.Ebook;
import com.taopoppy.wiki.service.EbookService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/ebook")
public class EbookController {
@Resource
private EbookService ebookService;
@GetMapping("/list")
public List<Ebook> list() {
return ebookService.list();
}
}
然后我们去http/ebook.http当中测试GET http://localhost:8081/ebook/list即可
由于后端会有很多接口,为了让前端能够统一处理逻辑(比如登录校验,权限校验),需要统一后端的返回值,所以我们需要自己制作一个统一的类,在com.taopoppy.wiki.resp的CommonResp内容如下:
package com.taopoppy.wiki.resp;
public class CommonResp<T> {
/**
* 业务上的成功或失败
*/
private boolean success = true;
/**
* 返回信息
*/
private String message;
/**
* 返回泛型数据,自定义类型
*/
private T content;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
然后我们在EbookController返回值当中就可以这样写(特别要注意泛型):
@GetMapping("/list")
public CommonResp list() {
CommonResp<List<Ebook>> resp = new CommonResp<>();
List<Ebook> list = ebookService.list();
resp.setContent(list);
return resp;
}
2. 封装请求参数和返回参数
我们先来做一个模糊查询的功能,比如我们在EbookController.java当中修改一下代码:
@GetMapping("/list")
public CommonResp list(String name) { # 传递name参数进去
CommonResp<List<Ebook>> resp = new CommonResp<>();
List<Ebook> list = ebookService.list(name);
resp.setContent(list);
return resp;
}
接着修改EbookService.java当中的代码:
public List<Ebook> list(String name) {
// 创建一个Ebookexample的查询实例
EbookExample ebookExample = new EbookExample();
// createCriteria相当于where条件
EbookExample.Criteria criteria = ebookExample.createCriteria();
criteria.andNameLike("%" + name + "%");
// 根据ebookExample条件查询
return ebookMapper.selectByExample(ebookExample);
}
接着我们可以通过GET http://localhost:8081/ebook/list?name=Spring 这种方式进行模糊查询
但是由于我们还有其他参数需要传递,所以我们不可能每一个参数都要书写一遍,所以我们需要将请求参数封装成一个类,另外我们之前书写的Ebook类是和数据库一一对应的,比如说如果是用户登录,我们不能将User当中的所有属性返回,因为密码也在里面,所以应该只将部分属性返回,也就必须创建一个返回类:
- EbookReq(用户请求的类)——-> Ebook(数据库对应的实体类)———-> EbookResp(服务器返回的类)
所以我们先创建req这个包,然后创建EbookReq.java,从用户的请求来看,只有可能需要传递id和name两个参数,所以内容如下(实际是拿Ebook类来做了剔除的工作):
package com.taopoppy.wiki.req;
public class EbookReq {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", name=").append(name);
sb.append("]");
return sb.toString();
}
}
然后我们接着创建resp这个包,在此包下创建EbookResp这个类,这个类实际就是拷贝Ebook类,因为这个类的所有属性都可以暴露给用户,所以这里就不展示了。
然后我们EbookController文件就需要改一下了,这个时候返回的就是EbookResp的类型:
@RestController
@RequestMapping("/ebook")
public class EbookController {
@Resource
private EbookService ebookService;
@GetMapping("/list")
public CommonResp list(EbookReq req) {
// controller层尽量不要出现Ebook这个实体类
// 因为实体类是和数据库一一对应的
CommonResp<List<EbookResp>> resp = new CommonResp<>();
List<EbookResp> list = ebookService.list(req);
resp.setContent(list);
return resp;
}
}
与此同时,我们要将从数据库查出的Ebook类型全部转换为EbookResp类型,所以EbookService.java内容如下:
@Service
public class EbookService {
@Resource
private EbookMapper ebookMapper;
public List<EbookResp> list(EbookReq req) {
EbookExample ebookExample = new EbookExample();
// createCriteria相当于where条件
EbookExample.Criteria criteria = ebookExample.createCriteria();
criteria.andNameLike("%" + req.getName() + "%");
// 根据ebookExample条件查询
List<Ebook> ebooksList = ebookMapper.selectByExample(ebookExample);
// 通过循环将通过Ebook类型查询的数据库数据 转换为 EbookResp类型数据转化出去
List<EbookResp> respList = new ArrayList<>();
for (Ebook ebook : ebooksList) {
EbookResp ebookResp = new EbookResp();
// 使用BeanUtils.copyProperties方法把对象属性拷贝到另一个里面
BeanUtils.copyProperties(ebook, ebookResp);
respList.add(ebookResp);
}
return respList;
}
}
3. 制作CopyUtil封装BeanUtils
通过上面的代码可以看到,对于Ebook和EbookResp转换的代码实际在后续很多地方都能用到,所以我们决定将其进行封装,创建一个util的包,然后创建CopyUtil.java,内容如下:
package com.taopoppy.wiki.util;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
public class CopyUtil {
/**
* 单体复制
*/
public static <T> T copy(Object source, Class<T> clazz) {
if (source == null) {
return null;
}
T obj = null;
try {
obj = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BeanUtils.copyProperties(source, obj);
return obj;
}
/**
* 列表复制
*/
public static <T> List<T> copyList(List source, Class<T> clazz) {
List<T> target = new ArrayList<>();
if (!CollectionUtils.isEmpty(source)){
for (Object c: source) {
T obj = copy(c, clazz);
target.add(obj);
}
}
return target;
}
}
上面的代码可以直接复制粘贴,因为是通用的,这样我们之前书写的代码就可以一行代替:
public List<EbookResp> list(EbookReq req) {
EbookExample ebookExample = new EbookExample();
// createCriteria相当于where条件
EbookExample.Criteria criteria = ebookExample.createCriteria();
criteria.andNameLike("%" + req.getName() + "%");
// 根据ebookExample条件查询
List<Ebook> ebooksList = ebookMapper.selectByExample(ebookExample);
// // 通过循环将通过Ebook类型查询的数据库数据 转换为 EbookResp类型数据转化出去
// List<EbookResp> respList = new ArrayList<>();
// for (Ebook ebook : ebooksList) {
// // EbookResp ebookResp = new EbookResp();
// // // 使用BeanUtils.copyProperties方法把对象属性拷贝到另一个里面
// // BeanUtils.copyProperties(ebook, ebookResp);
//
// EbookResp ebookResp = CopyUtil.copy(ebook, EbookResp.class);
//
// respList.add(ebookResp);
// }
// 上面10-20的代码直接代替为这一行
List<EbookResp> respList = CopyUtil.copyList(ebooksList, EbookResp.class);
return respList;
}
小技巧:如果代码改动了,但是出现莫名的错,可以试一下maven clean,比如:
- 代码没错却编译出错
- 测试结果和代码不符
- 引入了jar包却没有反应