mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-06 16:48:24 +08:00
!21 Mybatis-Flex 提供顶级增强 Service 及其实现类
Merge pull request !21 from 王帅/main
This commit is contained in:
commit
10a6ed0421
@ -58,6 +58,7 @@ export default defineConfig({
|
||||
items: [
|
||||
{text: '增删改', link: '/zh/base/add-delete-update'},
|
||||
{text: '查询和分页', link: '/zh/base/query'},
|
||||
{text: 'IService', link: '/zh/base/service'},
|
||||
{text: 'QueryWrapper', link: '/zh/base/querywrapper'},
|
||||
]
|
||||
},
|
||||
|
||||
73
docs/zh/base/service.md
Normal file
73
docs/zh/base/service.md
Normal file
@ -0,0 +1,73 @@
|
||||
# 顶级 Service 接口
|
||||
|
||||
MyBatis-Flex 提供了一个名为 `IService` 的接口,及其默认实现类 `ServiceImpl` ,用于简化在 「Service」 层重复定义 「Mapper」 层的方法。
|
||||
|
||||
> `IService` 接口只是提供了简单且常用的 “增删改查” 方法,更多细节以及复杂的业务,还是需要使用 `BaseMapper` 进行处理。
|
||||
|
||||
## 保存数据
|
||||
|
||||
`IService` 的接口提供了 save、saveOrUpdate、saveBatch 方法,用于保存数据:
|
||||
|
||||
- **save(entity)**:保存一条数据,忽略 null 值的字段。
|
||||
- **saveOrUpdate(entity)**:保存一条数据,如果数据存在则更新数据。
|
||||
- **saveBatch(entities)**:批量保存多条数据。
|
||||
- **saveBatch(entities, size)**:批量保存多条数据,按指定数量切分。
|
||||
|
||||
|
||||
## 删除数据
|
||||
|
||||
`IService` 的接口提供了 remove、removeById、removeByIds、removeByMap 方法,用于删除数据:
|
||||
|
||||
- **remove(query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件来删除数据。
|
||||
- **removeById(id)**:根据主键删除数据,复合主键需要传入一个数组。
|
||||
- **removeByIds(ids)**:根据主键的集合,批量删除多条数据。
|
||||
- **removeByMap(map)**:根据 `Map<字段名,值>` 组成的条件删除数据,字段名和值的关系为相等的关系;同时,防止 "不小心" 全表删除数据,Map 的值不允许为 null 或者空数据。
|
||||
|
||||
|
||||
## 更新数据
|
||||
|
||||
`IService` 的接口提供了 update、updateById、updateByMap 方法,用于更新数据:
|
||||
|
||||
- **update(entity, query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件更新数据,实体类可以没有主键(如果有也会被忽略),实体类的 null 属性,会自动被忽略。
|
||||
- **updateById(entity)**:根据主键更新数据,要求主键值不能为空,否则会抛出异常;同时,数据为 null 的字段不会更新到数据库。
|
||||
- **updateByMap(entity, map)**:根据 `Map<字段名,值>` 组成的条件更新数据,实体类可以没有主键(如果有也会被忽略),实体类的 null 属性,会自动被忽略。
|
||||
|
||||
|
||||
## 查询数据
|
||||
|
||||
### 查询一条数据
|
||||
|
||||
`IService` 的接口提供了 getById、getByIdOpt、getOne、getOneOpt 方法,用于查询一条数据:
|
||||
|
||||
- **getById(id)**:根据主键查询数据。
|
||||
- **getByIdOpt(id)**:根据主键查询数据,并封装为 `Optional` 返回。
|
||||
- **getOne(query)**: 根据 `QueryCondition` 或 `QueryWrapper` 构建的条件查询一条数据。
|
||||
- **getOneOpt(query)**: 根据 `QueryCondition` 或 `QueryWrapper` 构建的条件查询一条数据,并封装为 `Optional` 返回。
|
||||
|
||||
### 查询多条数据
|
||||
|
||||
`IService` 的接口提供了 list、listByIds、listByMap 方法,用于查询多条数据:
|
||||
|
||||
- **list()**:查询所有数据。
|
||||
- **list(query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件查询多条数据。
|
||||
- **listByIds(ids)**:根据主键的集合查询多条数据。
|
||||
- **listByMap(map)**:根据 `Map<字段名,值>` 组成的条件查询多条数据。
|
||||
|
||||
### 查询数据数量
|
||||
|
||||
`IService` 的接口提供了 exists、count 方法,用于查询数据数量;
|
||||
|
||||
- **count()**:查询所有数据数量。
|
||||
- **count(query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件查询数据数量。
|
||||
- **exist(query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件判断数据是否存在。
|
||||
|
||||
### 分页查询数据
|
||||
|
||||
`IService` 的接口提供了 page 方法,用于分页查询数据:
|
||||
|
||||
- **page(page)**:分页查询所有数据。
|
||||
- **page(page, query)**:根据 `QueryCondition` 或 `QueryWrapper` 构建的条件分页查询数据。
|
||||
|
||||
## 其他方法
|
||||
|
||||
- **getBaseMapper()**:获取对应的 `BaseMapper` 接口。
|
||||
@ -62,4 +62,25 @@ public class SqlUtil {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据数据库响应结果判断数据库操作是否成功。
|
||||
*
|
||||
* @param result 数据库操作返回影响条数
|
||||
* @return {@code true} 操作成功,{@code false} 操作失败。
|
||||
*/
|
||||
public static boolean retBool(int result) {
|
||||
return result >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据库响应结果判断数据库操作是否成功。
|
||||
*
|
||||
* @param result 数据库操作返回影响条数
|
||||
* @return {@code true} 操作成功,{@code false} 操作失败。
|
||||
*/
|
||||
public static boolean retBool(long result) {
|
||||
return result >= 1L;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,395 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.spring.service;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryCondition;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.util.CollectionUtil;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
import static com.mybatisflex.core.util.SqlUtil.retBool;
|
||||
|
||||
/**
|
||||
* 由 Mybatis-Flex 提供的顶级增强 Service 接口。
|
||||
*
|
||||
* @author 王帅
|
||||
* @since 2023-05-01
|
||||
* @param <T> 实体类(Entity)类型
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface IService<T> {
|
||||
|
||||
/**
|
||||
* 获取对应实体类(Entity)的基础映射类(BaseMapper)。
|
||||
*
|
||||
* @return 基础映射类(BaseMapper)
|
||||
*/
|
||||
BaseMapper<T> getBaseMapper();
|
||||
|
||||
// ===== 保存(增)操作 =====
|
||||
|
||||
/**
|
||||
* 保存实体类对象数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @return {@code true} 保存成功,{@code false} 保存失败。
|
||||
* @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法,忽略
|
||||
* {@code null} 字段的数据,使数据库配置的默认值生效。
|
||||
*/
|
||||
default boolean save(T entity) {
|
||||
return retBool(getBaseMapper().insertSelective(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者更新实体类对象数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @return {@code true} 保存或更新成功,{@code false} 保存或更新失败。
|
||||
* @apiNote 如果实体类对象主键有值,则更新数据,若没有值,则保存数据。
|
||||
*/
|
||||
default boolean saveOrUpdate(T entity) {
|
||||
return retBool(getBaseMapper().insertOrUpdate(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存实体类对象数据。
|
||||
*
|
||||
* @param entities 实体类对象
|
||||
* @return {@code true} 保存成功,{@code false} 保存失败。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
default boolean saveBatch(Collection<T> entities) {
|
||||
return retBool(getBaseMapper().insertBatch(new ArrayList<>(entities)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存实体类对象数据。
|
||||
*
|
||||
* @param entities 实体类对象
|
||||
* @param size 每次保存切分的数量
|
||||
* @return {@code true} 保存成功,{@code false} 保存失败。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
default boolean saveBatch(Collection<T> entities, int size) {
|
||||
return retBool(getBaseMapper().insertBatch(new ArrayList<>(entities), size));
|
||||
}
|
||||
|
||||
// ===== 删除(删)操作 =====
|
||||
|
||||
/**
|
||||
* 根据查询条件删除数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败。
|
||||
*/
|
||||
default boolean remove(QueryWrapper query) {
|
||||
return retBool(getBaseMapper().deleteByQuery(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件删除数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败。
|
||||
*/
|
||||
default boolean remove(QueryCondition query) {
|
||||
return retBool(getBaseMapper().deleteByCondition(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据主键删除数据。
|
||||
*
|
||||
* @param id 数据主键
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败。
|
||||
*/
|
||||
default boolean removeById(Serializable id) {
|
||||
return retBool(getBaseMapper().deleteById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据主键批量删除数据。
|
||||
*
|
||||
* @param ids 数据主键
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
default boolean removeByIds(Collection<? extends Serializable> ids) {
|
||||
if (CollectionUtil.isEmpty(ids)) {
|
||||
return false;
|
||||
}
|
||||
return retBool(getBaseMapper().deleteBatchByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 {@link Map} 构建查询条件删除数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败。
|
||||
*/
|
||||
default boolean removeByMap(Map<String, Object> query) {
|
||||
return retBool(getBaseMapper().deleteByMap(query));
|
||||
}
|
||||
|
||||
// ===== 更新(改)操作 =====
|
||||
|
||||
/**
|
||||
* 根据查询条件更新数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败。
|
||||
*/
|
||||
default boolean update(T entity, QueryWrapper query) {
|
||||
return retBool(getBaseMapper().updateByQuery(entity, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件更新数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败。
|
||||
*/
|
||||
default boolean update(T entity, QueryCondition query) {
|
||||
return retBool(getBaseMapper().updateByCondition(entity, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据主键更新数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败。
|
||||
*/
|
||||
default boolean updateById(T entity) {
|
||||
return retBool(getBaseMapper().update(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 {@link Map} 构建查询条件更新数据。
|
||||
*
|
||||
* @param entity 实体类对象
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败。
|
||||
*/
|
||||
default boolean updateByMap(T entity, Map<String, Object> query) {
|
||||
return retBool(getBaseMapper().updateByMap(entity, query));
|
||||
}
|
||||
|
||||
// ===== 查询(查)操作 =====
|
||||
|
||||
/**
|
||||
* 根据数据主键查询一条数据。
|
||||
*
|
||||
* @param id 数据主键
|
||||
* @return 查询结果数据
|
||||
*/
|
||||
default T getById(Serializable id) {
|
||||
return getBaseMapper().selectOneById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据主键查询一条数据。
|
||||
*
|
||||
* @param id 数据主键
|
||||
* @return 查询结果数据
|
||||
* @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
|
||||
*/
|
||||
default Optional<T> getByIdOpt(Serializable id) {
|
||||
return Optional.ofNullable(getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询一条数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 查询结果数据
|
||||
*/
|
||||
default T getOne(QueryWrapper query) {
|
||||
return getBaseMapper().selectOneByQuery(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询一条数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 查询结果数据
|
||||
* @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
|
||||
*/
|
||||
default Optional<T> getOneOpt(QueryWrapper query) {
|
||||
return Optional.ofNullable(getOne(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询一条数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 查询结果数据
|
||||
*/
|
||||
default T getOne(QueryCondition query) {
|
||||
return getBaseMapper().selectOneByCondition(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询一条数据。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 查询结果数据
|
||||
* @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
|
||||
*/
|
||||
default Optional<T> getOneOpt(QueryCondition query) {
|
||||
return Optional.ofNullable(getOne(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有数据。
|
||||
*
|
||||
* @return 所有数据
|
||||
*/
|
||||
default List<T> list() {
|
||||
return getBaseMapper().selectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询数据集合。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 数据集合
|
||||
*/
|
||||
default List<T> list(QueryWrapper query) {
|
||||
return getBaseMapper().selectListByQuery(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询数据集合。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 数据集合
|
||||
*/
|
||||
default List<T> list(QueryCondition query) {
|
||||
return getBaseMapper().selectListByCondition(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据主键查询数据集合。
|
||||
*
|
||||
* @param ids 数据主键
|
||||
* @return 数据集合
|
||||
*/
|
||||
default List<T> listByIds(Collection<? extends Serializable> ids) {
|
||||
return getBaseMapper().selectListByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 {@link Map} 构建查询条件查询数据集合。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 数据集合
|
||||
*/
|
||||
default List<T> listByMap(Map<String, Object> query) {
|
||||
return getBaseMapper().selectListByMap(query);
|
||||
}
|
||||
|
||||
// ===== 数量查询操作 =====
|
||||
|
||||
/**
|
||||
* 根据查询条件判断数据是否存在。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 数据存在,{@code false} 数据不存在。
|
||||
*/
|
||||
default boolean exists(QueryWrapper query) {
|
||||
return retBool(count(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件判断数据是否存在。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return {@code true} 数据存在,{@code false} 数据不存在。
|
||||
*/
|
||||
default boolean exists(QueryCondition query) {
|
||||
return retBool(count(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有数据数量。
|
||||
*
|
||||
* @return 所有数据数量
|
||||
*/
|
||||
default long count() {
|
||||
return getBaseMapper().selectCountByQuery(QueryWrapper.create());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询数据数量。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 数据数量
|
||||
*/
|
||||
default long count(QueryWrapper query) {
|
||||
return getBaseMapper().selectCountByQuery(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件查询数据数量。
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 数据数量
|
||||
*/
|
||||
default long count(QueryCondition query) {
|
||||
return getBaseMapper().selectCountByCondition(query);
|
||||
}
|
||||
|
||||
// ===== 分页查询操作 =====
|
||||
|
||||
/**
|
||||
* 分页查询所有数据。
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @return 分页对象
|
||||
*/
|
||||
default Page<T> page(Page<T> page) {
|
||||
return getBaseMapper().paginate(page, QueryWrapper.create());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件分页查询数据。
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param query 查询条件
|
||||
* @return 分页对象
|
||||
*/
|
||||
default Page<T> page(Page<T> page, QueryWrapper query) {
|
||||
return getBaseMapper().paginate(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件分页查询数据。
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param query 查询条件
|
||||
* @return 分页对象
|
||||
*/
|
||||
default Page<T> page(Page<T> page, QueryCondition query) {
|
||||
return getBaseMapper().paginate(page, QueryWrapper.create().where(query));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.spring.service.impl;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.mybatisflex.spring.service.IService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* 由 Mybatis-Flex 提供的顶级增强 Service 接口的默认实现类。
|
||||
*
|
||||
* @author 王帅
|
||||
* @since 2023-05-01
|
||||
* @param <M> 映射类(Mapper)类型
|
||||
* @param <T> 实体类(Entity)类型
|
||||
*/
|
||||
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
|
||||
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
|
||||
|
||||
@Autowired
|
||||
protected M baseMapper;
|
||||
|
||||
@Override
|
||||
public BaseMapper<T> getBaseMapper() {
|
||||
return baseMapper;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user