MyBatisPlus实现复杂查询
MybatisPlus YAML配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lqf</groupId>
<artifactId>springboot-mybatis-plus-genrator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-mybatis-plus-genrator</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
mybatis-plus.properties展示(自动生成的位置做成了配置)
#此处为本项目src所在路径(代码生成器输出路径)
OutputDir=D:/V/springboot-mybatis-plus-genrator/src/main/java
#mapper.xml的生成位置
OutputDirXml=D:/V/springboot-mybatis-plus-genrator/src/main/resources
#数据库表名(此处切不可为空,如果为空,则默认读取数据库的所有表名)
tableName=fy_currency_log
#装代码的文件夹名
className=crm
#设置作者
author=lqf
#正常情况下,下面的代码无需修改!!!!!!!!!!
#自定义包路径
parent=com.lqf.springbootmybatisplusgenrator
#数据库地址
url=jdbc:mysql://******:3306/crm?useUnicode=true&characterEncoding=utf-8&tinyInt1isBit=false
userName=***
password=***
代码生成器的java类
package com.lqf.springbootmybatisplusgenrator;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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.ResourceBundle;
/**
* <p>
* 代码生成器
* </p>
*/
public class MpGenerator {
public static void main(String[] args) throws InterruptedException {
//用来获取Mybatis-Plus.properties文件的配置信息
final ResourceBundle rb = ResourceBundle.getBundle("mybatis-plus");
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(rb.getString("OutputDir"));
gc.setOpen(false);
gc.setBaseResultMap(true);
gc.setBaseColumnList(true);
gc.setAuthor(rb.getString("author"));
gc.setMapperName("%sMapper");
gc.setXmlName("%sMapper");
gc.setServiceName("%sService");
gc.setServiceImplName("%sServiceImpl");
gc.setControllerName("%sController");
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setDbType(DbType.MYSQL);
dsc.setUrl(rb.getString("url"));
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername(rb.getString("userName"));
dsc.setPassword(rb.getString("password"));
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent(rb.getString("parent"));
pc.setController("controller." + rb.getString("className"));
pc.setService("service." + rb.getString("className"));
pc.setServiceImpl("service." + rb.getString("className") + ".impl");
pc.setEntity("bean." + rb.getString("className"));
pc.setMapper("dao." + rb.getString("className"));
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return rb.getString("OutputDirXml") + "/mapper/" + rb.getString("className") + "/" + tableInfo.getEntityName() + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setInclude(new String[]{rb.getString("tableName")});
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
Wrapper的常用方法:
eq方法,名称是equals的缩写,两个参数,一个是数据库表字段的名称,一个是表字段值
userQueryWrapper.eq("user_id", 9); // WHERE user_id = ?
between方法,即SQL的 WHERE xxxxx字段 BETWEEN 值1 AND 值2
注意,值1一定是小于值2的
userQueryWrapper.between("xxx表字段", 10, 65); // WHERE xx字段 BETWEEN 值1 AND 值2
大于小于、大于等于、小于等于
userQueryWrapper.gt("xx字段", 20); // WHERE columnX > valueX
userQueryWrapper.lt("xx字段", 20); // WHERE columnX < valueX
userQueryWrapper.ge("xx字段", 20); // WHERE columnX >= valueX
userQueryWrapper.le("xx字段", 20); // WHERE columnX <= valueX
按字段排序:
可以是默认和N个字段,默认排序就表示ASC顺序从小到大
也可以指定排序方式,和自定的字段:
众多条件需要进行连接,无非就是AND & OR两种
一般只需要连续引用就表示这些一连串的条件是AND拼接,其中一个条件是可选的,就使用or方法处理
// WHERE xx字段 <= 20 AND columnX > valueX OR xxx表字段 BETWEEN 10 AND 65
userQueryWrapper.le("xx字段", 20).gt("columnX","valueX").or().between("xxx表字段", 10, 65);
1. wapper介绍
-
Wrapper : 条件构造抽象类,最顶端父类。
-
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件。
-
QueryWrapper :Entity 对象封装操作类,不是用lambda语法
-
UpdateWrapper : Update 条件封装,用于Entity对象更新操作。
-
AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
-
LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
-
LambdaUpdateWrapper : Lambda 更新封装Wrapper
/**
-
ge 大于等于
-
gt 大于
-
le 小于等于
-
lt 小于
-
isNull 是null
-
isNotNull 不是nul
-
执行的也是逻辑删除 */ @Test public void testDelete() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.isNull("create_time").ge("age", 21).isNotNull("email");
int result = userMapper.delete(queryWrapper); System.out.println("result = " + result); } /**
-
selectOne返回的是一条实体记录,当出现多条时会报错
-
eq 等于
-
ne 不等于 */ @Test public void testSelectOne(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name","Sandy");
User user = userMapper.selectOne(queryWrapper); System.out.println("user = " + user); } public void testSelectCount(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.between("age",22,30); Integer count = userMapper.selectCount(queryWrapper); System.out.println("count = " + count); } /**
-
like
-
notLike
-
likeLeft
-
likeRight */ @Test public void testSelectMaps(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.like("name","2");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper); maps.forEach(System.out::println); }
-
in、notIn:
inSql、notinSql:可以实现子查询
例: inSql("age", "1,2,3,4,5,6")—>age in (1,2,3,4,5,6)
例: inSql("id", "select id from table where id < 3")—>id in (select id from table where id < 3)
/**
* orderBy
* orderByDesc 降序
* orderBYAsc 升序
*/
@Test
public void testSelectListOrderBy(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
直接拼接到 sql 的最后
注意:只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用。
@Test
public void testSelectListLast() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.last("limit 1");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
指定要查询的列
@Test
public void testSelectListColumn(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id","name","age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void testUpdateSet() {
//修改值
User user = new User();
user.setAge(99);
//修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "h")
.set("name", "老李头")//除了可以查询还可以使用set设置修改的字段
.setSql(" email = '123@qq.com'");//可以有子查询
int result = userMapper.update(user, userUpdateWrapper);
}
分页查询全部记录
Page<User> page = new Page<>(1, 5);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
IPage<User> userIPage = mapper.selectPage(page, queryWrapper);
System.out.println(userIPage);
/**
* <p>
* 根据 Wrapper 条件,查询全部记录(并翻页)
* </p>
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
* 和上个分页同理只是返回类型不同
*/
@Test
public void selectMapsPage() {
Page<User> page = new Page<>(1, 5);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
IPage<Map<String, Object>> mapIPage = mapper.selectMapsPage(page, queryWrapper);
System.out.println(mapIPage);
}
条件修改
/**
* <p>
* 根据 whereEntity 条件,更新记录
* </p>
*
* @param entity 实体对象 (set 条件值,不能为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
@Test
public void update() {
//修改值
User user = new User();
user.setStatus(true);
user.setName("zhangsan");
//修改条件s
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper.eq("name", "lqf");
int update = mapper.update(user, userUpdateWrapper);
System.out.println(update);
}
查询总记录数
/**
* <p>
* 根据 Wrapper 条件,查询总记录数
* </p>
*
* @param queryWrapper 实体对象
*/
@Test
public void selectCount() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "lqf");
Integer count = mapper.selectCount(queryWrapper);
System.out.println(count);
}
根据entity条件,查询一条数据(selectone是返回一条数据,当出现多条时会报错)
根据entity条件 ,删除记录
VO:View Object,视图层,其作用是将指定页面的展示数据封装起来,通常用于业务层之间的数据传递。
类似于将前端页面传输的数据在后端service层封装成一个VO类,控制层需要调用时,直接调用该类中的属性,以获取各种数据:
vo, 是controller和视图层(view)打交道,要和页面中的数据结构相同更方便。dto是service层与mappe层 数据持久层交互的。
Java8 Lambda表达式迭代输出:list.forEach(x -> {System.out.println("lambda迭代:"+x);});
假设你用name来区分人,class为Student,其实就是 list.stream() .collect( Collectors.groupingBy( Student::getName, Collectors.collectingAndThen( Collectors.toList(), x - { x.stream() .collect(Collectors.maxBy(Comparator.comparing(Student::getScore))) .ifPresent(m - m.setType(1)); return x; } ) ) );
for循环快捷键---> iter
左边是参数、后边是方法体
BigDecimal做减法计算
案例中用户的金额字段使用BigDecimal作为类型,直接使用减号"-"计算两个数值的值,报错了。
仔细想想BigDecimal是一个类,也不是基本数据类型,本来就不能用减号
BigDecimal本身提供了加减乘除的方法
加法 add()函数 减法subtract()函数 乘法multipy()函数 除法divide()函数 绝对值abs()函数
将list中元素按指定字段作为组进行统计
案例:有个ArrayList list1,demo类中有属性id和price两个,需要将相同id的price求和 代码:
Map<String, ArrayList<demo>> collect = list1.stream().collect(Collectors.groupingBy(e -> e.getId()));
collect.forEach((k,val)->{
System.out.println(k);
DoubleSummaryStatistics collect1 = val.stream().collect(Collectors.summarizingDouble(e -> e.getPrice().doubleValue())); //这里因为price是BigDecimal因此需要转换
System.out.println(collect1.getSum());
});
collect1.getSum()就是统计的值,可以根据需要整合到自己的结果集中
type-aliases-package的作用
mapper.xml文件中resultMap的type或者parameterType会使用自定义的pojo,
此时可以用完全限定名来指定这些POJO的引用,例如
,
又或者你可以通过在application.properties中指定POJO扫描包来让mybatis自动扫描到自定义POJO,如下:
mybatis.type-aliases-package=com.e3mall.cms.dao.mapper
mybatis中mapper传多个入参
使用@Param
#mapper中接口的签名
List<TbItem> selectByPage(@Param("page") int page , @Param("rows") int rows);
#sql
<select id="selectByPage" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
from tb_item LIMIT #{page} , #{rows}
</select>
@mapper个人理解
@mapper的作用是可以给mapper接口自动生成一个实现类,让spring对mapper接口的bean进行管理,并且可以省略去写复杂的xml文件
此处借用一段代码
/UserDAO
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import entity.User;
/**
* 添加了@Mapper注解之后这个接口在编译时会生成相应的实现类
*
* 需要注意的是:这个接口中不可以定义同名的方法,因为会生成相同的id
* 也就是说这个接口是不支持重载的
*/
@Mapper
public interface UserDAO {
@Select("select * from user where name = #{name}")
public User find(String name);
@Select("select * from user where name = #{name} and pwd = #{pwd}")
/**
* 对于多个参数来说,每个参数之前都要加上@Param注解,
* 要不然会找不到对应的参数进而报错
*/
public User login(@Param("name")String name, @Param("pwd")String pwd);
}
不过进过自己测试,用过写了xml,使用@mapper也会走到xml文件中,但是如果xml和@select同时存在,会报错,只能使用其中一种
原因:
springboot默认不会扫描到对应的bean文件
解决:
方式1、在mapper接口上添加@Mapper
方式2、在application启动类上添加@MapperScan(basePackages = {"com.e3mall.cms.dao.mapper"})
IDEA快捷键
| Ctrl + Shift + Enter | 自动结束代码,行末自动添加分号 (必备) |
|---|---|
| Ctrl + Shift + / | 注释代码块 |
| Ctrl+/ | 注释代码 |
| Ctrl+ | 展开代码 |
| Ctrl+y | 反撤回 |
| Ctrl+z | 撤回 |
| Ctrl- | 折叠代码 |
| Ctrl + Shift + U | 对选中的代码进行大 / 小写轮流转换 (必备) |