结构
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的内置方法。
关键规范:
- 业务层必须做参数校验,避免非法输入;
- 批量操作/组合操作需加
@transactional保证事务; - 复杂sql建议写在xml中,简单条件用
wrapper更简洁。
扩展思路:
自定义方法可覆盖“查询封装、批量操作、业务组合、数据统计”等场景,核心是复用mp的基础能力,同时适配业务需求。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论