diff --git a/cutejava/README.md b/cutejava/README.md index c0568f26..2f6c9a0e 100644 --- a/cutejava/README.md +++ b/cutejava/README.md @@ -1,4 +1,4 @@ -
ListquickList(Q criteria); + + List quickList(LambdaQueryWrapper wrapper); + + List quickList(Q criteria, Class targetClazz); + + List quickList(LambdaQueryWrapper wrapper, Class targetClazz); + + PageResult quickPage(LambdaQueryWrapper wrapper, IPage pageable); + + PageResult quickPage(LambdaQueryWrapper wrapper, IPage pageable, Class targetClazz); + + PageResult quickPage(Q criteria, IPage pageable, Class targetClazz); + + PageResultquickPage(Q criteria, IPage pageable); + + int quickUpdate(LambdaQueryWrapper wrapper, T entity); + + int quickDelete(LambdaQueryWrapper wrapper); +} diff --git a/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/interfaces/impl/EasyServiceImpl.java b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/interfaces/impl/EasyServiceImpl.java new file mode 100644 index 00000000..cabd24e1 --- /dev/null +++ b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/interfaces/impl/EasyServiceImpl.java @@ -0,0 +1,260 @@ +/* + * Copyright 2021-2025 Tian Jun + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 cn.odboy.mybatis.interfaces.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.odboy.base.PageResult; +import cn.odboy.exception.BadRequestException; +import cn.odboy.mybatis.interfaces.EasyMapper; +import cn.odboy.mybatis.util.MybatisHelper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.ibatis.binding.MapperMethod; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +/** + * 公共抽象Mapper接口类 + * + * @author odboy + * @date 2022-04-03 + */ +public class EasyServiceImpl , T> extends ServiceImpl { + public LambdaQueryWrapper quick() { + return new LambdaQueryWrapper<>(); + } + + /** + * 快速插入 + * + * @param resources / + */ + public int quickSave(G resources) { + return this.getBaseMapper().insert(BeanUtil.copyProperties(resources, this.getEntityClass())); + } + + /** + * 快速批量插入 + * + * @param resources / + */ + public int quickSaveBatch(List resources) { + return this.getBaseMapper().insertBatchSomeColumn(BeanUtil.copyToList(resources, this.getEntityClass())); + } + + /** + * 快速更新 + * + * @param resources / + */ + public int quickModifyById(G resources) { + return this.getBaseMapper().updateById(BeanUtil.copyProperties(resources, this.getEntityClass())); + } + + /** + * 快速批量更新 + * + * @param resources / + * @param batchSize 每批数量 + */ + public boolean quickModifyBatchById(Collection resources, int batchSize) { + String sqlStatement = this.getSqlStatement(SqlMethod.UPDATE_BY_ID); + return this.executeBatch(resources, batchSize, (sqlSession, entity) -> { + MapperMethod.ParamMap param = new MapperMethod.ParamMap<>(); + param.put("et", BeanUtil.copyProperties(entity, this.getEntityClass())); + sqlSession.update(sqlStatement, param); + }); + } + + /** + * 通过id查询 + * + * @param id / + * @param targetClazz 目标类型 + */ + public G quickGetOneById(Serializable id, Class targetClazz) { + T entity = this.getById(id); + return entity == null ? null : BeanUtil.copyProperties(entity, targetClazz); + } + + /** + * 查一条数据 + * + * @param wrapper 制造条件 + */ + public T quickGetOne(LambdaQueryWrapper wrapper, SFunction orderColumn) { + if (orderColumn == null) { + throw new BadRequestException("参数orderColumn(排序的列)必填"); + } + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + wrapper.last("limit 1"); + wrapper.orderByDesc(orderColumn); + List ts = baseMapper.selectList(wrapper); + if (ts.isEmpty()) { + return null; + } + return ts.stream().findFirst().get(); + } + + public G quickGetOne(LambdaQueryWrapper wrapper, SFunction orderColumn, Class clazz) { + if (orderColumn == null) { + throw new BadRequestException("参数orderColumn(排序的列)必填"); + } + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + wrapper.last("limit 1"); + wrapper.orderByDesc(orderColumn); + List ts = baseMapper.selectList(wrapper); + if (ts.isEmpty()) { + return null; + } + return BeanUtil.copyProperties(ts.stream().findFirst().get(), clazz); + } + + /** + * 通过id集合查询 + * + * @param ids / + * @param targetClazz 目标类型 + */ + public List quickListByIds(List ids, Class targetClazz) { + List entitys = this.listByIds(ids); + return entitys == null || entitys.isEmpty() ? CollUtil.newArrayList() : BeanUtil.copyToList(entitys, targetClazz); + } + + /** + * 查有关的数据 + * + * @param criteria 动态条件 + */ + public ListquickList(Q criteria) { + QueryWrapper predicate = MybatisHelper.build(criteria); + return baseMapper.selectList(predicate); + } + + /** + * 查有关的数据 + * + * @param wrapper 制造条件 + */ + public List quickList(LambdaQueryWrapper wrapper) { + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + return baseMapper.selectList(wrapper); + } + + /** + * 查有关的数据并转成目标类型的数据 + * + * @param criteria 动态条件 + * @param targetClazz 目标类型 + */ + public List quickList(Q criteria, Class targetClazz) { + QueryWrapper predicate = MybatisHelper.build(criteria); + List data = baseMapper.selectList(predicate); + return BeanUtil.copyToList(data, targetClazz); + } + + /** + * 查有关的数据并转换为目标类型 + * + * @param wrapper 制造条件 + * @param targetClazz 目标类型 + */ + public List quickList(LambdaQueryWrapper wrapper, Class targetClazz) { + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + return BeanUtil.copyToList(baseMapper.selectList(wrapper), targetClazz); + } + + /** + * 查有关的分页数据 + * + * @param wrapper 制造条件 + * @param pageable 分页参数 + */ + public PageResult quickPage(LambdaQueryWrapper wrapper, IPage pageable) { + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + IPage originPageData = baseMapper.selectPage(pageable, wrapper); + return new PageResult<>(originPageData.getRecords(), originPageData.getTotal()); + } + + /** + * 查有关的分页数据 + * + * @param wrapper 制造条件 + * @param pageable 分页参数 + * @param targetClazz 目标类型 + */ + public PageResult quickPage(LambdaQueryWrapper wrapper, IPage pageable, Class targetClazz) { + if (wrapper == null) { + wrapper = new LambdaQueryWrapper<>(); + } + IPage originPageData = baseMapper.selectPage(pageable, wrapper); + return new PageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal()); + } + + public PageResult quickPage(Q criteria, IPage pageable, Class targetClazz) { + QueryWrapper wrapper = MybatisHelper.build(criteria); + IPage originPageData = baseMapper.selectPage(pageable, wrapper); + return new PageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal()); + } + + public PageResultquickPage(Q criteria, IPage pageable) { + QueryWrapper wrapper = MybatisHelper.build(criteria); + IPage originPageData = baseMapper.selectPage(pageable, wrapper); + return new PageResult<>(originPageData.getRecords(), originPageData.getTotal()); + } + + /** + * 条件更新 + * + * @param wrapper 制造条件 + * @param entity 更新内容 + */ + public int quickUpdate(LambdaQueryWrapper wrapper, T entity) { + if (wrapper == null) { + throw new BadRequestException("参数wrapper必填"); + } + return baseMapper.update(entity, wrapper); + } + + /** + * 条件删除 + * + * @param wrapper 制造条件 + */ + public int quickDelete(LambdaQueryWrapper wrapper) { + if (wrapper == null) { + throw new BadRequestException("参数wrapper必填"); + } + return baseMapper.delete(wrapper); + } +} diff --git a/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/CmdGenHelper.java b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/CmdGenHelper.java new file mode 100644 index 00000000..96a9e1ed --- /dev/null +++ b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/CmdGenHelper.java @@ -0,0 +1,195 @@ +/* + * Copyright 2021-2025 Tian Jun + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 cn.odboy.mybatis.util; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.generator.FastAutoGenerator; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery; +import com.baomidou.mybatisplus.generator.config.rules.DateType; +import com.baomidou.mybatisplus.generator.config.rules.DbColumnType; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler; +import lombok.Data; + +import java.sql.Types; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +/** + * 代码生成器入口 + * + * @author odboy + * @date 2025-01-11 + */ +@Data +public class CmdGenHelper { + /** + * 数据库类型 MySQL + */ + private static final IDbQuery DB_QUERY = new MySqlQuery(); + /** + * 类型转换 + */ + private static final String TYPE_TINY_INT = "tinyint"; + private static final String TYPE_DATETIME = "datetime"; + private static final String TYPE_DATE = "date"; + private String databaseUrl; + private String databaseUsername; + private String databasePassword; + private String driverClassName; + private String parentPackageName; + private String parentPackageModuleName; + + /** + * 代码生成函数 + * + * @param tablePrefix 表前缀(可空) + * @param tableNames 表名称, 多个用逗号分隔 + */ + public void gen(String tablePrefix, List tableNames) { + // 1.数据库配置 + DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig + .Builder(this.databaseUrl, this.databaseUsername, this.databasePassword) + .driverClassName(this.driverClassName); + dataSourceConfigBuilder.dbQuery(DB_QUERY); + dataSourceConfigBuilder.keyWordsHandler(new MySqlKeyWordsHandler()); + // 1.1.快速生成器 + FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder); + // 2.全局配置 + // 自定义类型转换 + fastAutoGenerator.dataSourceConfig(getDataSourceConfigConsumer()); + // 覆盖已生成文件 + // 添加swagger注解 + // 设置注释的作者 + // 设置注释的日期格式 + // 使用java8新的时间类型 + fastAutoGenerator.globalConfig(getGlobalConfigConsumer()); + // 3.包配置 + // 设置父包名 + // 设置父包模块名 + // 设置MVC下各个模块的包名 + // 设置XML资源文件的目录 + fastAutoGenerator.packageConfig(getPackageConfigConsumer()); + // 4.模板配置 + // 使用Freemarker引擎模板, 默认的是Velocity引擎模板 + AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine(); + fastAutoGenerator.templateEngine(templateEngine); + // 5.策略配置 + // 设置需要生成的表名 + // 设置过滤表前缀 + fastAutoGenerator.strategyConfig(getStrategyConfigConsumer(tableNames) + ); + if (tablePrefix != null) { + // 表前缀, 可多个 + fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.addTablePrefix(tablePrefix)); + } + // 5.1.Entity策略配置 + // 生成实体时生成字段的注解, 包括@TableId注解等 + // 数据库表和字段映射到实体的命名策略, 为下划线转驼峰 + // 全局主键类型为None + // 实体名称格式化为XXXEntity + fastAutoGenerator.strategyConfig(getEntityConfigConsumer()); + // 5.2.Controller策略配置 + // 开启生成@RestController控制器 + fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder().enableRestStyle()); + // 如果不需要生成Controller + // fastAutoGenerator.templateConfig(templateConfig -> templateConfig.controller("")); + // 5.3.Service策略配置 + // 格式化service接口和实现类的文件名称, 去掉默认的ServiceName前面的I + fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder + .serviceBuilder() + .formatServiceFileName("%sService") + .formatServiceImplFileName("%sServiceImpl")); + // 5.4.Mapper策略配置 + // 格式化 mapper文件名,格式化xml实现类文件名称 + fastAutoGenerator.strategyConfig(getStrategyConfigConsumer()); + // 6.生成代码 + fastAutoGenerator.execute(); + } + + private static Consumer getEntityConfigConsumer() { + return strategyConfigBuilder -> strategyConfigBuilder + .entityBuilder() + .enableLombok() + // 如果不需要生成注解, 去掉.enableTableFieldAnnotation() + .enableTableFieldAnnotation() + .enableFileOverride() + .naming(NamingStrategy.underline_to_camel) + .columnNaming(NamingStrategy.underline_to_camel) + .idType(IdType.AUTO); + } + + private static Consumer getStrategyConfigConsumer(List tableNames) { + return strategyConfigBuilder -> strategyConfigBuilder + .enableCapitalMode() + .enableSkipView() + .disableSqlFilter() + .addInclude(tableNames) + .mapperBuilder() + .build(); + } + + private Consumer getPackageConfigConsumer() { + return packageConfigBuilder -> packageConfigBuilder + .parent(this.parentPackageName == null ? "cn.codegen" : this.parentPackageName) + .moduleName(this.parentPackageModuleName == null ? "moduleName" : this.parentPackageModuleName) + .entity("domain") + .service("service") + .mapper("mapper") + .serviceImpl("service.service") + .controller("rest") + .pathInfo(Collections.singletonMap(OutputFile.xml, (System.getProperty("os.name").toLowerCase().contains("win") ? "C:\\CodeGen\\resources\\mapper" : "/tmp/CodeGen/resources/mapper"))); + } + + private static Consumer getGlobalConfigConsumer() { + return globalConfigBuilder -> globalConfigBuilder + .enableSwagger() + .outputDir((System.getProperty("os.name").toLowerCase().contains("win") ? "C:\\CodeGen" : "/tmp/CodeGen")) + .author("codegen") + .commentDate("yyyy-MM-dd") + .dateType(DateType.TIME_PACK); + } + + private static Consumer getStrategyConfigConsumer() { + return strategyConfigBuilder -> strategyConfigBuilder + .mapperBuilder() + .formatMapperFileName("%sMapper") + .formatXmlFileName("%sMapper"); + } + + private static Consumer getDataSourceConfigConsumer() { + return builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> { + int typeCode = metaInfo.getJdbcType().TYPE_CODE; + if (typeCode == Types.SMALLINT) { + return DbColumnType.INTEGER; + } + if (typeCode == Types.DATE) { + return DbColumnType.DATE; + } + if (typeCode == Types.TIME) { + return DbColumnType.DATE; + } + if (typeCode == Types.TIMESTAMP) { + return DbColumnType.DATE; + } + return typeRegistry.getColumnType(metaInfo); + }); + } +} \ No newline at end of file diff --git a/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/MybatisHelper.java b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/MybatisHelper.java new file mode 100644 index 00000000..88079801 --- /dev/null +++ b/cutejava/cutejava-common/src/main/java/cn/odboy/mybatis/util/MybatisHelper.java @@ -0,0 +1,239 @@ +package cn.odboy.mybatis.util; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.odboy.base.MyEntity; +import cn.odboy.exception.BadRequestException; +import cn.odboy.mybatis.constant.MpQuery; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 查询条件创建工具 + */ +@Slf4j +public class MybatisHelper { + public static QueryWrapper build(Q query) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (query == null) { + return queryWrapper; + } + Class> clazz = query.getClass(); + try { + List fields = getAllFields(clazz, new ArrayList<>()); + for (Field field : fields) { + if (!field.canAccess(clazz)) { + field.setAccessible(true); + MpQuery q = field.getAnnotation(MpQuery.class); + if (q != null) { + String propName = q.propName(); + String blurry = q.blurry(); + String attributeName = StrUtil.isBlank(propName) ? field.getName() : propName; + attributeName = humpToUnderline(attributeName); + Object fieldVal = field.get(query); + if (ObjectUtil.isNull(fieldVal) || "".equals(fieldVal)) { + continue; + } + if (ObjectUtil.isNotEmpty(blurry)) { + handleBlurryQuery(queryWrapper, blurry, fieldVal); + continue; + } + handleWrapper(q, queryWrapper, attributeName, fieldVal); + } + field.setAccessible(false); + } + } + } catch (Exception e) { + log.error("组装SQL失败", e); + } + return queryWrapper; + } + + private static void handleWrapper(MpQuery q, QueryWrapper queryWrapper, String attributeName, Object fieldVal) { + switch (q.type()) { + case EQUAL: + queryWrapper.eq(attributeName, fieldVal); + break; + case GREATER_THAN: + queryWrapper.ge(attributeName, fieldVal); + break; + case LESS_THAN: + queryWrapper.le(attributeName, fieldVal); + break; + case LESS_THAN_NQ: + queryWrapper.lt(attributeName, fieldVal); + break; + case INNER_LIKE: + queryWrapper.like(attributeName, fieldVal); + break; + case LEFT_LIKE: + queryWrapper.likeLeft(attributeName, fieldVal); + break; + case RIGHT_LIKE: + queryWrapper.likeRight(attributeName, fieldVal); + break; + case IN: + handleInQuery(queryWrapper, attributeName, fieldVal); + break; + case NOT_IN: + handleNotInQuery(queryWrapper, attributeName, fieldVal); + break; + case NOT_EQUAL: + queryWrapper.ne(attributeName, fieldVal); + break; + case NOT_NULL: + queryWrapper.isNotNull(attributeName); + break; + case IS_NULL: + queryWrapper.isNull(attributeName); + break; + case BETWEEN: + handleBetweenQuery(queryWrapper, fieldVal, attributeName); + break; + default: + break; + } + } + + private static void handleBetweenQuery(QueryWrapper queryWrapper, Object fieldVal, String finalAttributeName) { + if (fieldVal instanceof List) { + List