OSS(CDN)配置和文件系统的一些操作

目前Oinone支持的OSS类型

类型 服务
OSS 阿里云OSS
UPYUN 又拍云
MINIO MinIO
HUAWEI_OBS 华为云OBS
LOCAL 本地NGINX文件存储
TENCENT_COS 腾讯云COS

OSS通用yaml配置

cdn:
  oss:
    name: # 名称
    type: # 类型
    bucket:
    uploadUrl: # 上传URL
    downloadUrl: # 下载URL
    accessKeyId:
    accessKeySecret:
    mainDir: # 主目录
    validTime: 3600000
    timeout: 600000
    active: true
    referer:
    localFolderUrl:
    others:
      [key]:
        name: # 名称
        type: # 类型
        bucket:
        uploadUrl: # 上传URL
        downloadUrl: # 下载URL
        accessKeyId:
        accessKeySecret:
        mainDir: # 主目录
        validTime: 3600000
        timeout: 600000
        active: true
        referer:
        localFolderUrl:

PS:others中使用自定义key来指定OSS服务进行文件上传/下载功能。上传/下载必须匹配,否则无法正常使用。

OSS配置示例

阿里云OSS
cdn:
  oss:
    name: 阿里云
    type: OSS
    bucket: pamirs(根据实际情况修改)
    uploadUrl: oss-cn-hangzhou.aliyuncs.com
    downloadUrl: oss-cn-hangzhou.aliyuncs.com
    accessKeyId: 你的accessKeyId
    accessKeySecret: 你的accessKeySecret
    # 根据实际情况修改
    mainDir: upload/
    validTime: 3600000
    timeout: 600000
    active: true
    imageResizeParameter:
    referer:
华为云OBS
cdn:
  oss:
    name: 华为云
    type: HUAWEI_OBS
    bucket: pamirs(根据实际情况修改)
    uploadUrl: obs.cn-east-2.myhuaweicloud.com
    downloadUrl: obs.cn-east-2.myhuaweicloud.com
    accessKeyId: 你的accessKeyId
    accessKeySecret: 你的accessKeySecret
    # 根据实际情况修改
    mainDir: upload/
    validTime: 3600000
    timeout: 600000
    active: true
    allowedOrigin: http://192.168.95.31:8888,https://xxxx.xxxxx.com
    referer:

华为云OBS需要在启动工程增加以下依赖

<okhttp3.version>4.9.3</okhttp3.version>

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>${okhttp3.version}</version>
</dependency>

注意事项
华为云OBS的防盗链配置,仅允许携带特定referer的才可以,而excel导入后端处理的逻辑匿名读的时候是不带referer的,所以会被拒绝

MINIO
文件系统,mino的配置:
cdn:
  oss:
    name: minio
    type: MINIO
    bucket: pamirs(根据实际情况修改)
    uploadUrl: http://192.168.243.6:32190(根据实际情况修改)
    downloadUrl: http://192.168.243.6:9000(根据实际情况修改)
    accessKeyId: 你的accessKeyId
    accessKeySecret: 你的accessKeySecret
    # 根据实际情况修改
    mainDir: upload/
    validTime: 3600000
    timeout: 600000
    active: true
    referer:
    localFolderUrl:

MINIO无公网访问地址下OSS的配置方式: https://doc.oinone.top/yun-wei-shi-jian/7112.html

又拍云
cdn:
  oss:
    name: 又拍云
    type: UPYUN
    bucket: pamirs(根据实际情况修改)
    uploadUrl: v0.api.upyun.com
    downloadUrl: v0.api.upyun.com
    accessKeyId: 你的accessKeyId
    accessKeySecret: 你的accessKeySecret
    # 根据实际情况修改
    mainDir: upload/
    validTime: 3600000
    timeout: 600000
    active: true
    referer: 
本地文件存储
cdn:
  oss:
    name: 本地文件NG系统
    type: LOCAL
    # uploadUrl 这个是Oinone后端服务地址和端口
    uploadUrl: http://127.0.0.1:8091
    # downloadUrl前端地址,即直接映射在nginx的静态资源的路径和端口
    downloadUrl: http://127.0.0.1:8081
    validTime: 3600000
    timeout: 600000
    active: true
    referer:
    # 本地Nginx静态资源目录
    localFolderUrl: /Users/wangxian/nginx/html/designer/static
腾讯云COS
cdn:
  oss:
    name: TENCENT_COS
    type: TENCENT_COS
    bucket: cos-dcode-prod-1252296671
    uploadUrl: cos.ap-shanghai.myqcloud.com
    downloadUrl: cos.ap-shanghai.myqcloud.com
    accessKeyId: 你的accessKeyId
    accessKeySecret: 你的accessKeySecret
    mainDir: upload/demo/
    validTime: 3600000
    timeout: 600000
    active: true
    image-resize-parameter:
    allowedOrigin: https://test.oinone.com,http://127.0.0.1:88
    referer:

OSS配置示例

后台要直接上传文件到OSS,通过FileClientFactory.getClient()获取系统配置的文件系统的客户端

// 获取文件客户端
// 1、获取默认的文件客户端
FileClient fileClient = FileClientFactory.getClient();
// 2、根据cdnKey获取文件客户端(多CDN配置下使用)
FileClient fileClient = FileClientFactory.getClient(resourceFileForm.getCdnKey());

// 示例1
CdnFile cdnFile = FileClientFactory.getClient().upload(fileName, data/**byte[]*/);

//示例2
String fileName = "路径名/" + file.getName();
FileClientFactory.getClient().uploadByFileName(fileName, is/**InputStream*/);

一个完整的示例:

private static Map<String, String> uploadFiles(File unzipDirectory) {
        Map<String, String> result = new HashMap<>();
        File[] files = unzipDirectory.listFiles();
        if (files == null) {
            return result;
        }
        for (File file : files) {
            try (FileInputStream is = new FileInputStream(file)) {
                // 文件名拼接fileName仅是一个示例,根据实际情况修改
                String fileName = "widgetFile/" + file.getName();
                FileClientFactory.getClient().uploadByFileName(fileName, is);
                String url = FileClientFactory.getClient().getDownloadUrl(fileName);
                result.put(file.getName(), url);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/62.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
nation的头像nation数式员工
上一篇 2023年6月20日 pm4:07
下一篇 2023年11月2日 pm1:58

相关推荐

  • 灵活敏捷开发,高效交付项目的6个关键

    项目工程管理 项目工程顶层分层 项目分层设计,划分出 CDM层、 标准业务层 、定制业务层; 沉淀领域业务模型至CDM层; 沉底业内通用功能至标准业务层; 客户定制化功能在定制业务层; 项目内部的层级划分 项目包结构管理及规范 pamirs-demo-api constant【常量的包路径】 enums【枚举类的包路径】 model【该领域核⼼模型的包路径】 pmodel【该领域代理模型的包路径】 tmodel【该领域传输模型的包路径】 service【存放该领域的⾮存储模型如:⽤于传输的临时模型】 utils【工具类】 XXModule【该类是Demo模块的定义】 pamirs-demo-core service【接口实现类】 init【模块初始化⼯作的包路径】 manager 【manager是 service的⼀些公共逻辑,不会定义为独⽴的function的类】 pamirs-demo-view(可选) action【模型对外交互的⾏为的包路径】 项目中模块间依赖 禁止出现api模块依赖core模块的情况,api模块只允许依赖api模块; 根据当前项目结构进行模块划分,避免循环依赖; 规划项目模块 项目阶段,代码开发前,业务架构师需充分的理解需求和蓝图,对系统进行业务域, 功能域的划分;例如:对一个电商系统: 提高系统的可维护性:通过将系统拆分为不同的业务域,每个业务域都有清晰的边界和职责,可以独立开发、测试和维护; 提升开发效率:业务域划分可以使开发团队更加专注于自己负责的业务,减少不必要的沟通和协调,提升开发效率; 促进团队合作:通过业务域划分,每个团队可以负责一个或多个业务域,团队成员之间可以有更高效的合作和协同。 支持系统的扩展和演化:业务域划分可以使系统更加灵活和可扩展。当需要新增一个新的业务功能或调整现有的业务逻辑时,只需要修改对应的业务域,而不需要对整个系统进行改动。 项目文档管理 项目文档管理对于项目的实施,项目进度管理,项目后期维护等都是至关重要的。系统详细的产品文档,测试文档,运维文档,开发文档,项目管理文档等。 协同合作:团队成员可以共享和访问项目文档,促进协同合作和信息共享,避免信息孤岛和重复工作。 知识管理:项目中所获得的知识,对项目的成功和后续的知识积累至关重要。通过良好的文档管理,可以确保项目知识的保存和传承,提高组织的知识管理能力。 问题解决:项目文档中记录了项目的需求、决策、问题和解决方案等信息。当出现问题或需要做决策时,可以通过查阅文档来获取相关信息,加快问题解决的速度,并减少错误和重复。 项目追踪:通过文档管理,可以跟踪项目的进展和状态。可以记录项目的里程碑、任务分配、进度更新等信息,帮助团队了解项目的整体情况,及时发现和解决问题。 知识共享:好的文档管理可以促进知识共享和传播。通过将项目文档进行分类、索引和存档,可以使团队成员更容易找到所需的信息,并从中学习和借鉴经验,提高工作效率和质量。 数据库和事务 多表联合查询 减少需要join的操作出现 用多次查询替代 索引相关 核心业务访问DB的Sql 要命中或者覆盖索引,保存核心业务的响应时间; 控制单表的索引数量,注意联合索引 数据一致性:乐观锁控制,unique�等 事务代码示例 事务相关注意点参考【Oinone如何支持构建分布式项目】:https://doc.oinone.top/kai-fa-shi-jian/5572.html

    2024年2月20日
    1.1K00
  • 字段类型之关系描述的特殊场景(常量关联)

    场景概述 【字段类型之关系与引用】一文中已经描述了各种关系字段的常规写法,还有一些特殊场景如:关系映射中存在常量,或者M2M中间表是大于两个字段构成。 场景描述 1、PetTalent模型增加talentType字段2、PetItem与PetTalent的多对多关系增加talentType(达人类型),3、PetItemRelPetTalent中间表维护petItemId、petTalentId以及talentType,PetDogItem和PetCatItem分别重写petTalents字段,关系中增加常量描述。示意图如下: 实际操作步骤 Step1 新增 TalentTypeEnum package pro.shushi.pamirs.demo.api.enumeration; import pro.shushi.pamirs.meta.annotation.Dict; import pro.shushi.pamirs.meta.common.enmu.BaseEnum; @Dict(dictionary = TalentTypeEnum.DICTIONARY,displayName = "达人类型") public class TalentTypeEnum extends BaseEnum<TalentTypeEnum,Integer> { public static final String DICTIONARY ="demo.TalentTypeEnum"; public final static TalentTypeEnum DOG =create("DOG",1,"狗达人","狗达人"); public final static TalentTypeEnum CAT =create("CAT",2,"猫达人","猫达人"); } Step2 PetTalent模型增加talentType字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.demo.api.enumeration.TalentTypeEnum; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(PetTalent.MODEL_MODEL) @Model(displayName = "宠物达人",summary="宠物达人",labelFields ={"name"}) public class PetTalent extends AbstractDemoIdModel{ public static final String MODEL_MODEL="demo.PetTalent"; @Field(displayName = "达人") private String name; @Field(displayName = "达人类型") private TalentTypeEnum talentType; } Step3 修改PetItem的petTalents字段,在关系描述中增加talentType(达人类型) @Field.many2many(relationFields = {"petItemId"},referenceFields = {"petTalentId","talentType"},through = PetItemRelPetTalent.MODEL_MODEL ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id","talentType"}) @Field(displayName = "推荐达人",summary = "推荐该商品的达人们") private List<PetTalent> petTalents; Step4 PetDogItem增加petTalents字段,重写父类PetItem的关系描述 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Field(displayName = "推荐达人") @Field.many2many( through = "PetItemRelPetTalent", relationFields = {"petItemId"}, referenceFields = {"petTalentId","talentType"} ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id", "#1#"}, domain = " talentType == DOG") private List<PetTalent> petTalents; Step5 PetCatItem增加petTalents字段,重写父类PetItem的关系描述 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Field(displayName = "推荐达人") @Field.many2many( through = "PetItemRelPetTalent", relationFields = {"petItemId"}, referenceFields = {"petTalentId","talentType"} ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id", "#2#"}, domain = " talentType == CAT") private List<PetTalent> petTalents; Step6 PetCatItem增加petTalents字段,many2one关系示例 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Model.model(PetPet.MODEL_MODEL) @Model(displayName…

    2024年5月25日
    1.6K00
  • 后端代码规范

    前言 虽然oinone框架减少了很多的代码,但是低代码部分的代码质量也需要高度关注,不管是写的代码bug多,或者说被吐槽代码不行,还是说写的代码经常被重构,核心点还是没有代码规范的意识和技巧,下面摘录了一些常见的规范要求,去提高后端的代码质量,代码质量提高后,自然效率也会提升。 常见代码规范 **1、规范命名** 命名是写代码中最频繁的操作,比如类、属性、方法、参数等。好的名字应当能遵循以下几点: **见名知意** 比如需要定义一个变量需要来计数 int i = 0; 名称 i 没有任何的实际意义,没有体现出数量的意思,所以我们应当指明数量的名称 int count = 0; **能够读的出来** 如下代码: private String sfzh; private String dhhm; 这些变量的名称,根本读不出来,更别说实际意义了。 所以我们可以使用正确的可以读出来的英文来命名 private String idCardNo; private String phone; **2、规范代码格式** 好的代码格式能够让人感觉看起来代码更加舒适。 好的代码格式应当遵守以下几点: 合适的空格 代码对齐,比如大括号要对齐 及时换行,一行不要写太多代码 好在现在开发工具支持一键格式化,可以帮助美化代码格式,大家统一使用idea的规范即可。 **3、写好代码注释** 在《代码整洁之道》这本书中作者提到了一个观点,注释的恰当用法是用来弥补我们在用代码表达意图时的失败。换句话说,当无法通过读代码来了解代码所表达的意思的时候,就需要用注释来说明。 书的作者之所以这么说,是因为作者觉得随着时间的推移,代码可能会变动,如果不及时更新注释,那么注释就容易产生误导,偏离代码的实际意义。而不及时更新注释的原因是,程序员不喜欢写注释。😒 但是这不意味着可以不写注释,当通过代码如果无法表达意思的时候,就需要注释,比如如下代码: for (Integer id : ids) { if (id == 0) { continue; } //做其他事 } 为什么 id == 0 需要跳过,代码是无法看出来了,就需要注释了。 好的注释应当满足一下几点: 解释代码的意图,说明为什么这么写,用来做什么 对参数和返回值注释,入参代表什么,出参代表什么 有警示作用,比如说入参不能为空,或者代码是不是有坑 当代码还未完成时可以使用 todo 注释来标记 代码review发现漏洞时 可以使用 fixme 注释来标记 **4、try catch 内部代码抽成一个方法** try catch代码有时会干扰我们阅读核心的代码逻辑,这时就可以把try catch内部主逻辑抽离成一个单独的方法 如下图是Eureka服务端源码中服务下线的实现中的一段代码 整个方法非常长,try中代码是真正的服务下线的代码实现,finally可以保证读锁最终一定可以释放。 所以这段代码其实就可以对核心的逻辑进行抽取。 protected boolean internalCancel(String appName, String id, boolean isReplication) { try { read.lock(); doInternalCancel(appName, id, isReplication); } finally { read.unlock(); } // 剩余代码 } private boolean doInternalCancel(String appName, String id, boolean isReplication) { //真正处理下线的逻辑 } **5、方法别太长** 方法别太长就是字面的意思。一旦代码太长,给人的第一眼感觉就很复杂,让人不想读下去; 同时方法太长的代码可能读起来容易让人摸不着头脑,不知道哪一些代码是同一个业务的功能。 比如代码中有那种2000+行大类,各种if else判断,光理清代码思路就需要用很久时间。🤷🏻‍♀️ 所以一旦方法过长,可以尝试将相同业务功能的代码单独抽取一个方法,最后在主方法中调用即可。 **6、抽取重复代码** 当一份代码重复出现在程序的多处地方,就会造成程序又臭又长,当这份代码的结构要修改时,每一处出现这份代码的地方都得修改,导致程序的扩展性很差。 所以一般遇到这种情况,可以抽取成一个工具类,还可以抽成一个公共的父类。 **7、多用return** 在有时我们平时写代码的情况可能会出现if条件套if的情况,当if条件过多的时候可能会出现如下情况: if (条件1) { if (条件2) { if (条件3) { if (条件4) { if (条件5) { System.out.println("11111"); } } } } } 面对这种情况,可以换种思路,使用return来优化 if (!条件1) { return; } if (!条件2) { return; } if (!条件3) { return; } if (!条件4) { return; } if (!条件5) { return; } System.out.println("11111"); 这样优化就感觉看起来更加直观 **8、if条件表达式不要太复杂**…

    2024年12月11日
    2.6K00
  • 如何自定义覆盖内置模块的页面

    1.首先通过sql查询找到我们需要的页面,从其中的template字段复制出原视图的配置 通过模型编码model在base_view查找需要修改的视图 select * from base_view where model='workflow.WorkflowUserTask' and is_deleted = 0; 2.将base_view的template内容复制到java的core工程的resources目录下新建一个xml文件,修改里面的动作名称 <view widget="WorkFlowImplement"> <template slot="actions"> <action name="$$internal_GotoListTableRouter" priority="1" model="workflow.WorkflowUserTask" tag="contextFreeAction"/> <action name="approveStaging" widget="FlowTaskCommonAction" invisible="!(activeRecord.allowStaging)" priority="2" label="新暂存" model="workflow.WorkflowUserTask" displayName="新暂存"/> <action name="workflow_agree" invisible="!(activeRecord.allowAgree && activeRecord.status == &apos;ACTIVE&apos;)" priority="3" label="新同意" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新同意" goBack="true" validateForm="true" loadRootData="true"/> <action name="workflow_rejust" invisible="!(activeRecord.allowReject && activeRecord.status == &apos;ACTIVE&apos;)" priority="4" label="新拒绝" model="workflow.WorkflowUserTask" displayName="新拒绝" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_turnon" invisible="!(activeRecord.taskType == &apos;APPROVE&apos; && activeRecord.allowTransfer && activeRecord.status == &apos;ACTIVE&apos;)" priority="5" label="新转交" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新转交" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_addsign" invisible="!(activeRecord.taskType == &apos;APPROVE&apos; && activeRecord.allowAddSign && activeRecord.status == &apos;ACTIVE&apos;)" priority="6" label="新加签" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新加签" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_write_fallback" invisible="!(activeRecord.taskType == &apos;WRITE&apos; && activeRecord.allowFallback && activeRecord.status == &apos;ACTIVE&apos;)" priority="7" label="新回退" model="workflow.WorkflowUserTask" displayName="新回退" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_sharing" priority="8" label="新分享" model="workflow.WorkflowUserTask" displayName="新分享" goBack="true" loadRootData="true" tag="contextFreeAction"/> </template> <template slot="fields"> <field name="remark" widget="TextArea" invisible="activeRecord.taskType != &apos;APPROVE&apos;" priority="8" model="workflow.WorkflowUserTask" data="remark" displayName="意见备注"/> </template> </view> 3.在生命周期的元数据编辑方法内覆盖视图 package pro.shushi.pamirs.demo.core.init; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; import pro.shushi.pamirs.workflow.app.api.model.WorkflowUserTask; import java.util.Map; @Slf4j @Component @Order(Ordered.LOWEST_PRECEDENCE) public class DemoModuleMetaInstall implements MetaDataEditor { @Override public void edit(AppLifecycleCommand command,…

    2024年7月2日
    1.4K00
  • Oinone开发实践-业务实现多租户方案

    总体方案 业务项目中,需要隔离的模型自定义增加租户字段进行数据隔离; 参考了Mybatis-Plus插件的TenantSqlParser进行的JPA实现,使用jsqlparser解析并修改SQL; 实现获取当前用户租户ID,SQL增删改查时处理租户字段,实现租户数据的隔离 参考项目: https://github.com/baomidou/mybatis-plus https://github.com/JSQLParser/JSqlParser 具体实现方式 1、业务上定义两个基础抽象模型包含租户字段 定义包含ID的基础抽象模型,且包含租户字段(如:公司编码, 用其他字段作为租户字段也可以,根据实际业务情况灵活修改)。 @Model.model(XXIdModel.MODEL_MODEL) @Model.Advanced(type = ModelTypeEnum.ABSTRACT) @Model(displayName = “带公司CODE的基础ID抽象模型”, summary = “带公司Code的Id模型”) public abstract class XXIdModel extends IdModel { public static final String MODEL_MODEL = “demo.biz.XXIdModel”; @Field.String @Field(displayName = “所属公司编码”, invisible = true, index = true) private String companyCode; } 定义包含Code的基础抽象模型,且包含租户字段(如:公司编码, 用其他字段作为租户字段也可以,根据实际业务情况灵活修改)。 @Model.model(XXCodeModel.MODEL_MODEL) @Model.Advanced(type = ModelTypeEnum.ABSTRACT) @Model(displayName = “带公司CODE的基础Code抽象模型”, summary = “带公司CODE的Code模型”) public abstract class XXCodeModel extends CodeModel { public static final String MODEL_MODEL = “demo.biz.XXCodeModel”; @Field.String @Field(displayName = “所属公司编码”, invisible = true, index = true) private String companyCode; } 2、业务模块的模型需租户隔离的都是继承上面这两个模型; @Model.model(PetPetCompany.MODEL_MODEL) @Model(displayName = “宠物公司”, labelFields = “name”) public class PetPetCompany extends AbstractCompanyCodeModel { public static final String MODEL_MODEL = “demo.PetPetCompany”; @Field.String @Field(displayName = “名称”) private String name; @Field.Text @Field(displayName = “简介”) private String introduction; } 3、自定义扩展Session,Session中设置租户信息 每次请求多把登录用户所属公司编码(companyCode)放到Session中;Session扩展参考:https://doc.oinone.top/oio4/9295.html 4、定义拦截器Interceptor进行数据隔离 数据创建和查询通过拦截器把Session中的中的公司编码(companyCode)设置到隔离字段中;拦截器的java示例代码参考: package pro.shushi.pamirs.demo.core.interceptor; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitor; import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList; import net.sf.jsqlparser.expression.operators.relational.NamedExpressionList; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.select.*; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.values.ValuesStatement; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import…

    2024年4月6日
    1.1K00

Leave a Reply

登录后才能评论