Spring Boot + MyBatis 初体验

Spring Boot makes it easy to create Spring-powered, production-grade applications and services with absolute minimum fuss. It takes an opinionated view of the Spring platform so that new and existing users can quickly get to the bits they need.



使用Spring开发的痛点在于复杂的XML配置文件,而Spring Boot解决了这个问题。

Spring Boot通过其框架中的大量的自动化配置简化了原Spring项目中繁杂的配置步骤,可以轻松快速地搭建起Web服务,使得开发可以更加专注于业务逻辑。

环境配置

要调试部署一个Spring Boot项目非常简单,具体需要的运行环境如下:

Java Development Kit

Oracle 最近更新了官方网站,现在下载安装 JDK 需要注册登录才可以了

官方声明的 LTS 版本为8和11,由于目前使用 JDK8 较多,所以选择 JDK8 进行安装

JetBrains IntellJ IDEA Ultimate

注意需要安装Ultimate版本

学生凭edu邮箱可以获得一年的免费正版认证

当然也可以用注册服务器白嫖

MySQL

推荐8.0以上版本,据官网介绍性能比5.7快2倍

Maven

其他一切依赖由Maven进行管理

如果使用IDEA就不必单独安装了,因为IDEA已经内置了Maven

快速开始

Spring Initializr 是Spring官方提供的在线全自动构建Spring Boot项目的工具,IDEA中的快速创建Spring Boot项目原理就是Spring Initializr

关于参数的说明:

  • “ GroupID “ 是项目组织唯一的标识符,实际对应 Java 的包结构,是 main 目录里 Java 的目录结构
  • “ ArtifactID “ 是项目的唯一的标识符,实际对应项目的名称,也就是项目根目录的名称
  • “ Type “ 可以简单理解为项目管理工具,可以选择 Maven或者 Gradle
  • “ Language “ 表示编程语言的选择,现在支持 Java 、Kotlin 和 Groovy
  • “ Packaging “ 表示项目的打包方式,有两种选择:Jar 和 War,在 Spring Boot 生成后,如果选用的方式不同,那么导入的打包插件也有区别
  • “ Java Version “ 表示 JDK 版本的选择
  • “ Version “ 是项目版本号,IDEA 默认为 0.0.1-SNAPSHOT,也可以自行修改

关于依赖的选择:

后期可以随意修改,根据个人需要进行选择,可以先选一个Spring Web


这样就很轻松地完成了Spring Boot项目的搭建,解压项目导入IDEA可以看到项目结构如下:

Maven 包地址默认在用户文件夹下的.m2中。

其中各种依赖由Maven自动下载导入,因此首次启动耗时较长。

右上角启动,简单暴力,默认端口号为8080,具体看输出信息:

能看到此页面说明项目已经正确配置,只不过还没有对具体请求作出具体处理,接下来配置控制器。

控制器

在 src/main/java/com.example.demo/ 下新建 Package 命名为 Controller,其中新建 Class 命名为 DemoController,如图所示:

我们这样定义控制器 DemoController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.demo.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class DemoController {
@GetMapping("/")
@ResponseBody
public String hello(){
return "Hello world";
}
}
//注意三个Annotation缺一不可,具体含义自行百度

重新启动项目,访问主页便可以看到控制器中定义的字符串了

模板引擎

不同于传统的JSP模式,使用例如Thymeleaf的模板引擎可以更好地做到前后端分离,因为对HTML中内容进行响应是通过数据+模板文件的方式进行的,不产生Class,不依赖Servlet,具有低耦合,高灵活性的优点。

这里我们使用Thymeleaf作为模板引擎:

安装

安装非常简单,将官方插件添加到pom.xml中,然后Maven解决一切

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

新建模板

在src/main/resources/templates/下新建模板echo.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Echo</title>
</head>
<body>
<div style="text-align: center">
<h1 th:text="${words}">复读机</h1>
</div>
</body>
</html>

配置控制器

回到Controller包,新建类EchoController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.demo;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;

@Controller
public class EchoController {
@GetMapping("/echo")
public String hello(HttpServletRequest request, @RequestParam(value = "words", required = false, defaultValue = "我是一个没有感情的复读机") String words) {
request.setAttribute("words", words);
return "echo";
}
}

尝试一下

再次运行项目,复读机启动成功


尝试与复读机进行交流(注意参数)


连接数据库

首先尝试MySQL + JDBC老哥俩

初始化配置

同样是使用Maven安装:

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

然后在src/main/resources/application.properties中添加JDBC相关配置:

1
2
3
4
5
6
spring.datasource.name=test
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&serverTimezone=GMT&characterEncoding=utf8&autoReconnect=true&useSSL=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123

需要注意在MySQL 8.0中需要手动设置时区才可以连接(上面的serverTimezone)

测试连接

在src/test/java/com/example/demo/DemoApplicationTests.java中添加测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootTest
class DemoApplicationTests {
@Autowired
private DataSource dataSource;

@Test
public void dataSourceTest() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection != null);
connection.close();
}

}

右键Run,查看测试结果

如果配置正确的话应该会测试通过

初始化数据库

搬出来上学期数据库课程里的例子实验一下

sid cid grade
201710001 10001 90
201720001 10001 90
201730001 10001 90
201730001 20001 88
201740001 10001 90
201750001 10001 90
201760001 10001 98
201760001 20001 60
201740001 30001 89
201720001 30001 93

在数据库test中新建表student,导入数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
USE DATABASE test;
DROP TABLE IF EXISTS `student`;

CREATE TABLE student(
sid char(20),
cid char(20),
grade char(20),
PRIMARY KEY (sid, cid));

INSERT INTO student VALUES
("201710001", "10001", "90"),
("201720001", "10001", "90"),
("201730001", "10001", "90"),
("201730001", "20001", "88"),
("201740001", "10001", "90"),
("201750001", "10001", "90"),
("201760001", "10001", "98"),
("201760001", "20001", "60"),
("201740001", "30001", "89"),
("201720001", "30001", "93");

配置控制器

接下来写控制器,实现 “SELECT *” 和 “INSERT INTO”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.demo.Controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
public class JdbcController {
//自动注入
@Autowired
JdbcTemplate jdbcTemplate;

// 查询所有记录
@GetMapping("/queryAll")
public List<Map<String, Object>> queryAll() {
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from student");
return list;
}

// 新增一条记录
@GetMapping("/insert")
public Object insert(String sid, String cid, String grade) {
if (StringUtils.isEmpty(sid) || StringUtils.isEmpty(cid)||StringUtils.isEmpty(grade)) {
return false;
}
jdbcTemplate.execute("insert into student value (\"" + sid + "\",\"" + cid + "\",\""+grade+"\")");
return true;
}
}

启动项目

首先尝试查询所有人的信息

访问http://localhost:8080/queryAll,成功查询到所有键值:


接下来将导入雷同学

访问http://localhost:8080/insert?sid=这tm的&cid=绝对是捣乱的&grade=是吧

网站返回true即插入成功

再次查询全部键值:

整合MyBatis

MyBatis 是Apache社区的开源项目(Apache nb !)

它避免了JDBC繁琐的手动设置参数和手动获取结果的问题,使得开发能更高效注重于业务本身

真正使得Java代码与SQL代码分离

安装

MyBatis-Spring-Boot-Starter 是MyBatis官方开发的Spring Boot 插件,同样Maven搞定

1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>

配置

在src/main/resources/application.properties中添加MyBatis相关配置:

在JDBC配置的最后加上一行:

1
mybatis.mapper-locations=classpath:mapper/*Dao.xml

即MyBatis的Mapper文件的路径


然后在启动类中添加一行@MapperScan注解

1
@MapperScan("com.example.demo.dao")

这样Spring Boot项目启动之后会自动扫描com.example.demo.dao下的Mapper接口

数据库

依旧使用上文的test.student

实体类

在src/main/java/com/example/demo/下新建Package “entity”

然后在entity下新建类Student:

只需要写变量然后Generate getter() and setter()就可以自动生成所有方法了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.example.demo.entity;

public class Student {
private String sid;
private String cid;
private String grade;

public Student(String sid, String cid, String grade) {
this.cid = cid;
this.sid = sid;
this.grade = grade;
}

public String getSid() {
return sid;
}

public void setSid(String sid) {
this.sid = sid;
}

public String getCid() {
return cid;
}

public void setCid(String cid) {
this.cid = cid;
}

public String getGrade() {
return grade;
}

public void setGrade(String grade) {
this.grade = grade;
}
}

Mapper接口

在src/main/java/com/example/demo/下新建Package “dao”

然后在dao下新建接口StudentDao,定义增删查改四个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.example.demo.dao;

import com.example.demo.entity.Student;

import java.util.List;

public interface StudentDao {
/**
* 返回数据列表
*
* @return
*/
List<Student> findAllStudents();

/**
* 添加
*
* @param student
* @return
*/
int insertStudent(Student student);

/**
* 修改
*
* @param student
* @return
*/
int updateStudent(Student student);

/**
* 删除
*
* @param student
* @return
*/
int deleteStudent(Student student);
}

映射

在src/main/resources/下新建mapper文件夹,在mapper下新建映射文件StudentDao.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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.example.demo.dao.StudentDao">

<!--配置表结构和实体类的关系-->
<resultMap type="com.example.demo.entity.Student" id="StudentResult">
<result property="sid" column="sid"/>
<result property="cid" column="cid"/>
<result property="grade" column="grade"/>
</resultMap>

<!--对应接口的方法写SQL-->
<select id="findAllStudents" resultMap="StudentResult">
select sid,cid,grade from student
order by sid desc
</select>
<insert id="insertStudent" parameterType="com.example.demo.entity.Student">
insert into student(sid,cid,grade)
values(#{sid},#{cid},#{grade})
</insert>
<update id="updateStudent" parameterType="com.example.demo.entity.Student">
update student
set grade=#{grade}
where sid=#{sid} and cid=#{cid}
</update>
<delete id="deleteStudent" parameterType="com.example.demo.entity.Student">
delete from student where sid=#{sid} and cid=#{cid}
</delete>
</mapper>

配置控制器

现在需要配置控制器来接收参数并处理

在com.example.demo.controller下新建StudentController类,实现接口中的四个方法

在每个方法中做如下处理:

  • 验证参数是否完整
  • 返回Query是否OK
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.demo.Controller;

import com.example.demo.dao.StudentDao;
import com.example.demo.entity.Student;
import org.springframework.util.StringUtils;
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 StudentController {

@Resource
StudentDao studentDao;

@GetMapping("/student/queryAll")
public List<Student> queryAll() {
return studentDao.findAllStudents();
}

@GetMapping("/student/insert")
public Boolean insert(String sid, String cid, String grade) {
if (StringUtils.isEmpty(sid) || StringUtils.isEmpty(cid) || StringUtils.isEmpty(grade)) {
return false;
}
Student student = new Student(sid, cid, grade);
return studentDao.insertStudent(student) > 0;
}

@GetMapping("/student/update")
public Boolean update(String sid, String cid, String grade){
if (StringUtils.isEmpty(sid) || StringUtils.isEmpty(cid) || StringUtils.isEmpty(grade)) {
return false;
}
Student student = new Student(sid, cid, grade);
return studentDao.updateStudent(student) > 0;
}

@GetMapping("/student/delete")
public Boolean delete(String sid, String cid){
if (StringUtils.isEmpty(sid) || StringUtils.isEmpty(cid)) {
return false;
}
Student student = new Student(sid, cid, "");
return studentDao.deleteStudent(student) > 0;
}
}

启动项目

分别访问查看是否正常运行,效果如图所示 ~

queryAll

insert

update

delete