数据库准备
本地数据库准备
在本地使用navicat 添加本地数据库连接:
创建一个wiki数据库:
创建一个专用的账户:
配置权限设置单个库的权限:
通过这个用户名创建数据库的连接:
然后就能操作数据库了
阿里云数据库准备
略
IDEA数据库插件配置
使用IDEA右侧的Database创建连接:
输入账号密码测试连接(如果是首次连接可能需要下载驱动 看看报错有没有提示下载):
之后我们就可以直接操作数据库和查看数据库:
如果我们使用可视化界面来操作数据库,例如增加数据等,我们需要提交事物,否则数据库不会改变:
集成持久层框架Mybatis
Hibernate:全自动的框架,强大、复杂、笨重、学习成本较高。
Mybatis:半自动的框架(需要开发者了解数据库),必须要自己写SQL
集成Mybatis
添加依赖:
<!-- 集成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>
此时我们运行代码会报错,是因为没有找到数据源,所以得我们自己去application.properties中配置数据源:
演示查询test表
我们在wiki目录下新增一个包domain(可以叫domain或entity或POJO,宗旨这一层实体类就是和数据库表一一映射)
我们在domain包中创建一个Test:
接下来我们创建持久层(Mapper层)即广为人知的Dao层,因为后需要用官方代码生成器,其生成的代码就是XXXMapper:
创建TestMapper接口返回一个Test的List:
我们在resource下创建一个mapper,以后所有的sql脚本全部放在该文件夹下:
编写一个对应刚刚的接口的xml文件TestMapper.xml,其中namespace要和接口文件对应,id对应接口中的方法名,resultType为返回的实体类:
<?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 namespace="com.jiawa.wiki.mapper.TestMapper" >
<select id="list" resultType="com.jiawa.wiki.domain.Test">
select `id`, `name`, `password` from `test`
</select>
</mapper>
这里推荐一款插件(能够快速从代码跳转到mapper及从mapper返回代码):
那么项目怎么知道Mapper就是持久层呢,我们需要在启动类添加扫描注解(MapperScan):
整个项目怎么知道XML就是要执行的SQL 呢?
我们 需要在项目的配置文件(application.properties)配置mybatis所有Mapper.xml所在的路径:
接下来我们演示如何使用持久层:
我们创建一个service包,服务层中编写逻辑(注解不要漏,@service是提供给系统扫描的):
@Service
public class TestService {
@Resource
private TestMapper testMapper;
public List<Test> list() {
return testMapper.list();
}
}
接下来我们在TestController里编写接口,先注入TestService:
再编写接口:
测试:
集成Mybatis官方代码生成器
集成MybatisGenerator
通过我们之前编写的查询test表的代码我们可以看出还是比较繁琐的,这时候我们就可以使用MybatisGenerator简化开发。
在配置文件中添加插件:
<!-- 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>
创建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-uf6470s9615e13hc4no.mysql.rds.aliyuncs.com:3306/wikidev?serverTimezone=Asia/Shanghai"
userId="wikidev"
password="wikidevABC123">
</jdbcConnection>
<!-- domain类的位置 -->
<javaModelGenerator targetProject="src\main\java"
targetPackage="com.jiawa.wiki.domain"/>
<!-- mapper xml的位置 -->
<sqlMapGenerator targetProject="src\main\resources"
targetPackage="mapper"/>
<!-- mapper类的位置 -->
<javaClientGenerator targetProject="src\main\java"
targetPackage="com.jiawa.wiki.mapper"
type="XMLMAPPER"/>
<!--<table tableName="demo" domainObjectName="Demo"/>-->
<!--<table tableName="ebook"/>-->
<!--<table tableName="category"/>-->
<!--<table tableName="doc"/>-->
<!--<table tableName="content"/>-->
<!--<table tableName="user"/>-->
<table tableName="ebook_snapshot"/>
</context>
</generatorConfiguration>
演示demo表列表查询
接下来我们添加一个configuration
选择maven:
然后运行我们就发现自动生成了一些文件我们就可以直接使用了:
编写服务层代码:
@Service
public class DemoService {
@Resource
private DemoMapper demoMapper;
public List<Demo> list() {
return demoMapper.selectByExample(null);
}
}
编写接口:
@RestController
@RequestMapping("/demo")
public class DemoController {
@Resource
private DemoService demoService;
@GetMapping("/list")
public List<Demo> list() {
return demoService.list();
}
}
测试:
电子书列表查询接口开发
电子书表结构设计
使用代码生成器快速开发列表接口
在generator-config中添加table:
运行mybatis-generator,自动生成持久层代码。
编写服务层代码:
编写controller:
测试:
后端会有很多接口,为了让前端能够统一处理逻辑(登录校验、权限校验),需要统一后端的返回值。
新建resp包:
编写通用的返回类:
public class CommonResp<T> {
/**
* 业务上的成功或失败
*/
private boolean success = true;
/**
* 返回信息
*/
private String message;
/**
* 返回泛型数据,自定义类型
*/
private T content;
public boolean getSuccess() {
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;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("ResponseDto{");
sb.append("success=").append(success);
sb.append(", message='").append(message).append('\'');
sb.append(", content=").append(content);
sb.append('}');
return sb.toString();
}
}
实际工作中,有些项目会在CommonResp里加上其他通用的属性,比如接口版本号、返回码等。
封装请求参数和返回参数
根据名称模糊查询电子书
例如我们根据电子书名字模糊查询
修改service代码(使用插件给我们自动生成的Example类):
左匹配和右匹配,左右都加%,最后再把创建好的example用于查询。
测试:
封装请求参数
我们通常不会直接使用name去查询,因为后续迭代可能有新的需求,所以我们一般将所有参数封装成一个类。
创建一个包req:
新建电子书查询请求的类:
修改controller和service:
热部署启动后我们使用刚刚编写的测试类,测试发现依旧能请求成功,我们虽然请求参数封装了,但Sprin会自动将参数映射到类属性,只要属性名和请求参数的时候的名字一样就行。
封装返回参数
我们当前接口编写的返回参数为整个Ebook,但是有时候我们的业务并不需要返回整个类,例如:
创建一个Ebook的返回参数类:
同样需要修改service层代码:
这样直接用set写比较麻烦,所以我们可以直接使用spring提供的工具类:
修改controller:
热部署项目,测试成功:
制作CopyUtil封装BeanUtils
就在之前我们使用Spring提供的BeanUtils简化了代码,但还是有些繁琐,要写循环语句等:
所以我们一般会提取公用的东西封装工具类,创建一个工具类的包util:
编写CopyUtil:
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;
}
}
修改service层:
修改完后我们重新编译,发现报错,但是代码没问题,这时候我们可以clean一下,因为maven可能存在编译缓存:
总结