Go 项目如何集成类似mybatisPlus插件呢?GORM走起!!

导读:

在 Go 项目中,虽然没有像 MyBatis Plus 这样特定的 ORM 插件,但可以使用功能相似的 Go ORM 框架,比如 GORM,它支持链式查询、自动迁移、预加载等功能,与 MyBatis Plus 有相似之处。通过一些插件或扩展,可以实现更丰富的功能,比如软删除、分页查询等。下面是 GORM 集成的一些步骤和相关插件的推荐,本文以之前集成的项目Go语言?IDEA能支持吗?增删查走起?_go idea-CSDN博客为模版在此基础上进行迭代。

目录

 一、引入GORM

二、GORM能力:

2.1分页查询:

2.2软删除

2.3分页拓展

 2.4链式查询

2.5自定义拓展

三、源码改造

3.1改造数据库连接类database.go

3.2改造中间件DBMiddleware

3.3 改造userDao.go

3.4 改造userService.go

3.5 改造router.go

3.6 改造main.go

四、启动

 五、异常情况:

5.1解决思路:

 六、复杂查询拓展:

6.1实体类Orders.go

 6.2新增OrderInfoDTO.go

6.3新增GetUserWithOrders方法:


 一、引入GORM

先在项目中引入 GORM:

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql  # 根据你的数据库类型选择驱动

二、GORM能力:

GORM 提供了一些类似 MyBatis Plus 的功能,比如:

  • 软删除:通过 gorm.Model 或自定义字段来实现软删除。
  • 条件查询:可以通过链式查询构建条件查询。
  • 分页插件:可以手动实现分页,或使用封装的分页插件。

2.1分页查询:

go 一遍集成GORM 的 LimitOffset 方法实现分页查询:

var users []User
db.Limit(10).Offset(20).Find(&users)  // 查询第 21-30 条数据

2.2软删除

例如:通过 gorm.Model 或自定义字段来实现软删除。

type User struct {gorm.ModelName stringAge  int
}db.Delete(&user) // 软删除

2.3分页拓展

可以手动实现分页,或使用封装的分页插件比如分页器 github.com/biezhi/gorm-paginator 

 2.4链式查询

GORM 支持链式调用来构建复杂的查询:

var users []User
db.Where("age > ?", 18).Find(&users)

2.5自定义拓展

如果需要类似 MyBatis Plus 的扩展功能,你可以通过自定义 GORM 的钩子函数(Hooks)或中间件,来实现数据插入、更新时自动添加字段等逻辑。GORM 提供了生命周期回调接口,可以在执行操作前后进行拦截和处理。

三、源码改造

3.1改造数据库连接类database.go

  • 引入 GORM:通过 gorm.io/gormgorm.io/driver/mysql 代替原来的 database/sql

  • 初始化数据库连接:使用 gorm.Open() 方法替代 sql.Open(),并且支持更多的配置参数,比如 charset=utf8mb4parseTime=True

  • GetDB 函数:返回 *gorm.DB 类型的数据库实例,供其他模块使用。

  • 这边删除了原先的func GetDB() *sql.DB { return DB } 方法

package configimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger""log"
)var DB *gorm.DB// InitGormDatabase 初始化 GORM 数据库连接并返回 *gorm.DB
func InitGormDatabase() *gorm.DB {dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",AppConfig.Database.User,AppConfig.Database.Password,AppConfig.Database.Host,AppConfig.Database.Port,AppConfig.Database.DBName,)var err errorDB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Info),})if err != nil {log.Fatalf("Failed to connect to database: %v", err)return nil}log.Println("GORM database successfully connected")return DB
}

3.2改造中间件DBMiddleware

这边说明一下,中间件的引入是刚搭建项目时想从java中的切面编程来实现跨功能关注点的处理。比如数据库的连接。但是呢go没有内置切面的支持。所以就引入了中间件模式,每次调用数据库操作都通过中间件来处理。下面是优化前的中间件:

package middlewareimport ("database/sql""go_tas/dao/database""log"
)type DBMiddleware struct {db *sql.DB
}func NewDBMiddleware() *DBMiddleware {return &DBMiddleware{db: database.GetDB(),}
}func (mw *DBMiddleware) ExecuteQuery(query string, args ...interface{}) (*sql.Rows, error) {rows, err := mw.db.Query(query, args...) // 使用中间件中保存的 dbif err != nil {return nil, mw.logError("Failed to execute query", err)}return rows, nil
}func (mw *DBMiddleware) ExecuteExec(query string, args ...interface{}) (int64, error) {result, err := mw.db.Exec(query, args...) // 使用中间件中保存的 dbif err != nil {return 0, mw.logError("Failed to execute exec", err)}insertID, err := result.LastInsertId()if err != nil {return 0, mw.logError("Failed to get last insert ID", err)}return insertID, nil
}func (mw *DBMiddleware) BeginTransaction() (*sql.Tx, error) {tx, err := mw.db.Begin() // 使用中间件中保存的 dbif err != nil {return nil, mw.logError("Failed to begin transaction", err)}return tx, nil
}func (mw *DBMiddleware) logError(message string, err error) error {log.Printf("%s: %v", message, err)return err
}

使用原生的 database/sql 改造为使用 GORM,可以直接使用 GORM 的功能来处理查询、事务等操作。GORM 已经封装了这些常见的操作,并且支持更简洁的 API。

下面是改造后的 middleware 模块,使用 GORM 替代 database/sql

  1. gorm.DB 替换 sql.DBDBMiddleware 中的 db 现在使用 *gorm.DB,所有的数据库操作通过 GORM 进行。

  2. ExecuteQuery 方法

    • 使用 GORM 的 Raw 方法执行原生 SQL 查询,并通过 Scan 将结果映射到传入的 model 结构体。
    • 原生 SQL 查询返回的结果可以映射到结构体切片中。
    var users []User
    middleware.ExecuteQuery(&users, "SELECT * FROM users WHERE age > ?", 18)
    

  3. ExecuteExec 方法

    • 使用 GORM 的 Exec 方法执行修改(插入、更新、删除)语句。
    • 返回执行后影响的行数,而不是插入 ID。
  4. 事务管理

    • 使用 GORM 的 Begin 方法开启事务,返回事务对象 *gorm.DB
    tx, err := middleware.BeginTransaction()
    if err != nil {// handle error
    }
    // 在事务中执行操作
    err = tx.Create(&user).Error
    if err != nil {tx.Rollback()
    } else {tx.Commit()
    }
    

    中间件现在可以使用 GORM 的功能,简化数据库操作并支持复杂的 ORM 功能。

package middlewareimport ("go_tas/dao/database""log""gorm.io/gorm"
)type DBMiddleware struct {db *gorm.DB
}func NewDBMiddleware() *DBMiddleware {return &DBMiddleware{db: database.GetDB(), // 使用 GORM 的 DB 实例}
}// ExecuteQuery 执行查询语句
func (mw *DBMiddleware) ExecuteQuery(model interface{}, query string, args ...interface{}) error {result := mw.db.Raw(query, args...).Scan(model) // 使用 GORM 的 Raw 方法if result.Error != nil {return mw.logError("Failed to execute query", result.Error)}return nil
}// ExecuteExec 执行修改语句(插入、更新、删除)
func (mw *DBMiddleware) ExecuteExec(query string, args ...interface{}) (int64, error) {result := mw.db.Exec(query, args...) // 使用 GORM 的 Exec 方法if result.Error != nil {return 0, mw.logError("Failed to execute exec", result.Error)}return result.RowsAffected, nil // 返回影响的行数
}// BeginTransaction 开启事务
func (mw *DBMiddleware) BeginTransaction() (*gorm.DB, error) {tx := mw.db.Begin() // 使用 GORM 的事务支持if tx.Error != nil {return nil, mw.logError("Failed to begin transaction", tx.Error)}return tx, nil
}// logError 记录错误信息
func (mw *DBMiddleware) logError(message string, err error) error {log.Printf("%s: %v", message, err)return err
}

3.3 改造userDao.go

使用原生 SQL 改造为使用 GORM,可以直接利用 GORM 的模型操作方法来简化数据库操作。GORM 允许直接对结构体进行增删改查,而不需要手动编写 SQL 查询

package daoimport ("go_tas/entity""gorm.io/gorm""log"
)type UserDAO struct {db *gorm.DB
}// NewUserDAO 创建新的 UserDAO 实例
func NewUserDAO(db *gorm.DB) *UserDAO {return &UserDAO{db: db}
}// GetAllUsers 获取所有用户
func (dao *UserDAO) GetAllUsers() ([]entity.User, error) {var users []entity.User// 使用 GORM 查询所有用户if err := dao.db.Find(&users).Error; err != nil {log.Printf("Failed to get users: %v", err)return nil, err}return users, nil
}// CreateUser 创建新用户
func (dao *UserDAO) CreateUser(user *entity.User) (int64, error) {// 使用 GORM 创建用户if err := dao.db.Create(user).Error; err != nil {log.Printf("Failed to create user: %v", err)return 0, err}// 返回创建的用户 IDreturn int64(user.ID), nil
}

3.4 改造userService.go

使用 GORM 替代原生 SQL 操作来进行数据处理。可以将事务处理和数据库操作使用 GORM 的特性进行简化和改造

package serviceimport ("encoding/json""go_tas/dao""go_tas/entity""go_tas/utils""gorm.io/gorm""net/http"
)// GetUsers 获取所有用户
func GetUsers(w http.ResponseWriter, r *http.Request, db *gorm.DB) {userDAO := dao.NewUserDAO(db)users, err := userDAO.GetAllUsers()if err != nil {utils.HandleError(w, http.StatusInternalServerError, "Failed to retrieve users", err)return}respondWithJSON(w, http.StatusOK, users)
}// CreateUser 创建新用户
func CreateUser(w http.ResponseWriter, r *http.Request, db *gorm.DB) {var user entity.Userif err := json.NewDecoder(r.Body).Decode(&user); err != nil {utils.HandleError(w, http.StatusBadRequest, "Invalid request payload", err)return}// 开始一个事务tx := db.Begin()if tx.Error != nil {utils.HandleError(w, http.StatusInternalServerError, "Failed to begin transaction", tx.Error)return}defer func() {if r := recover(); r != nil {tx.Rollback() // 回滚事务utils.HandleError(w, http.StatusInternalServerError, "Internal server error", nil)}}()// 插入用户数据userDAO := dao.NewUserDAO(tx)if _, err := userDAO.CreateUser(&user); err != nil {tx.Rollback() // 回滚事务utils.HandleError(w, http.StatusInternalServerError, "Failed to create user", err)return}// 提交事务if err := tx.Commit().Error; err != nil {utils.HandleError(w, http.StatusInternalServerError, "Failed to commit transaction", err)return}respondWithJSON(w, http.StatusCreated, user)
}// respondWithJSON 处理JSON响应
func respondWithJSON(w http.ResponseWriter, status int, payload interface{}) {w.Header().Set("Content-Type", "application/json")w.WriteHeader(status)if err := json.NewEncoder(w).Encode(payload); err != nil {utils.HandleError(w, http.StatusInternalServerError, "Failed to encode response data", err)}
}

3.5 改造router.go

router 中的数据库操作从 dbMiddleware 改为使用 GORM 数据库连接,并清理代码逻辑

package routerimport ("github.com/gorilla/mux"httpSwagger "github.com/swaggo/http-swagger""go_tas/controller""go_tas/middleware""go_tas/service""gorm.io/gorm""net/http"
)func InitRouter(authMiddleware *middleware.CustomAuthMiddleware, db *gorm.DB) *mux.Router {r := mux.NewRouter()// 添加身份验证中间件r.Use(authMiddleware.Middleware)// 使用 GORM 数据库连接r.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {service.GetUsers(w, r, db)}).Methods("GET")r.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {service.CreateUser(w, r, db)}).Methods("POST")// 设备控制接口r.HandleFunc("/tas/control", controller.Control).Methods("POST")r.HandleFunc("/tas/adminControl", controller.AdminControl).Methods("POST")// Swagger Handlerr.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler)return r
}

3.6 改造main.go

main 函数中,可以将原本使用的 dbMiddleware 改为直接使用 GORM 初始化的数据库连接,以便与前面改造的代码保持一致

package mainimport ("go_tas/config""go_tas/logger""go_tas/middleware""go_tas/router""log""net/http"
)func main() {// 初始化配置config.InitConfig()log.Println("Config initialized")// 初始化数据库,获取 GORM 数据库连接db := config.InitGormDatabase()if db == nil {log.Fatal("Failed to initialize database")}log.Println("Database initialized with GORM")// 初始化 Redisconfig.InitRedis()log.Println("Redis initialized")// 初始化日志logger.InitLogger()// 初始化认证中间件appCode := config.AppConfig.AppCodeappSecret := config.AppConfig.AppSecretauthMiddleware := middleware.NewCustomAuthMiddleware(appCode, appSecret)// 初始化路由并传递 GORM 数据库连接r := router.InitRouter(authMiddleware, db)log.Println("authMiddleware initialized")// 启动服务器log.Println("Starting server on :8080")log.Fatal(http.ListenAndServe(":8080", r))
}

四、启动

 五、异常情况:

如果提示Table 'go_data_base.users' doesn't exist这种情况可以查看一下实体类,原因可能是由于查询时表名不匹配造成的。GORM 默认会使用复数形式表名进行查询,因此它在查找 users 表,而你的实际表名是 user

5.1解决思路:

可以通过在 GORM 模型中设置表名

package entitytype User struct {ID    int    `json:"id"`Name  string `json:"name"`Email string `json:"email"`
}// TableName 指定表名为 user
func (User) TableName() string {return "user"
}

 六、复杂查询拓展:

如果涉及多表关联查询则可使用Joins来进行SQL联表查询,下面举个栗子:

6.1实体类Orders.go

package entitytype Orders struct {ID          int    `json:"id"`UserId      int    `json:"user_id"`Amount      int    `json:"amount"`Description string `json:"description"`
}func (Orders) TableName() string {return "orders"
}

 6.2新增OrderInfoDTO.go

package dtotype OrderInfoDTO struct {ID          int    `json:"id"`Name        string `json:"name"`Email       string `json:"email"`Amount      int    `json:"amount"`Description string `json:"description"`
}

6.3新增GetUserWithOrders方法:

在userDao.go 新增一个GetUserWithOrders方法,Joins 用于执行 SQL 联表查Select("users.*, orders.amount") 指定返回的字段,你可以选择返回哪些表的字段Scan(&users) 将查询结果扫描到 users 切片中。

func (dao *UserDAO) GetUsersWithOrderInfo() ([]dto.OrderInfoDTO, error) {var userInfo []dto.OrderInfoDTOerr := dao.db.Table("user").Joins("LEFT JOIN orders ON orders.user_id = user.id").Select("user.*, orders.*").Scan(&userInfo).Errorif err != nil {log.Printf("Failed to get users with order info: %v", err)return nil, err}return userInfo, nil
}

最后将数据库的语句:

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',`amount` int(10) NULL DEFAULT NULL COMMENT '支付金额/分',`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品描述',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

如果需要源码的同学评论区把邮箱放置一下哈!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881872.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE】——TCP应答报文机制,超时重传机制

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:TCP协议(面试重点重点) 1:报头长度 2:…

Linux学习网络编程学习(TCP和UDP)

文章目录 网络编程主要函数介绍1、socket函数2、bind函数转换端口和IP形式的函数 3、listen函数4、accept函数网络模式(TCP&UDP)1、面向连接的TCP流模式2、UDP用户数据包模式 编写一个简单服务端编程5、connect函数编写一个简单客户端编程 超级客户端…

国产单片机及其特点

国产单片机在近年来取得了显著的发展,不仅在技术上不断突破,还在市场上占据了越来越重要的位置。 主要国产单片机品牌及特点 兆易创新(GD) 主要系列:GD32系列,基于ARM Cortex-M内核。特点:高性能…

PDT 数据集:首个基于无人机的高精密度树木病虫害目标检测数据集

2024-09-24,由中国山东计算机科学中心、北京大学等机构联合创建了Pests and Diseases Tree(PDT)数据集,目的解决农业领域中病虫害检测模型开发中专业数据集缺失的问题。通过集成公共数据和网络数据,进一步推出了Common…

前端笔记(二):svg图标;git

一、svg图标 原视频 注意:图片是使用的png但是图标是使用的svg; (1)配置svg ①main.js里引入icons目录 ②调用函数遍历使用svg ③配置symbolId前都加了icon-,所以引用时应该加icon- ④但是使用时没有加因为组件里…

2024.10.15 sql

刷题网站&#xff1a; 牛客网 select device_id as user_infos_example from user_profile where id < 2 select device_id, university from user_profile where university"北京大学" select device_id, gender, age, university from user_profile where ag…

计算机毕业设计Django+Vue.js豆瓣图书推荐系统 图书评论情感分析 豆瓣图书可视化大屏 豆瓣图书爬虫 数据分析 图书大数据 大数据毕业设计 机器学习

《DjangoVue.js豆瓣图书推荐系统》开题报告 一、研究背景与意义 1. 研究背景 随着数字化时代的来临&#xff0c;图书资源日益丰富&#xff0c;用户面临着信息过载的问题。如何在海量图书中快速找到符合个人兴趣和需求的书籍成为了亟待解决的问题。传统的图书检索方式往往基于…

javaweb以html方式集成富文本编辑器TinyMce

前言&#xff1a; 单一的批量图片上传按钮&#xff0c;禁用tinymce编辑器&#xff0c;但是还可以操作图片编辑&#xff1b; 多元化格式的富文本编辑要求&#xff1b; 采用tinymce实现。 附&#xff1a; tinymce中文手册网站&#xff1a; http://tinymce.ax-z.cn/download-all.…

空间解析几何 3:空间点到线段和平面的距离【附MATLAB代码】

目录 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 function [dis,P2,t] point2Line (A1,B1,C1) %求空间一点到一线段的最短距离 %[dis,P2,Q2]pointSegmentDistance(A,B,C) %A B为线段首末端…

使用LlamaFactory进行模型微调

使用LlamaFactory进行模型微调 简介 论文地址&#xff1a;https://arxiv.org/pdf/2403.13372 仓库地址&#xff1a;https://github.com/hiyouga/LLaMA-Factory/tree/main 名词解释 1. 预训练 (Pre-training, PT) 预训练是指模型在大规模无监督数据集上进行初步训练的过程…

最强 OpenAI o1 逻辑推理正确率仅 50%!清华、智谱推出「大模型逻辑推理新基准」

9.11 和 9.9 哪个大&#xff1f; 这一连人类幼儿园儿童都能回答的问题&#xff0c;曾经&#xff08;至今&#xff09;难倒了众多大语言模型&#xff08;LLM&#xff09;。 然而&#xff0c;要想达到通用人工智能&#xff08;AGI&#xff09;的水平&#xff0c;LLM 不仅要完成“…

居民小区的有序充电策略及解决方案

0引言 全球经济增长导致化石能源过度消耗&#xff0c;加剧环境污染。电动汽车因其环保优势迅速崛起&#xff0c;预计到2030年中国电动汽车保有量将达到6000万辆。这有助于减少化石能源依赖&#xff0c;推广绿色出行&#xff0c;但也对电网稳定性构成挑战。因此&#xff0c;研究…

2.1 HTML5 - Canvas标签

文章目录 引言Canvas标签概述定义实例&#xff1a;创建画布 理解Canvas坐标系概述实例&#xff1a;获取Canvas坐标 获取Canvas环境上下文概述实例&#xff1a;获取Canvas上下文设置渐变色效果 结语 引言 大家好&#xff0c;今天我们要一起探索HTML5中一个非常有趣且强大的特性…

001 Hadoop安装、Spring整合测试

Hadoop安装、整合测试 文章目录 Hadoop安装、整合测试1.简介1.优点2.组成 2.安装1.安装jdk&#xff08;如已安装可跳过&#xff09;2.安装hadoop1.安装2. 修改配置文件core-site.xml3. 修改配置文件hdfs-site.xml4.启动hadoop5.启动yarn6.执行jps查看7.相关端口及配置位置8.访问…

python中不变的数据类型有哪些

在Python中&#xff0c;不可变&#xff08;immutable&#xff09;数据类型是指一旦创建了这些类型的对象后&#xff0c;就不能改变其值。Python中的不可变数据类型包括以下几种&#xff1a; 数字 (int, float, complex): 这些类型的数值一旦创建就不能更改。例如&#xff0c;如…

Flutter 与 React Native - 详细深入对比分析(2024 年)

超长内容预警&#xff0c;建议收藏后阅。 Flutter 和 React Native 是跨平台应用程序开发的两个领先工具。了解它们的差异以及各自的最佳用例。 什么是Flutter&#xff1f; Flutter 是 Google 于 2018 年发布的用户界面 (UI) 软件开发套件。Flutter 可让您为多种平台和操作系统…

在线深度学习:爱奇艺效果广告分钟级模型优化

01# 背景 在效果广告投放场景中&#xff0c;媒体侧需要准确衡量每次请求的价值&#xff0c;模型预估值在广告竞价中扮演着核心角色。模型预估精度的提升&#xff0c;是改善媒体侧变现效率、提升广告收益的核心技术驱动力。 此前&#xff0c;爱奇艺效果广告预估模型为小时级模型…

构建流媒体管道:利用 Docker 部署 Nginx-RTMP 从 FFmpeg RTMP 推流到 HLS 播放的完整流程

最近要实现一个类似导播台的功能&#xff0c;于是我先用 FFmpeg 实现一个参考对照的 Demo&#xff0c;我将其整理为一篇文章&#xff0c;方便后续大家或者和自己参考&#xff01; 1、软件工具介绍 本次部署相关软件 / 工具如下&#xff1a; FFmpeg&#xff1a;全称是 Fast Fo…

软件确认测试内容和方法分享,CMA、CNAS第三方软件检测机构推荐

在现代软件开发中&#xff0c;软件确认测试扮演着至关重要的角色。它不仅帮助开发团队识别系统中的缺陷&#xff0c;还确保软件产品符合用户需求和期望。 软件确认测试旨在验证软件系统的性能和功能是否符合设计规格和用户需求。它通常在软件开发的后期进行&#xff0c;以确保…

火语言RPA流程组件介绍--浏览器上传文件

&#x1f6a9;【组件功能】&#xff1a;在浏览器内自动点击上传功能按钮&#xff0c;选择本地文件完成文件网页上传 配置预览 配置说明 目标元素 支持T或# 通过捕获网页元素或填写css,xpath获取网页元素作为操作目标 上传文件路径 支持T或# 默认FLOW输入项 需要上传的文件…