赞
踩
public class User {
private int id;
private String username;
private String password;
private String address;
}
public interface UserMapper {}
<!--MybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
public interface UserMapper extends BaseMapper<User> {}
约定大于配置
MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
uerInfo -> user_info
。userName - > user_name
@TableName
:用来指定表名。@Tableld
:用来指定表中的主键字段信息。
value
:对应表内主键的名称type
:主键增长类型
IdType.AUTO
:数据库自增长IdType.INPUT
:通过set方法自行输入IdType.ASSIGN_ID
:分配ID ,接口oldentifierGenerator
的方法nextld
来生成id,默认实现类为DefaultldentifierGenerator
雪花算法。@TableField
:用来指定表中的普通字段信息。 使用场景如下
order
”)。MyBatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置。
mybatis-plus:
type-aliases-package: com.po #别名扫持包
mapper-locations: "classpath*:/mapper/**/*.xml" # Mappe.xml文件地址,默认值
configuration:
map-underscore-to-camel-case: true 中是否开启下划线和轮峰的关射
cache-enabled: false #是否开启二级缓存
global-config:
db-config:
id-type: assign_id #id为雪花算法生成
update-strategy: not_null #更新策略: 只更新非空字段
其他配置官网可查
条件构造器的"族谱"
构造器举例
sql语句
SELECT id ,username, info , balance
FROM user
WHERE username LIKE ? AND balance >= ?
代码
// 1.构建查询条件
QueryWrapper<User> wrapper=new QueryWrapper<User>()
.select("id", "username", "info", "balance"')
.like("username","o")
.ge("balance",1000);
// 2.查询
List<User> users = userMapper.selectlist(wrapper);
sql语句
UPDATE user
SET balance = 2000
WHERE (username = "jack")
代码
// 1. 要更新的数据
new User();
user.setBalance(2000);
// 2.更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");
// 3.执行更新
userMapper.update(user, wrapper);
sql语句
UPDATE user
SET balance = balance - 200
WHERE id in (1, 2, 4)
代码
List<Long> ids = List.of(1L, 2L,4L);
UpdateWrapper<User> wrapper = new UpdateWrapper<user>()
.setSql("balance = balance - 200")
.in("id", ids) ;
userMapper.update(null, wrapper);
// 1.构建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.select(User::getId,
User::getUsername,
User::getInfo,
User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
// 2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
QueryWrapper
和LambdaQueryWrapper
通常用来构建select
、delete
、update
的where
条件部分。UpdateWrapper
和LambdaUpdateWrapper
通常只有在set
语句比较特殊才使用。LambdaQueryWrapper
和LambdaUpdateWrapper
,避免硬编码。我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。
ListcLong> ids = List.of(1L, 2L,4L);
int amount = 200 ;
// 1. 构建来件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(User::getId, ids);
// 2. 自定XSQL方法调用
userHapper .updateBalanceByIds (wrapper, amount);
void updateBalanceByIds (@Param("ew") LambdaQueryWrapper<User> wrapper, @Param ("amount") int amount) ;
<update id="updateBalanceByIds">
UPDATE tb_user SET balance = balance - #{amount} ${ew.customsqtsegment}
</update>
基于Restful风格实现下面的接口:
<!-- swagger-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
<!-- web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
knife4j:
enable: true
openapi :
title: 用户管理接口文档
description: "用户管理接口文档"
email:
concat: 作者
url: https://www.xxx.cn
version: V1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources :
- com.ai.www.controller
@Api(tags="用户管理接口") @RequestMapping("/users") @RestController @RequiredArgsConstructor//只会为需要注入的变量注入(加final或者@NonNull就是可以自动注入的) public class UserController { //@Autowired //private IUserService userService;//spring不推荐 private final IUserService userService; @ApiOperation("新增用户接口") @PostMapping public void saveUser (@RequestBody UserFormDTO userDTO){ // 1. 把DTO拷贝到PO User user = Beanutil.copyProperties(userDT0, User.class) ; // 2.新增 userService.save(user); } @ApiOperation("删除用户接口") @DeleteMapping("{id}") public void deleteUserById(@ApoParam("用户ID") @Pathvariable("id") Long id{ userService.removeById(user); } @ApiOperation("根据id查询用户接口") @GetMapping("{id}") public UserVo queryUserById(@ApiParam("用户id") @PathVariable("id") Long id) { // 1.查询用户PO User user = userservice. getById(id); // 2. 把PO拷贝到Vo return BeanUtil.copyProperties(user, UserVo.class) ; } @ApiOperation("根据id批最查询用户接口") @GetMapping public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids) { // 1.查沟用户PO List<User> users = userService.listByIds(ids); // 2. 把PO拷贝到Vo return Beanutil.copyTolist(users, Uservo.class); } @ApiOperation("扣减用户余额接口") @PutMapping("/{id}/deduction/{money}") public void deductMoneyById(@ApiParam("用户id")@Pathvariable("id") Long id, @ApiParam("扣减的金额")@PathVariable("money") Integer money){ userService.removeById(id); } }
代码
public interface UserMapper extends BaseMapper<user> {
List<User> queryUserByIds(@Param("ids") List<Long> ids);
void updateBalanceByIds(@Param(Constants.WRAPPER) {Querywrapper<User> wrapper, @Param("anount") int amount);
@Update("UPDATE tb_user SET balance = balance - #{money} WHERE id = #{id}")
void deductbalance (@Param("id") Long id, @Param("money")Integer money);
}
mapper文件
<?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.xxx.mp.mapper.UserMapper"> <update id="updateBalanceByIds"> UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment} </update> <select id="queryUserByIds" resultType="com.xxx.mp.donain.po.User"> SELECT * FROM tb_user <if test="ids != null"> WHERE id IN <foreach collection="ids" open="(" close=")" item="id" separator=","> #{id} </foreach> </if> LIMIT 10; </select> </mapper>
@Data @ApiModel(description = "用户表单实体") public class UserFormDTO { @ApiModelProperty("id") private Long id; @ApiModelProperty("用户名") private string username; @ApiModelProperty("密码") private string password; @ApiModetProperty("注册手机号") private String phone; @ApiModelProperty("详细信息,JSON风格") private string info; @ApiModelProperty("账户余额") private Integer balance; }
@Data @TableName("tb_user") public class pser { //用户id // @TableId(type.IdType.AUTO) private Long id; //用户名 // @TableField("username“") private string username; //密码 // @TableField(exist = false) private string password; //注册手机号 private string phone; //详细信息 private string info; //使用状态(1正常2陈结) private Integer status; //账户余额 private Integer balance; //创建时间 private LocalDateTime createTime; //更新时间 private LocalDateTime updateTime;
@Data @ApiModel (description="用户Vo实体") public class UserVo { @ApiModelProperty("用户id"') private Long id; @ApiModetProperty("用户名") private string user name; @ApiModelProperty("详细信息") private String info; @ApiModelProperty("使用状态(1正常2陈结) ") private Integer status; @ApiModelProperty("账户余额") private Integer balance;
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { @Override public void deductBalance(Long id, Integer money) { // 1. 查询用户 User user = this.getById(id); // 2.校验用户状态 if (user == null || user.getstatus() == 2){ throw new RuntimeException("用户状态异常! "); } // 3. 校验余额是否充足 if (user.getBalance() < money) { throw new RuntimeException("用户余额不足! "); } // 4.扣减余额update tb_ user set balance = balance -? baseMapper.deductBlance(id, money); }
需求:实现一个根据复杂条件查询用户的接口,查询条件如下:
@Apioperat ion("根据复杂条件查询用户接口")
QGetMapping("/List")
public List<UserVo> queryusers(Userquery query){
// 1. 查淘用户PO
List<user> users = userService.queryUsers(query.getName(),query.getstatus(),query.getaxBalance(), query.getMaxBalance())
// 2. PO 拷贝到Wo
return Beanutil.copyTolist(users, Uservo.class);
lambdaQuery()
可以换成Db.lambdaQuery
,当然可以直接导包@Override
public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
return lambdaQuery()
.like(name != null, User::getUsername,name)
.eq(status != null, User::igetstatus, status)
.gt(minBalance != null,User::getBalance,minBalance)
.lt(maxBalance != null, User::getBalance, maxBalance)
.list();//其他查询方法看编译器提醒就行
}
需求:改造根据id修改用户余额的接口,要求如下:
@Transactional public void deductBalance(Long id, Integer money) { // 1.查询用户 User user = getById(1d); // 2.校验用户状态 if (user == null | user.getstatus() == 2) { throw new Runt imeExcept ion("用户状态异常! "); } // 3. 校验余额是否充足 if (user.getBalance() < money) { throw new RuntimeExcept ion("用户余额不足! "); } // 4.加减余额 update tb_user set balonce = balance - 1 int remainBalance = user.getBalance() - money; lambdaUpdate() .set(User::getBalance, remainBalance) .set(remainBalance == 0, User::getstatus, 2) .eq(User::getId, id) .eq(User::getBalance(), user::getBalance())//加锁,乐观锁,防止并发一起改 .update();
连接时拼上参数
&rewriteBatchedStatements=true
新版在Tools,旧版在上面的Other
import com.baomidou.mybatisplus.extension.toolkit.Db;
需求:
@Override public Uservo queryUserAndAddressById(Long id) { // 1.查询用户 User user = getById(4L) ; if (user = null || user .getstatus() == 2) { throw new Runt imeException("用户状态异常! "); } // 2.查询地址 List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId,id).1ist(); // 3.对Vo // 3.1.转User的PO%为V0 UserVo userVo = BeanUtil.copyProperties(user, Uservo.class); // 3.2.转地hv0 if (CollUtil.isNotEmpty(addresses)) { uservo.setAddresses(BeanUtil.copyToList(addresses, AddressVo.class)); } return uservo; }
// 1.查询用户 List<User> users = listByIds(ids); if (Collutil.isEmpty(users)) { return Collections.emptylist(); } // 2.查询地址 // 2.1.获收用户id集合 List<Long> userIds = users.stream().map(User::getId).collect(Collectors.tolist()); // 2.2. 根据用户id查询地址 List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId,userIds).list(); // 2.3. 转换地址VO List<AddressVo> addressVoList = BeanUtil.copyTolist(addresses, AddressVo.class); // 2.4.用户地址集合分出处理,相同用户的放入一个集合(组)中 Map<Long,List<AddressVo>> addressMap = new HashMap<>(0) ; if(CollUtil.isNotEmpty(addressVoList )){ addressMap = addressVoList.stream().collect(Collectors.groupingBy(Addressvo::getUserId)); } // 3.转换Vo返回 List<UserVo> list = new ArrayList<>(users.size()); for (User user : users) { // 3.1.转换User MPO为VO UserVO vo = BeanUtil.copyProperties(user,Uservo.class); list.add(vo); // 3.2.转换地hVO vo.setAddresses(adlressMap.get(user.getId()); } return list;
逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。
删除操作
查询操作
MybatisPlus提供了逻辑删除功能,无需改变方法调用的方式,而是在底层自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可。
mybatis-plus:
globa1-config:
db-config:
logic-delete-field: flag #全局逻辑删除的实体字段名,字服类型可以是boolean, integer
logic-delete-value: 1 #逻辑已删除值(默认为1)
logic-not-delete-value: 0 #逻辑未删除值(默认为0)
修改配置
mybatis-plus:
configuration:
default-enum-type-handter: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
枚举加注解
@Getter
public enum UserStatus {
NORMAL(1, "正常"),
FROZEN(2, "冻结"),
;
@EnumValue
@JsonValue()//枚举返回值,返回给前端value值
private final int value;
private final String desc;
UserStatus(int value, String desc) {
this.value = value;
this.desc = desc;
}
}
@Data
@TableName ( value= "user", autoResultMap = true )
public class User {
private Long id;
private String username;
@TableField(typeHandler = JacksonTyeHandler.class)
private UserInfo info;
}
@Data
public class UserInfo {
private Integer age;
private String intro;
private String gender;
}
MyBatisPlus提供的内置拦截器有下面这些:
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
// 1.初始化核心播件
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 2. 添加分页插件
PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
pageInterceptor.setMaxLimit(1000L); //设置分页上限
interceptor.addInnerInterceptor(pageInterceptor);
return interceptor;
}
}
@Test void testPageQuery() { // 1.查询 int pageNo = 1, pageSize = 5; // 1.1.分页参数 Page<User> page = Page.of(pageNo, pageSize) ; // 1.2. 排序参数,通orderItem来指定 page.addOrder(new OrderItem("balance", false)); // 1.3. 分页查询 Page<User> p = userService.page(page); // 2.总来数 System.out.println("total = " + p.getTotal()); // 3.总页数 System.out.println("pages = " + p.getPages()); // 4.分页数据 List<User>records = p.getRecords(); records.forEach(System.out::println); }
其他的查询继承此类即可
@Data @ApiModel (description ="分页查削实体") public class PageQuery{ @ApiModelProperty("页码") private Integer pageNo; @ApiModeProperty("页码") private Integer pagesize; @ApiModelProperty("排序字段") private String sortBy; @ApiModelProperty("是否升序") private Boolean isAsc ; public <T> Page<T> toMpPage(orderItem ... items){ // 1.分页条件 PagecT> page = Page.of(pageNo, pagesize); // 2.排序条件 if(StrUtil.isNotBlank(sortBy)){ //不为空 page.addorder(new orderItem(sortBy, isAsc)); }else if(items != null){ //为空默以招序 page.addorder (items); } return page; } }
@Data @ApiModel (description = "分页结果") public class PageDTO<T> { QApiModelProperty("总条数") private Integer total; QApiModelProperty("总页数") private Integer pages; @ApiModetProperty("集合") private List<T> list; public static <Po,Vo>PageDTO<VO> of(Page<Po> p,Class<Vo> clazz){ PageDTO<VO> dto = new PageDT0<>(); // 1.总条数 dto.setTotal(p.getTotal()); // 2.总页数 dto.setPages(p.getPages()); // 3.当前页数 List<userPo> records = p.getRecords(); if (Collutil.isEmpty(records)) { dto.setList(Collections.emptylist()); return dto; } // 4.拷贝V0 dto.setList(BeanUtil.copyTolist(records, clazz)); // 5.返回 return dto; } }
遵循下面的接口规范,编写一个UserController接口, 实现User的分页查询。
省略其他一些东西,直接核心代码
service 代码
注意lambdaQuery()
可以换成Db.lambdaQuery
,当然可以直接导包
@override public PageDTocUserV0> quer yUser sPage (UserQuery query) { String name = query.getName(); Integer status = query.getstatus(); // 1. 构建分页条件 // 1.1.分页条件 Page<User> page = Page.of(query.getPageNo(), query.getPagesize()); // 1.2.那序条件 if(Strutil.isNotBlank(query.getSortBy())){ //不为空 page.addOrder(new orderItem(query.getSorBy(), query.getIsAsc()); }else{ //为空,默认按照更新时间排序 page.addOrder(new OrderItem("update_time", false)); // 2.分页查询 Page<User> p = lambdaQuery() .like(nane != null, User::getUsername, nane) .eq(status != null, User::gotStatus, status) .page(page); // 3.封装Vo结果 PageDTO<UserVo> dto = new PageDTO<>(); // 3.1.总条数 dto.setTotal(p.getTotal()); // 3.2.总页数 dto.setPages(p.getPoges()); // 3.3. 当前页数据 List<User> records = p.getRecords(); if(CollUtil.isEmpty(records)) { dto.setList(Collections.emptylist(); return dto; } // 3.4.传userVO dto.setList(Beanutil.copyTolist(records,UserVo.class)); // 4.返回 return dto; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。