java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > mybatis-plus自定义业务

mybatis-plus自定义业务实现方式

作者:改了一个昵称

本文介绍了使用MyBatis-Plus(简称MP)进行数据库操作的实现步骤,包括创建实体类、Mapper接口和XML文件、Service接口和实现类,以及测试类,重点强调了业务层参数校验、事务管理以及复杂SQL的处理方式

结构

src/main/java/com/example/demo/
├── DemoApplication.java          // 启动类
├── entity/User.java              // 实体类
├── mapper/UserMapper.java        // Mapper 接口(含自定义SQL)
├── service/IUserService.java     // Service 接口(自定义方法声明)
└── service/impl/UserServiceImpl.java // Service 实现类(自定义方法实现)
src/main/resources/
├── application.yml               // 配置文件
└── mapper/UserMapper.xml         // 自定义SQL的XML文件(如需)
src/test/java/com/example/demo/
└── UserServiceTest.java          // 测试类

实体类 User

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_user") // 对应数据库表名
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;         // 主键自增
    private String username; // 用户名
    private String email;    // 邮箱
    private Integer age;     // 年龄
    private Integer status;  // 状态:1-正常 0-禁用
}

Mapper 接口(UserMapper.java)

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;

public interface UserMapper extends BaseMapper<User> {
    " 自定义SQL:根据年龄范围查询(也可通过Wrapper实现,这里演示XML方式) "
    List<User> selectByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);

    " 自定义SQL:统计不同年龄段的用户数量 "
    List<Map<String, Object>> countUserByAgeGroup();
}

Mapper XML 文件(UserMapper.xml)

resources/mapper 下创建,存放自定义SQL:

<?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.mapper.UserMapper">

    <!-- 对应 selectByAgeRange 方法 -->
    <select id="selectByAgeRange" resultType="com.example.demo.entity.User">
        SELECT id, username, email, age, status 
        FROM t_user 
        WHERE age BETWEEN #{minAge} AND #{maxAge}
    </select>
    

    <!-- 对应 countUserByAgeGroup 方法 -->
    <select id="countUserByAgeGroup" resultType="java.util.Map">
        SELECT 
            CASE 
                WHEN age < 18 THEN '未成年'
                WHEN age BETWEEN 18 AND 30 THEN '青年'
                WHEN age BETWEEN 31 AND 50 THEN '中年'
                ELSE '老年'
            END AS age_group,
            COUNT(*) AS user_count
        FROM t_user
        GROUP BY age_group
    </select>

</mapper>

Service 接口(IUserService.java)

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;
import java.util.List;
import java.util.Map;

public interface IUserService extends IService<User> {
    "示例1:根据年龄范围查询用户(调用Mapper自定义SQL)"
    List<User> getUserByAgeRange(Integer minAge, Integer maxAge);

    "示例2:批量插入用户(基于MP的saveBatch扩展)"
    int batchInsertUsers(List<User> userList);

    "示例3:根据用户名模糊查询并按年龄降序排序(纯MP Wrapper实现)"
    List<User> listUsersByUsernameLike(String usernameKeyword);

    "示例4:统计不同年龄段的用户数量(调用Mapper自定义SQL)"
    Map<String, Long> countUserByAgeGroup();

    "示例5:逻辑删除+状态更新(业务组合操作)"
    boolean disableUserById(Long userId);
}

Service 实现类(UserServiceImpl.java)

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    "示例1:调用Mapper自定义SQL实现年龄范围查询"
    @Override
    public List<User> getUserByAgeRange(Integer minAge, Integer maxAge) {
        // 非空校验(业务层必备)
        if (minAge == null || maxAge == null || minAge > maxAge) {
            throw new IllegalArgumentException("年龄范围参数不合法");
        }
        return baseMapper.selectByAgeRange(minAge, maxAge);
    }

    "示例2:批量插入(扩展MP的saveBatch,增加批次控制和返回值)"
    @Override
    @Transactional(rollbackFor = Exception.class) // 事务保证
    public int batchInsertUsers(List<User> userList) {
        if (userList == null || userList.isEmpty()) {
            return 0;
        }
        // MP的saveBatch默认批次是1000,这里自定义批次大小为500
        boolean success = saveBatch(userList, 500);
        return success ? userList.size() : 0;
    }

    "示例3:纯Wrapper实现模糊查询+排序"
    @Override
    public List<User> listUsersByUsernameLike(String usernameKeyword) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .like(usernameKeyword != null, User::getUsername, usernameKeyword) // 非空才拼接条件
                .orderByDesc(User::getAge); // 按年龄降序
        return list(wrapper); // 调用IService的默认方法
    }

    "示例4:统计年龄段数量(处理Mapper返回的Map)"
    @Override
    public Map<String, Long> countUserByAgeGroup() {
        List<Map<String, Object>> resultList = baseMapper.countUserByAgeGroup();
        Map<String, Long> ageGroupMap = new HashMap<>();
        for (Map<String, Object> map : resultList) {
            String ageGroup = (String) map.get("age_group");
            Long userCount = (Long) map.get("user_count");
            ageGroupMap.put(ageGroup, userCount);
        }
        return ageGroupMap;
    }

    "示例5:组合业务操作(逻辑删除+状态更新)"
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean disableUserById(Long userId) {
        // 1. 查询用户是否存在
        User user = getById(userId);
        if (user == null) {
            return false;
        }
        // 2. 更新状态为禁用(0)
        user.setStatus(0);
        return updateById(user);
    }
}

测试类(UserServiceTest.java)

import com.example.demo.DemoApplication;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SpringBootTest(classes = DemoApplication.class)
public class UserServiceTest {

    @Autowired
    private IUserService userService;

    // 测试示例1:年龄范围查询
    @Test
    public void testUserByAgeRange() {
        List<User> userList = userService.getUserByAgeRange(18, 30);
        System.out.println("18-30岁用户:" + userList);
    }

    // 测试示例2:批量插入
    @Test
    public void testBatchInsert() {
        List<User> userList = new ArrayList<>();
        User u1 = new User();
        u1.setUsername("张三");
        u1.setEmail("zhangsan@test.com");
        u1.setAge(25);
        u1.setStatus(1);

        User u2 = new User();
        u2.setUsername("李四");
        u2.setEmail("lisi@test.com");
        u2.setAge(28);
        u2.setStatus(1);

        userList.add(u1);
        userList.add(u2);
        int count = userService.batchInsertUsers(userList);
        System.out.println("批量插入成功数量:" + count);
    }

    // 测试示例3:模糊查询+排序
    @Test
    public void testListByUsernameLike() {
        List<User> userList = userService.listUsersByUsernameLike("张");
        System.out.println("用户名含'张'的用户(按年龄降序):" + userList);
    }

    // 测试示例4:统计年龄段
    @Test
    public void testCountAgeGroup() {
        Map<String, Long> ageGroupMap = userService.countUserByAgeGroup();
        System.out.println("年龄段统计:" + ageGroupMap);
    }

    // 测试示例5:禁用用户
    @Test
    public void testDisableUser() {
        boolean success = userService.disableUserById(1L);
        System.out.println("禁用用户是否成功:" + success);
    }
}

数据库

CREATE TABLE `t_user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `age` int DEFAULT NULL COMMENT '年龄',
  `status` int DEFAULT 1 COMMENT '状态:1-正常 0-禁用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

总结

自定义Service方法的核心

继承 IService/ServiceImpl 后,可通过 baseMapper 调用自定义Mapper方法,或通过 Wrapper 直接使用MP的内置方法。

关键规范

扩展思路

自定义方法可覆盖“查询封装、批量操作、业务组合、数据统计”等场景,核心是复用MP的基础能力,同时适配业务需求。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文