pom.xml如下所示
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
mysql
mysql-connector-java
runtime
com.baomidou
mybatis-plus-boot-starter
3.1.2
org.springframework.boot
spring-boot-starter-test
test
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springboot-learning?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
# 设置mybatis-plus
mybatis-plus.mapper-locations=classpath:mapper/*.xml
#实体扫描,多个package用逗号或者分号分隔
mybatis-plus.type-aliases-package=com.example.springbootchapter4.entity
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名),
# 自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
mybatis-plus.configuration.map-underscore-to-camel-case=true
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
#mybatis-plus.global-config.id-type=0
#打印sql日志
logging.level.com.example.springbootchapter4.mapper=debug
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
@SpringBootApplication
@MapperScan("com.example.springbootchapter4.mapper")
public class SpringbootChapter4Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootChapter4Application.class, args);
}
}
package com.example.springbootchapter4.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* Created by lzc
* 2019/8/3 15:45
*/
@Data
@TableName("student")
public class Student {
//主键id,如果是自增id,需要使用这个注解
@TableId(type = IdType.AUTO)
private Long id;
// 学生姓名
private String studentName;
// 学生姓名
private String gender;
// 班级名称
private String className;
// 学生年龄
private Integer age;
// 学生所在城市
private String cityName;
// 创建时间
private Date createTime;
// 更新时间
private Date updateTime;
}
创建好实体类后,在数据库中创建实体类所对应的数据表
CREATE TABLE `student` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` int(11) NULL DEFAULT NULL,
`city_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`student_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
package com.example.springbootchapter4.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootchapter4.entity.Student;
/**
* Created by lzc
* 2019/8/3 15:43
*/
public interface StudentMapper extends BaseMapper<Student> {
}
可以发现,我们自己创建的StudentMapper什么东西都没有写,只是继承了com.baomidou.mybatisplus.core.mapper.BaseMapper接口,查看BaseMapper接口的源码可以发现,BaseMapper接口为我们提供了很多现成接口供我们使用。一行代码也不用写,那么针对 StudentMapper,已经拥有下面的功能:
public interface BaseMapper<T> {
/**
*
* 插入一条记录
*
*
* @param entity 实体对象
*/
int insert(T entity);
/**
*
* 根据 ID 删除
*
*
* @param id 主键ID
*/
int deleteById(Serializable id);
/**
*
* 根据 columnMap 条件,删除记录
*
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
*
* 根据 entity 条件,删除记录
*
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 删除(根据ID 批量删除)
*
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
*
* 根据 ID 修改
*
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
/**
*
* 根据 whereEntity 条件,更新记录
*
*
* @param entity 实体对象 (set 条件值,不能为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
*
* 根据 ID 查询
*
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
*
* 查询(根据ID 批量查询)
*
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
*
* 查询(根据 columnMap 条件)
*
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
*
* 根据 entity 条件,查询一条记录
*
*
* @param queryWrapper 实体对象
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 Wrapper 条件,查询总记录数
*
*
* @param queryWrapper 实体对象
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 entity 条件,查询全部记录
*
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 Wrapper 条件,查询全部记录
*
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 Wrapper 条件,查询全部记录
* 注意: 只返回第一个字段的值
*
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 entity 条件,查询全部记录(并翻页)
*
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
*
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
因为在查询的时候需要用到分页插件,所以还需要设置分页插件,新建MybatisPlusConfig类
@EnableTransactionManagement
@Configuration
@MapperScan("com.example.springbootchapter4.mapper")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// paginationInterceptor.setLimit(你的最大单页限制数量,默认 500 条,小于 0 如 -1 不受限制);
return paginationInterceptor;
}
}
说明:
添加测试类,进行功能测试:
package com.example.springbootchapter4;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springbootchapter4.entity.Student;
import com.example.springbootchapter4.mapper.StudentMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by lzc
* 2019/8/3 16:24
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentTest {
@Autowired
private StudentMapper studentMapper;
/* ################################# 新增 ################################# */
// 插入一条记录
@Test
public void test1() {
Student student = new Student();
student.setCityName("南宁");
student.setStudentName("王麻子");
//SQL语句:INSERT INTO student ( student_name, city_name ) VALUES ( ?, ? )
studentMapper.insert(student);
}
/* ################################# 删除 ################################# */
// 根据 ID 删除
@Test
public void test2() {
// SQL语句:DELETE FROM student WHERE id=?
studentMapper.deleteById(7L);
}
// 根据 columnMap 条件,删除记录
@Test
public void test3() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("city_name", "桂林");
columnMap.put("class_name", "计科153");
// SQL语句:DELETE FROM student WHERE city_name = ? AND class_name = ?
studentMapper.deleteByMap(columnMap);
}
// 根据 entity 条件,删除记录
@Test
public void test4() {
Student student = new Student();
student.setCityName("南宁");
student.setStudentName("zhangsan");
// SQL语句:DELETE FROM student WHERE student_name=? AND city_name=?
studentMapper.delete(new QueryWrapper<>(student));
// 通过SQL语句可以发现,条件语句只包含了实体类不为空的属性
}
// 删除(根据ID 批量删除)
@Test
public void test5() {
List<Long> ids = new ArrayList<>();
ids.add(3L);
ids.add(8L);
// SQL语句:DELETE FROM student WHERE id IN ( ? , ? )
studentMapper.deleteBatchIds(ids);
}
/* ################################# 修改 ################################# */
// 根据 ID 修改
@Test
public void test6() {
Student student = new Student();
student.setId(9L);
student.setCityName("深圳");
// SQL语句:UPDATE student SET city_name=? WHERE id=?
studentMapper.updateById(student);
}
// 根据 whereEntity 条件,更新记录
@Test
public void test7() {
Student entity = new Student(); // 修改内容
entity.setAge(20);
Student whereEntity = new Student(); // 修改条件
whereEntity.setCityName("桂林");
whereEntity.setClassName("计科152");
// SQL语句:UPDATE student SET age=? WHERE class_name=? AND city_name=?
studentMapper.update(entity, new UpdateWrapper<>(whereEntity));
}
/* ################################# 查询 ################################# */
// 根据 ID 查询
@Test
public void test8() {
// SQL语句:SELECT id,student_name,gender,class_name,age,city_name,create_time,update_time FROM student WHERE id=?
Student student = studentMapper.selectById(10L);
System.out.println(student.toString());
}
// 查询(根据ID 批量查询)
@Test
public void test9() {
// idList 主键ID列表(不能为 null 以及 empty)
List<Long> idList = new ArrayList<>();
idList.add(9L);
idList.add(10L);
// SQL语句:SELECT id,student_name,gender,class_name,age,city_name,create_time,update_time FROM student WHERE id IN ( ? , ? )
List<Student> studentList = studentMapper.selectBatchIds(idList);
studentList.forEach(System.out::println);
}
// 查询(根据 columnMap 条件)
@Test
public void test10() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("city_name", "桂林");
columnMap.put("class_name", "计科152");
// SQL语句:SELECT id,student_name,gender,class_name,age,city_name,create_time,update_time FROM student WHERE city_name = ? AND class_name = ?
List<Student> studentList = studentMapper.selectByMap(columnMap);
studentList.forEach(System.out::println);
}
// 根据 Wrapper 条件,查询总记录数
@Test
public void test11() {
Student student = new Student(); // 查询条件实体类
student.setCityName("桂林");
// SQL语句:SELECT COUNT( 1 ) FROM student WHERE city_name=?
Integer count = studentMapper.selectCount(new QueryWrapper<>(student));
System.out.println(count);
}
// 根据 entity 条件,查询全部记录
@Test
public void test12() {
Student entity = new Student(); // 查询条件实体类
entity.setCityName("桂林");
entity.setClassName("计科152");
// SQL语句:SELECT id,student_name,gender,class_name,age,city_name,create_time,update_time FROM student WHERE class_name=? AND city_name=?
List<Student> studentList = studentMapper.selectList(new QueryWrapper<>(entity));
studentList.forEach(System.out::println);
}
// 根据 entity 条件,查询全部记录并分页(使用分页功能一定要设置PaginationInterceptor插件)
@Test
public void test13() {
Student entity = new Student(); // 查询条件实体类
entity.setCityName("桂林");
entity.setClassName("计科152");
// SQL语句:
// SELECT id,student_name,gender,class_name,age,city_name,create_time,update_time
// FROM student WHERE class_name=? AND city_name=? LIMIT ?,?、
Page<Student> studentPage = new Page<>(1,3);
studentMapper.selectPage(studentPage,new QueryWrapper<>(entity));
studentPage.getRecords(); // 分页对象记录列表
System.out.println("总数:" + studentPage.getTotal());
System.out.println("当前页:" + studentPage.getCurrent());
System.out.println("当前分页总页数:" + studentPage.getPages());
System.out.println("每页显示条数,默认 10:" + studentPage.getSize());
}
}
可以发现,上面会经常用到QueryWrapper和UpdateWrapper,这两个类继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件。
通过以上几个简单的步骤,我们就实现了 student 表的 CRUD 功能,甚至连 XML 文件都不用编写!
这里只举一个例子,具体用法请查看官网:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper
/* ################################# 条件构造器 ################################# */
@Test
public void test14() {
Student entity = new Student(); // 查询条件实体类
entity.setCityName("桂林");
entity.setClassName("计科152");
Page<Student> studentPage = new Page<>(1,3);
// SQL语句:
// SELECT
// id,student_name,gender,class_name,age,city_name,create_time,update_time
// FROM student
// WHERE class_name=? AND city_name=?
// AND age >= ?
// LIMIT ?,?
studentMapper.selectPage(studentPage,new QueryWrapper<>(entity).ge("age", 20));
}
// 获取指定的列字段出来
@Test
public void test15() {
Student entity = new Student(); // 查询条件实体类
entity.setCityName("桂林");
entity.setClassName("计科152");
Page<Student> studentPage = new Page<>(1,3);
// SQL语句:
// SELECT
// id,student_name,class_name
// FROM student
// WHERE class_name=? AND city_name=?
// AND age >= ?
// LIMIT ?,?
studentMapper.selectPage(studentPage,
new QueryWrapper<>(entity)
.select("id","student_name","class_name")
.ge("age", 20)
);
}
说明:
新建StudentService接口
package com.example.springbootchapter4.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springbootchapter4.entity.Student;
import org.springframework.stereotype.Service;
/**
* Created by lzc
* 2019/8/4 11:10
*/
public interface StudentService extends IService<Student> {
}
新建StudentServiceImpl类
package com.example.springbootchapter4.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootchapter4.entity.Student;
import com.example.springbootchapter4.mapper.StudentMapper;
import com.example.springbootchapter4.service.StudentService;
import org.springframework.stereotype.Service;
/**
* Created by lzc
* 2019/8/4 11:16
*/
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}
用法和Mapper CRUD 接口类似
如果需要写XML文件,使用步骤如下:
public interface StudentMapper extends BaseMapper<Student> {
Student getStudentById(Long id);
List<Student> getStudentByCityNameAndStudentName(Student student);
}
<mapper namespace="com.example.springbootchapter4.mapper.StudentMapper" >
<select
id="getStudentById"
parameterType="Long"
resultType="com.example.springbootchapter4.entity.Student">
SELECT *
FROM student
WHERE id = #{id}
select>
<select
id="getStudentByCityNameAndStudentName"
parameterType="com.example.springbootchapter4.entity.Student"
resultType="com.example.springbootchapter4.entity.Student">
SELECT *
FROM student
WHERE city_name = #{cityName}
AND student_name = #{studentName}
select>
mapper>
测试方法如下
/* ################################# XML形式测试方法 ################################# */
@Test
public void test17() {
System.out.println(("----- getStudentById method test ------"));
Student student = studentMapper.getStudentById(2L);
System.out.println(student.toString());
}
@Test
public void test18() {
System.out.println(("----- getStudentByCityNameAndStudentName method test ------"));
Student s = new Student();
s.setCityName("南宁");
s.setStudentName("zhangsan");
List<Student> studentList = studentMapper.getStudentByCityNameAndStudentName(s);
studentList.forEach(System.out::println);
}
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
添加 代码生成器 依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.2</version>
</dependency>
添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。
我这里使用的是freemarker
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
代码生成器代码
package com.example.springbootchapter4;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Created by lzc
* 2019/8/4 11:27
*/
// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
/**
*
* 读取控制台内容
*
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("lzc"); //作者
gc.setFileOverride(true); //是否覆蓋已有文件 默认值:false
gc.setOpen(false); //是否打开输出目录 默认值:true
// gc.setSwagger2(true); //开启 swagger2 模式 默认false
// gc.setBaseColumnList(true); //开启 baseColumnList 默认false
// gc.setBaseResultMap(true); //开启 BaseResultMap 默认false
// gc.setEntityName("%sEntity"); //实体命名方式 默认值:null 例如:%sEntity 生成 UserEntity
gc.setMapperName("%sMapper"); //mapper 命名方式 默认值:null 例如:%sDao 生成 UserDao
gc.setXmlName("%sMapper"); //Mapper xml 命名方式 默认值:null 例如:%sDao 生成 UserDao.xml
gc.setServiceName("%sService"); //service 命名方式 默认值:null 例如:%sBusiness 生成 UserBusiness
gc.setServiceImplName("%sServiceImpl"); //service impl 命名方式 默认值:null 例如:%sBusinessImpl 生成 UserBusinessImpl
gc.setControllerName("%sController"); //controller 命名方式 默认值:null 例如:%sAction 生成 UserAction
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/springboot-learning?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.example");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.ant.common.BaseEntity");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
在数据库中新建一张表,运行上面的代码,输入表名,即可自动生成entity、mapper、service
代码地址:https://github.com/923226145/SpringBoot-learning/tree/master/springboot-chapter4