在单表查询时候简化了Mapper接口与XML的配置统统不需要了
//只需继承mybatis-plus提供的接口,指定对应实体类
public interface UserMapper extends BaseMapper<User> {
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mp.mapper.UserMapper">
mapper>
Test类中直接调用Mapper接口继承的方法完成增删改查等操作
package com.itheima.mp.mapper;
import com.itheima.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
User user = new User();
user.setId(5L);
user.setUsername("Lucy");
user.setPassword("123");
user.setPhone("18688990011");
user.setBalance(200);
user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userMapper.insert(user);
}
@Test
void testSelectById() {
User user = userMapper.selectById(5L);
System.out.println("user = " + user);
}
@Test
void testQueryByIds() {
List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));
users.forEach(System.out::println);
}
@Test
void testUpdateById() {
User user = new User();
user.setId(5L);
user.setBalance(20000);
userMapper.updateById(user);
}
@Test
void testDeleteUser() {
userMapper.deleteById(5L);
}
}
注意is开头且为boolean类型的变量名,经过反射会将is省略
@Data
@TableName("tb_user")
public class User {
/**
* 用户id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户名
*/
// @TableField("'username'")
private String username;
10:53:53 DEBUG 21696 --- [ main] c.i.mp.mapper.UserMapper.selectBatchIds : ==>
Preparing: SELECT id,'username',phone,info,status,balance,create_time,update_time FROM tb_user WHERE id IN ( ? , ? , ? , ? )
@Test
void testQueryWrapper() {
//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);
users.forEach(System.out::println);
}
//输出
//User(id=3, username=Hope, password=null, phone=null,
//info={"age": 25, "intro": "上进青年", "gender": "male"}, status=null, balance=100000, createTime=null, updateTime=null)
@Test
void testUpdateByQueryWrapper() {
//1.要更新的数据
User user = new User();
user.setBalance(2000);
//2、更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.eq("username", "jack");
//3、执行更新
userMapper.update(user, wrapper);
}
//Preparing: UPDATE tb_user SET balance=? WHERE (username = ?)
@Test
void testUpdateWrapper() {
List<Long> ids = List.of(1L,2L,4L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql("balance = balance -200")
.in("id", ids);
//3、执行更新
userMapper.update(null, wrapper);
}
@Test
void testCustomSqlUpdate() {
//1.更新条件
List<Long> ids = List.of(1L,2L,4L);
int amount = 200;
//2.定义条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.in("id",ids);
//3.调用自定义SQL方法
userMapper.updateBalanceByIds(wrapper,amount);
}
创建Mapper接口
void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper, @Param("amount") int amount);
XML文件
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mp.mapper.UserMapper">
<update id="updateBalanceByIds">
update tb_user set balance = balance - #{amount} ${ew.customSqlSegment}
update>
mapper>
创建Service层的接口类和实现类
public interface IUserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
测试
@SpringBootTest
class IUserServiceTest {
@Autowired
private IUserService userService;
@Test
void testSaveUser() {
User user = new User();
user.setUsername("zhangshuwen");
user.setPassword("123");
user.setPhone("18688990011");
user.setBalance(200);
user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
}
@Test
void testQuery() {
List<User> users = userService.listByIds(List.of(1L,2L,4L));
users.forEach(System.out::println);
}
}
@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/users")
/**
* @RequiredArgsConstructor 注解在类上使用时,
* Lombok会为类中的每个标有 final 或 @NonNull 注解的字段生成一个构造函数参数,
* 然后在编译时自动生成带有这些参数的构造函数。
* 这样你就不需要手动编写这个构造函数,Lombok会为你处理。
*/
@RequiredArgsConstructor
public class UserController {
private final IUserService iUserService;
@ApiOperation("新增用户接口")
@PostMapping
public void saveUser(@RequestBody UserFormDTO userFormDTO) {
//1.将DTO拷贝到PO
User user = BeanUtil.copyProperties(userFormDTO, User.class);
//2.新增
iUserService.save(user);
}
@ApiOperation("删除用户接口")
@DeleteMapping("/{id}")
public void saveUser(@PathVariable Long id) {
iUserService.removeById(id);
}
@ApiOperation("根据id查询用户接口")
@GetMapping("/{id}")
public UserVO selectUser(@PathVariable Long id) {
User user = iUserService.getById(id);
return BeanUtil.copyProperties(user, UserVO.class);
}
@ApiOperation("根据id批量查询用户接口")
@GetMapping
public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids) {
List<User> users = iUserService.listByIds(ids);
return BeanUtil.copyToList(users, UserVO.class);
}
@ApiOperation("扣减用户余额")
@PutMapping("/{id}/deduction/{money}")
public void deductMoneyId(@PathVariable("id") Long id,
@PathVariable("money") Integer money) {
iUserService.deductBalance(id,money);
}
}
Service实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Override
public void deductBalance(Long id, Integer money) {
//1.查询用户
User user = getById(id);
//2.校验用户状态
if (user == null || user.getStatus() ==2 ){
throw new RuntimeException("用户状态异常!");
}
//3.校验余额是否充足
if (user.getBalance() <money ) {
throw new RuntimeException("用户余额不足!");
}
//4.扣减余额
baseMapper.deductBalance(id,money);
}
Mapper接口
@Update("update tb_user set balance = balance - #{money} where id = #{id}")
void deductBalance(@Param("id") Long id, @Param("money") Integer money);
@ApiOperation("根据复杂条件查询")
@GetMapping("/list")
public List<UserVO> queryUsers(UserQuery userQuery) {
//1.查需要你用户PO
List<User> users = iUserService.queryUsers(userQuery.getName(),userQuery.getStatus(),userQuery.getMinBalance(),userQuery.getMaxBalance());
//2.把PO拷贝到VO
return BeanUtil.copyToList(users, UserVO.class);
}
Service实现类
/**
* lambdaQuery(): 这是 MyBatis-Plus 提供的静态方法,用于创建一个 LambdaQueryWrapper 对象,LambdaQueryWrapper 是 MyBatis-Plus 中的查询条件构造器,允许通过 lambda 表达式动态构建查询条件。
*
* .like(name!=null, User::getUsername, name): 这一行表示如果 name 不为 null,则添加一个模糊查询条件,查询条件是 User 对象的 getUsername 方法返回的字段,且字段值与传入的 name 相匹配。
*
* .eq(status!=null, User::getStatus, status): 这一行表示如果 status 不为 null,则添加一个等于查询条件,查询条件是 User 对象的 getStatus 方法返回的字段,且字段值与传入的 status 相等。
*
* .ge(minBalance!=null, User::getBalance, minBalance): 这一行表示如果 minBalance 不为 null,则添加一个大于等于查询条件,查询条件是 User 对象的 getBalance 方法返回的字段,且字段值大于等于传入的 minBalance。
*
* .le(maxBalance!=null, User::getBalance, maxBalance): 这一行表示如果 maxBalance 不为 null,则添加一个小于等于查询条件,查询条件是 User 对象的 getBalance 方法返回的字段,且字段值小于等于传入的 maxBalance。
*/
@ApiOperation("根据复杂条件查询")
@GetMapping("/list")
public List<UserVO> queryUsers(UserQuery userQuery) {
//1.查需要你用户PO
List<User> users = iUserService.queryUsers(userQuery.getName(),userQuery.getStatus(),userQuery.getMinBalance(),userQuery.getMaxBalance());
//2.把PO拷贝到VO
return BeanUtil.copyToList(users, UserVO.class);
}
@Override
public void deductBalance(Long id, Integer money) {
//1.查询用户
User user = getById(id);
//2.校验用户状态
if (user == null || user.getStatus() ==2 ){
throw new RuntimeException("用户状态异常!");
}
//3.校验余额是否充足
if (user.getBalance() <money ) {
throw new RuntimeException("用户余额不足!");
}
//4.扣减余额
int remainBalance = user.getBalance() - money;
lambdaUpdate()
.set(User::getStatus,remainBalance)
.set(remainBalance==0, User::getStatus,2)
.eq(User::getId,id)
.eq(User::getBalance,user.getBalance()) //乐观锁防止并发错误
.update();
}
在idea中通过mybatis-plus插件生成代码
分别点击两个选项完成配置数据库配置信息
静态工具类(如 MyBatis-Plus 中的 SqlHelper)和 IService 接口在具体开发与实际使用中有一些区别,主要取决于它们的设计目的和使用场景:
设计目的:
静态工具类: 静态工具类的设计目的是提供一些通用的静态方法,用于执行底层的 SQL
操作或其他常见操作。这些方法通常是静态的,无需创建对象实例,用于简化底层操作。 IService 接口: IService 接口及其实现类
ServiceImpl 的设计目的是为了提供一些通用的 CRUD(增删改查)操作,封装常见的业务逻辑,提供了一种面向对象的服务层抽象。使用场景:
静态工具类: 静态工具类适用于一些不涉及对象实例状态的操作,例如执行 SQL 查询,文件操作等。这些方法通常是静态的,可以通过类名直接调用。
IService 接口: IService 接口适用于业务服务层的抽象,封装了一些通用的业务操作,特别是针对实体对象的 CRUD
操作。IService 接口可以被业务层的服务类实现,提供具体的业务逻辑。
需求1
Controller层
@GetMapping("/{id}")
public UserVO selectUser(@PathVariable Long id) {
return iUserService.queryUsersAndAddressById(id);
}
Service实现类
@Override
public UserVO queryUsersAndAddressById(Long id) {
//1.查询用户
User user = getById(id);
if (user == null || user.getStatus() == 2){
throw new RuntimeException("用户状态异常!");
}
//2.查询地址
List<Address> addresses = Db.lambdaQuery(Address.class)
.eq(Address::getUserId, id).list();
//3.封装VO
//3.1装User的PO为VO
UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
//3.2转地址VO
if (CollUtil.isNotEmpty(addresses)) {
userVO.setAddress(BeanUtil.copyToList(addresses, AddressVO.class));
}
return userVO;
}
需求2
Controller层
@ApiOperation("根据id批量查询用户接口")
@GetMapping
public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids) {
return iUserService.queryUserAndAddressByIds(ids);
}
Service实现类
@Override
public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
//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<>();
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的PO为VO
UserVO vo = BeanUtil.copyProperties(user,UserVO.class);
list.add(vo);
//3.2转换地址VO
vo.setAddress(addressMap.get(user.getId()));
}
return list;
}
@ApiOperation("根据条件分页查询用户接口查询")
@GetMapping("/page")
public PageDTO<UserVO> queryUserspage(UserQuery userQuery) {
return iUserService.queryUserspage(userQuery);
}
service实现类
@Override
public PageDTO<UserVO> queryUserspage(UserQuery userQuery) {
String name = userQuery.getName();
Integer status = userQuery.getStatus();
//1.构建查询条件
//1.1分页条件
Page<User> page = Page.of(userQuery.getPageNo(), userQuery.getPageSize());
//1.2排序条件
if (StrUtil.isNotBlank(userQuery.getSortBy())){
//不为空
page.addOrder(new OrderItem(userQuery.getSortBy(),userQuery.getIsAsc()));
}else {
//为空,默认按照更新时间排序
page.addOrder(new OrderItem("update_time",false));
}
//2.分页查询
Page<User> userPage = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus, status)
.page(page);
//3.封装VO结果
PageDTO<UserVO> pageDTO = new PageDTO<>();
//3.1总条数和总页数
pageDTO.setTotal(userPage.getTotal());
pageDTO.setPages(userPage.getPages());
//当前页数据
List<User> records = userPage.getRecords();
if (CollUtil.isEmpty(records)){
pageDTO.setList(Collections.emptyList());
return pageDTO;
}
//拷贝User的VO
List<UserVO> userVOS = BeanUtil.copyToList(records, UserVO.class);
pageDTO.setList(userVOS);
//4.返回
return pageDTO;
}