【REST2SQL】04 REST2SQL第一版Oracle版实现

news2024/11/25 14:55:53

REST2SQL的第一个版本,只支持Oracle数据库,以后会逐步加入其它数据看的支持。

项目文件组织如下:
在这里插入图片描述

1 REST2SQL为项目主目录

主控main()函数、请求日志函数、请求响应函数、请求参数返回函数在此目录。

1.1 import引用包

import (
	"encoding/json"
	"fmt"

	"io"
	"log"
	"net/http"
	"rest2sql/config" //配置信息在config.json文件
	do "rest2sql/dothing"
	"strings"
	"time"
)

1.2 请求信息放在Map里

// 请求信息map
var (
	req   map[string]interface{} = make(map[string]interface{}) //请求参数
	count int                    = 0                            //请求计数器
)

1.3 main() 主控函数

// main()
func main() {
	// 打印配置信息
	fmt.Println("config:", config.Conf)

	//响应所有的请求
	http.HandleFunc("/", handler)
	// http.HandleFunc("/REST", restHandler)
	// http.HandleFunc("/SQL", sqlHandler)

	println("Starting Http Server at", config.Conf.HostPort, "\n")

	//启动监听和服务
	//log.Println(http.ListenAndServe(Conf.HostPort, RequestLogger(http.DefaultServeMux)))
	http.ListenAndServe(config.Conf.HostPort, RequestLogger(http.DefaultServeMux))
	//log.Println(err)

	//测试可以用这个
	//curl -X POST -d "{\"gpdm\":600800}" -H "Content-Type:application/json" http://localhost:8080/rest/blma

}

1.4 请求日志函数

// 请求日志
func RequestLogger(targetMux http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		count++
		start := time.Now()
		targetMux.ServeHTTP(w, r)
		log.Printf(
			"(%v)\t%s\t\t%s\t\t%s\t\t%v",
			count,
			r.Method,
			r.RemoteAddr,
			r.RequestURI,
			time.Since(start),
		)
	})
}

1.5 请求响应函数

// handler
func handler(w http.ResponseWriter, r *http.Request) {
	// 1请求主机Host
	req["Host"] = r.Host

	// 2请求路径Path
	req["Path"] = r.URL.Path
	path := strings.Split(r.URL.Path, "/")
	if len(path) < 3 {
		w.Write([]byte("400 Bad Request错误请求。请尝试/rest/xxx or /sql/xxx"))
		return
	}

	//fmt.Println(path)
	// 3 请求类型REST or SQL
	rors := strings.ToUpper(fmt.Sprint(path[1]))
	// 支持的请求类型
	if !(rors == "REST" || rors == "SQL") {
		w.Write([]byte("400 Bad Request错误请求。请尝试/REST/xxx or /SQL/xxx"))
		return
	}
	req["RESTorSQL"] = rors //请求类型SQL or REST

	// 4 资源名 ResName
	req["ResName"] = path[2] //资源名,表名ResName

	// 5请求方法Method
	req["Method"] = r.Method

	// 6请求头Content-Type
	req["Content-Type"] = r.Header.Get("Content-Type")

	// 7请求数据Data
	data, err := io.ReadAll(r.Body)

	if err != nil {
		w.Write([]byte(err.Error()))
		return
	}
	defer r.Body.Close()
	//反序列化
	if len(data) > 0 {
		var idata interface{}
		//fmt.Println("data:", data)
		err = json.Unmarshal(data, &idata)
		if err != nil {
			w.Write([]byte(err.Error()))
			return
		}
		//fmt.Println("idata:", idata)
		req["Data"] = idata
	} else {
		req["Data"] = ""
	}

	// 8 请求参数
	query := r.URL.Query()
	req["Where"] = query.Get("where")
	req["OrderBy"] = query.Get("orderby")

	//返回http请求参数
	resReturn(w, req)

	//根据请求参数执行不同的操作
	do.DoThing(w, req)
}

1.6 请求参数返回函数

// http请求主要参数直接返回
func resReturn(w http.ResponseWriter, req map[string]interface{}) {
	w.Write([]byte("{\"Request\":"))
	str, err := json.MarshalIndent(req, "", "   ")
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//fmt.Println(str)
	w.Write(str)
	w.Write([]byte(","))
}

2 config配置文件读取子目录

2.1 包名改为 config

//全局变量包

package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"strings"
)

var Conf config //全局变量

func init() {
	Conf = getConfig()
}

// 配置结构体
type config struct {
	DBType     string //数据库类型 :oracle、mysql等
	ConnString string `json:"connString"`
	HostPort   string `json:"hostPort"`
	REST       string `json:"REST"`
	SQL        string `json:"SQL"`
}

// 取配置信息
func getConfig() config {
	bytes, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Println("读取json文件失败:", err)
		panic(nil)
	}
	conf := &config{}
	err = json.Unmarshal(bytes, conf)
	if err != nil {
		log.Println("json解析失败", err)
		panic(nil)
	}
	//数据库类型为数据库的第一部分
	end := strings.Index(conf.ConnString, ":/")
	if end < 0 {
		log.Println("连接字符串设置有误。")
		panic(nil)
	}
	conf.DBType = conf.ConnString[0:end]
	// fmt.Println(conf)
	// fmt.Println("connString:", conf.ConnString)
	// fmt.Println("hostPort:", conf.HostPort)
	return *conf
}

2.2 doc.go 文件设置

// config project doc.go

/*
config document
*/
package config

3 dboracle子目录,Oracle数据库操作

3.1 包名:dboracle

// gooracle project main.go
package dboracle

import (
	"database/sql/driver"
	"encoding/json"

	"io"
	"log"
	"rest2sql/config"

	go_ora "github.com/sijms/go-ora/v2" // 1 go get github.com/sijms/go-ora/v2
)

// Oracle连接字符串
//var ConnStr string = "oracle://blma:5217@127.0.0.1:1521/CQYH"

var ConnString string = config.Conf.ConnString

/*
func main() {
	var (
		sqls   string //sql语句
		result string //sql执行后返回的结果
	)

	// select查询数据
	sqls = "select sysdate from dual"
	result = selectData(sqls)
	fmt.Println(result)

	// delete 删除数据
	sqls = "delete from atop where p_id = -5"
	result = deleteData(sqls)
	fmt.Println(result)

	// update 更新数据
	sqls = "update atop set f_dm = '005217' where p_id = -5217"
	result = updateData(sqls)
	fmt.Println(result)

	// insert 插入一行数据
	sqls = "insert into atop (p_id) values (FLOOR(DBMS_RANDOM.value(0, 100)))"
	result = insertData(sqls)
	fmt.Println(result)
}
*/

// 连接Oracle数据库
func connDB(connStr string) *go_ora.Connection {
	//创建连接
	DB, err := go_ora.NewConnection(connStr)
	dieOnError("Can't open the driver:", err)
	//打开连接
	err = DB.Open()
	dieOnError("Can't open the connection:", err)
	return DB
}

// delete
func DeleteData(deleteSql string) string {
	result, _ := execSQL(deleteSql)
	rows, err := result.RowsAffected()
	dieOnError("Can't delete", err)
	ret := map[string]int{
		"Delete rowsAffected": int(rows),
	}
	jsonBytes, err := json.MarshalIndent(ret, "", "   ")
	dieOnError("map 转 json失败:", err)
	return string(jsonBytes)
}

// update
func UpdateData(updateSql string) string {
	result, _ := execSQL(updateSql)
	rows, err := result.RowsAffected()
	dieOnError("Can't update", err)
	ret := map[string]int{
		"Update rowsAffected": int(rows),
	}
	jsonBytes, err := json.Marshal(ret)
	dieOnError("map 转 json失败:", err)
	return string(jsonBytes)
}

// insert
func InsertData(insertSql string) string {
	result, _ := execSQL(insertSql)
	rows, err := result.RowsAffected()
	dieOnError("Can't insert", err)
	ret := map[string]int{
		"Insert rowsAffected": int(rows),
	}
	jsonBytes, err := json.MarshalIndent(ret, "", "   ")
	dieOnError("map 转 json失败:", err)
	return string(jsonBytes)
}

// 执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML, PLSQL) and return driver.Result object
func execSQL(sqls string) (result driver.Result, err error) {
	//连接数据库
	DB := connDB(ConnString)
	//延迟关闭连接
	defer DB.Close()

	//准备sql语句
	stmt := go_ora.NewStmt(sqls, DB)
	//延迟关闭SQL
	defer stmt.Close()

	//执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML, PLSQL) and return driver.Result object
	result, err = stmt.Exec(nil)
	dieOnError("Can't execSql() ", err)

	return result, err
}

// select查询,结果为json
func SelectData(sqls string) string {
	//连接数据库
	DB := connDB(ConnString)
	//延迟关闭连接
	defer DB.Close()

	//准备sql语句
	stmt := go_ora.NewStmt(sqls, DB)
	//延迟关闭SQL
	defer stmt.Close()

	rows, err := stmt.Query(nil)
	dieOnError("Can't query", err)

	defer rows.Close()

	//fmt.Println(rows)

	columns := rows.Columns()
	//fmt.Println("columns:", columns)
	values := make([]driver.Value, len(columns))
	var dataset []map[string]interface{} //元素为map的切片
	//Header(columns)
	for {
		err = rows.Next(values)
		if err != nil {
			break
		}
		//fmt.Println("values:", values)
		row1 := record(columns, values)
		dataset = append(dataset, row1)

	}
	if err != io.EOF {
		dieOnError("Can't Next", err)
	}

	//切片转json
	jsonBytes, err := json.MarshalIndent(dataset, "", "   ")
	dieOnError("slice 转 json失败:", err)
	//fmt.Println(string(jsonBytes))
	return string(jsonBytes)
}

// 发生错误退出1
func dieOnError(msg string, err error) {
	if err != nil {
		log.Println(msg, err)
		//os.Exit(1)
	}
}

// func Header(columns []string) {

// }

// 一行记录加入 map
func record(columns []string, values []driver.Value) map[string]interface{} {
	mc := make(map[string]interface{}) //一行记录信息放入 map
	for i, c := range values {
		//fmt.Printf("\"%s\":%v,", columns[i], c)
		mc[columns[i]] = c
	}
	//fmt.Println(mc)

	return mc //返回一行记录的信息map
}

/* 查询表的主键方法
select * from user_cons_columns where table_name = 'ATOP'
and constraint_name = (
select constraint_name from user_constraints
where table_name = 'ATOP' and constraint_type = 'P')
order by position
*/

// func returnErr(err error) error {
// 	if err != nil {
// 		return err
// 	}
// 	return nil
// }

// // 7调用存储过程
// func callStoredProcedure() error {
// 	var (
// 		id  int
// 		msg string = strings.Repeat(" ", 2000) //先赋值内容
// 	)
// 	//执行存储过程,
// 	_, err := db.Exec(`BEGIN ora_test2_pro(:1, :2 ); END;`,
// 		id,
// 		sql.Out{Dest: &msg},
// 	)
// 	if err != nil {
// 		return err
// 	}
// 	//输出结果
// 	fmt.Println(msg)
// 	return nil
// }

// // 8.调用函数
// func callFunction() error {
// 	var (
// 		id  int
// 		msg string = strings.Repeat(" ", 2000) //先赋值内容
// 	)
// 	//执行存储过程,
// 	_, err := db.Exec(`BEGIN :1 := ora_test2_func(:2 ); END;`,
// 		sql.Out{Dest: &msg},
// 		id,
// 	)
// 	if err != nil {
// 		return err
// 	}
// 	//输出结果
// 	fmt.Println(msg)
// 	return nil
// }

3.2 doc.go

// gooracle project doc.go

/*
gooracle document
*/
package dboracle

4 dothing主要逻辑处理

4.1 包名dothing

// dothing project dothing.go
package dothing

import (
	"encoding/json"
	"fmt"
	"net/http"
	"rest2sql/config"
	"rest2sql/dboracle"
	"strings"
)

// 当前连接的数据库类型oracle
var (
	DBType string = config.Conf.DBType //数据库类型
	REST   string = config.Conf.REST   //支持的REST:GET,POST,PUT,DELETE
	SQL    string = config.Conf.SQL    //支持的SQL:SELECT,INSERT,UPDATE,DELETE
)

// 根据请求类型参数执行不同的操作 
func DoThing(w http.ResponseWriter, req map[string]interface{}) {
	w.Write([]byte("\n"))
	//请求类型 REST or SQL
	switch req["RESTorSQL"] {
	case "REST":
		//REST请求方法过滤
		sMethod := strings.ToUpper(req["Method"].(string))
		if !strings.Contains(REST, sMethod) {
			w.Write([]byte("!!!不准许的REST请求,检查配置文件config.json的REST项。"))
			return
		}
		//执行REST请求
		doREST(w, req)
	case "SQL":
		//SQL过滤
		resSQL := req["ResName"].(string)
		sqlToUpper := strings.ToUpper(resSQL)
		sql6 := sqlToUpper[:6]
		if !strings.Contains(SQL, sql6) {
			w.Write([]byte("!!!不准许的SQL请求,检查配置文件config.json的SQL项。"))
			return
		}
		//执行SQL
		doSQL(w, req)
	}
}

// 根据请求参数执行不同的操作
func doREST(w http.ResponseWriter, req map[string]interface{}) {
	//w.Write([]byte("\ndoREST()"))
	//资源名
	resName := req["ResName"].(string)

	// 检查是否有效资源
	if !isRes(resName) {
		w.Write([]byte("\nerror:无效资源" + resName))
		return
	} else {
		//w.Write([]byte("\nresName:" + resName))
	}

	// 查询条件检查
	var qry map[string]string = make(map[string]string)
	qry["ResName"] = resName
	qry["Where"] = req["Where"].(string)
	qry["OrderBy"] = req["OrderBy"].(string)

	// 有效资源,再看请求方法Get、Post、Put、Delete
	sMethod := strings.ToUpper(req["Method"].(string))
	switch sMethod {
	case "GET":
		getAll(w, qry)

	case "POST":
		var iData interface{}
		iData = req["Data"]
		postAdd(w, resName, iData)

	case "PUT":
		var iData interface{}
		iData = req["Data"]
		putUpdate(w, qry, iData)

	case "DELETE":
		deleteDel(w, qry)
	}
}

// 根据请求参数执行不同的操作 
func doSQL(w http.ResponseWriter, req map[string]interface{}) {
	//w.Write([]byte("\ndoSQL()\n"))
	w.Write([]byte("\"Response\":"))
	//资源名sql语句
	resSQL := req["ResName"].(string)
	fmt.Println("SQL://", resSQL)
	sqlToUpper := strings.ToUpper(resSQL)
	sql6 := sqlToUpper[:6]
	var result string
	switch sql6 {
	case "SELECT":
		result = dboracle.SelectData(resSQL)
	case "INSERT":
		result = dboracle.InsertData(resSQL)
	case "UPDATE":
		result = dboracle.UpdateData(resSQL)
	case "DELETE":
		result = dboracle.DeleteData(resSQL)
	default:
		// 过滤sql ,只能执行 SELECT INSERT UPDATE DELETE
		result = "\"只能执行 SELECT INSERT UPDATE DELETE\""
	}
	fmt.Println("SQL://", resSQL)
	w.Write([]byte(result))
	w.Write([]byte("}"))
}

// 检查资源是否存在 /
func isRes(resName string) bool {
	resname := strings.ToUpper(resName)
	var selectSQL string
	switch DBType {
	case "oracle":
		{
			//表和视图
			selectSQL = "select object_name from user_objects where object_type in ('TABLE','VIEW') and object_name = '" + resname + "'"
		}
	case "":
		{
		}

	}

	//执行数据库查询
	result := dboracle.SelectData(selectSQL)
	//检查数据库是否有此表
	if strings.Contains(result, resname) {
		return true
	} else {
		return false
	}
}

// GET all //
func getAll(w http.ResponseWriter, qry map[string]string) {
	//w.Write([]byte("\nGET ALL"))
	w.Write([]byte("\"Response\":"))
	selectSQL := "select * from " + qry["ResName"]
	if len(qry["Where"]) > 0 {
		//fmt.Println("where ", qry["Where"])
		selectSQL += " where " + qry["Where"] + " and rownum < 52"
	}
	if len(qry["OrderBy"]) > 0 {
		//fmt.Println("OrderBy ", qry["OrderBy"])
		selectSQL += " order by " + qry["OrderBy"]
	}

	//执行 sql并返回 json 结果
	fmt.Println("REST://", selectSQL)
	result := dboracle.SelectData(selectSQL)
	w.Write([]byte(result))
	w.Write([]byte("}"))
}

// GET 1
func get1(w http.ResponseWriter) {
	w.Write([]byte("\nGET ONE"))
}

// POST /
func postAdd(w http.ResponseWriter, resName string, iData interface{}) {
	//curl "http://localhost:5217/rest/atop" --data "{\"p_id\":190,\"s_mc\":\"龙\"}" -X POST
	//w.Write([]byte("\nPOST ADD"))
	w.Write([]byte("\"Response\":{\"Data\":"))
	//fmt.Println("iData:", iData)
	str, err := json.MarshalIndent(iData, "", "   ")
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//fmt.Println("str", str)
	w.Write(str)
	w.Write([]byte(",\"Row\":"))

	var mapData map[string]interface{}
	err = json.Unmarshal(str, &mapData)
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//fmt.Println(mapData)
	var keys, values string
	for k, v := range mapData {
		//fmt.Printf("%s %v %T\n", k, v, v)
		keys += k + ","
		if typeofVar(v) == "string" {
			values += "'" + v.(string) + "',"
		}

		if typeofVar(v) == "float64" || typeofVar(v) == "int" {
			values += fmt.Sprintf("%f", v) + ","
		}

	}

	keys = strings.Trim(keys, ",")
	values = strings.Trim(values, ",")
	//fmt.Println(keys, values)
	insertSQL := "insert into " + resName + "(" + keys + ")" + " values( " + values + " )"
	//执行 insertSQL 并返回 json 结果
	fmt.Println("REST://:", insertSQL)
	result := dboracle.InsertData(insertSQL)
	w.Write([]byte(result))
	w.Write([]byte("}}"))

}

// 数据类型断言 
func typeofVar(variable interface{}) string {
	switch variable.(type) {
	case string:
		return "string"
	case int:
		return "int"
	case float32:
		return "float32"
	case float64:
		return "float64"
	case bool:
		return "boolean"
	case []string:
		return "[]string"
	default:
		return "unknown"
	}
}

// PUT
func putUpdate(w http.ResponseWriter, qry map[string]string, iData interface{}) {
	//w.Write([]byte("\nPUT UPDATE"))
	w.Write([]byte("\"Response\":{\"Data\":"))

	str, err := json.MarshalIndent(iData, "", "   ")
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//fmt.Println("str", str)
	w.Write(str)
	w.Write([]byte(",\"Row\":"))

	var mapData map[string]interface{}
	err = json.Unmarshal(str, &mapData)
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//fmt.Println(mapData)
	var sets string
	for k, v := range mapData {
		//fmt.Printf("%s %v %T\n", k, v, v)
		sets += k + "="
		if typeofVar(v) == "string" {
			sets += "'" + v.(string) + "',"
		}

		if typeofVar(v) == "float64" || typeofVar(v) == "int" {
			sets += fmt.Sprintf("%f", v) + ","
		}

	}

	sets = strings.Trim(sets, ",")

	updateSQL := "update " + qry["ResName"] + "  set " + sets + " where " + qry["Where"]
	//执行 insertSQL 并返回 json 结果
	fmt.Println("REST://", updateSQL)
	result := dboracle.UpdateData(updateSQL)

	w.Write([]byte(result))
	w.Write([]byte("}}"))
}

// DELETE
func deleteDel(w http.ResponseWriter, qry map[string]string) {
	// 查询条件在URL/?后面
	//w.Write([]byte("\nDELETE DEL"))
	w.Write([]byte("\"Response\":"))
	deleteSQL := "delete from " + qry["ResName"]
	if len(qry["Where"]) > 0 {
		//fmt.Println("where ", qry["Where"])
		deleteSQL += " where " + qry["Where"] + " and rownum < 52"
	}

	//执行 sql并返回 json 结果
	fmt.Println("REST://", deleteSQL)
	result := dboracle.DeleteData(deleteSQL)
	w.Write([]byte(result))
	w.Write([]byte("}"))
}

4.2 doc.go

// Dothing project doc.go

/*
dothing document
*/
package dothing

5 部分运行效果图

5.1 启动REST2SQL.exe服务

编译后的rest2sql.exe为14M,启动后的窗口为:
在这里插入图片描述

5.2 浏览器操作演示效果

5.2.1 浏览器REST之GET请求

在这里插入图片描述

5.2.2 浏览器SQL之Select

在这里插入图片描述

5.2.3 执行RESR或SQL请求后,服务窗口返回操作日志

在这里插入图片描述

5.3 详细的操作说明参阅

【REST2SQL】01RDB关系型数据库REST初设计

需要运行程序的可以在评论区留言。

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

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

相关文章

在IDEA中按照默认提示安装Lua脚本插件后,IDEA启动报错【解决方案】

在IDEA中按照默认提示安装Lua脚本插件后&#xff0c;再次重启IDEA就报错了&#xff0c;下面是报错信息&#xff1a; 简单来说就是Lua插件冲突了&#xff0c;因为我勾选了三个&#xff0c;只要其中一个就够了&#xff08;删了其他两个&#xff09;&#xff0c;在IDEA的安装目录…

现在的人们如何看待数据隐私?

PrimiHub一款由密码学专家团队打造的开源隐私计算平台&#xff0c;专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 在当前时代&#xff0c;每一次点击、触摸或按键都留下了数字痕迹。但是我们对自己的个人数据几乎没有控制的权限&#xff0c;这让…

简单聊聊大力发展国产堡垒机的几个原因

我们大家都知道堡垒机起源于国外&#xff0c;但近些年我国在大力发展国产堡垒机&#xff0c;这是为什么呢&#xff1f;相信还有很多小伙伴对于这个问题不是很了解&#xff0c;今天我们大家一起就来简单聊聊大力发展国产堡垒机的几个原因。 简单聊聊大力发展国产堡垒机的几个原…

【XR806开发板试用】+00. Win11环境下安装docker环境

很幸运得到XR806开发板的试用机会&#xff0c;在此深深感谢主办方给菜鸟一个机会。 之前开发的芯片主要是STM32、GD32之类的芯片&#xff0c;都是基于win环境的集成环境。现在拿到这块开发板感觉无从下手&#xff0c;就从安装docker环境开始&#xff0c;慢慢更新xr806的开发之…

移动神器RAX3000M路由器变身家庭云之四:开放LuCI管理界面,网站服务

前面已经改造成了家庭云供外网访问了。由于这个路由本来就是openwrt&#xff0c;openwrt本身的管理界面LuCI-admin很好用&#xff0c;但被屏蔽了&#xff0c;需要打开。 打开界面 ssh登录路由器&#xff0c;修改 /etc/config/uhttpd配置文件如下&#xff1a; config uhttpd …

基于Java SSM框架实现固定资产管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现固定资产管理系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…

C#:如何产生一个临时文件

在我们实际编程中&#xff0c;经常有将内容写到一个临时文件的需要。 比如&#xff1a;将网络上的图片下载下来&#xff0c;获取到图片的一些信息。 代码如下&#xff0c;看结果可知&#xff1a; 临时文件都是保存在系统临时文件夹的目录下&#xff0c;临时文件的扩展名统一…

uniCloud 的 schema2code 【实用教程】

schema2code 用于通过 schema 文件&#xff0c;自动生成对表进行增删改查的操作页面。 以 uniCloud-aliyun/database/todo.schema.json 为例 {"bsonType": "object","required": [],"permission": {"read": true,"cr…

文档工程师怎样做到年薪百万

▲ 搜索“大龙谈智能内容”关注公众号▲ 2023年10月&#xff0c;Infomagic发布了《2023中国技术传播行业调研报告》。 其中&#xff0c;有一项是关于文档工程师年收入的调研&#xff0c;以下分别是2018年和2023年收入分布。 图1 - 文档工程师年收入分布 有朋友看到真有人年…

(vue)el-popover鼠标移入提示效果

(vue)el-popover鼠标移入提示效果 效果&#xff1a; 代码&#xff1a; <el-form-itemv-for"(item,index) of ele.algorithmParameters":key"index":label"item.parametersName"class"descInput" ><el-input v-model"i…

助力数据出境安全 | 时代新威出席第二届粤港澳数据合作会议

12月19日&#xff0c;第二届粤港澳数据合作会议在广州南沙成功举办。会议以“数智力量汇聚南沙&#xff0c;打造粤港澳数据高水平合作平台&#xff0c;赋能大湾区数字经济高质量发展”为主题&#xff0c;汇聚了政府主管部门领导、粤港澳相关主管机构代表、中国工程院院士和众多…

【PTA-C语言】编程练习6 - 结构体与共用体 - 编程题

如果代码存在问题&#xff0c;麻烦大家指正 ~ ~有帮助麻烦点个赞 ~ ~ 编程练习6 - 结构体与共用体 - 编程题 7-1 查找书籍&#xff08;分数 20&#xff09;7-2 一帮一&#xff08;分数 15&#xff09;7-3 计算职工工资&#xff08;分数 15&#xff09; 7-1 查找书籍&#xff08…

公司图纸该怎么管理? 公司图纸管理的方案

公司图纸管理是一个重要的环节&#xff0c;涉及到图纸的存储、分类、检索和使用等方面。以下是一些建议&#xff0c;帮助你有效地管理公司图纸&#xff1a; 建立图纸管理制度&#xff1a;制定明确的图纸管理制度&#xff0c;包括图纸的存储、分类、检索和使用等方面的规定。确保…

k8s的pod基础

pod概念 pod是k8s中最小的资源管理组件。 pod也是最小化运行容器化的应用的资源管理对象。 pod是一个抽象的概念&#xff0c;可以理解为一个或者多个容器化应用的集合。 在一个pod当中运行一个容器是最常用的方式。在一个pod当中同时运行多个容器&#xff0c;在一个pod当中…

SD-WAN搭建企业多云专用网络

随着云服务的快速发展&#xff0c;越来越多的企业将数据部署、存储在云平台上&#xff0c;以达到降本增效。但近年国内外云服务崩溃事故频发&#xff0c;让不少对网络稳定性要求较高的企业开始思考多云灾备的重要性。下文将探讨目前企业多云网络面临的困境以及如何用SD-WAN解决…

Mysql锁机制与优化

欢迎大家关注我的微信公众号&#xff1a; 传送门&#xff1a;Mysql事务原理与优化 目录 概述 锁分类 锁等待分析 锁优化实践 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中&#xff0c;除了传统的计算资源&#xff08;如CPU、RAM、I/O等&…

vue3+Cesium 添加地面测控站台

效果 cesiumRadar.js import * as Cesium from cesium; export function addentities(viewer, res, index) {viewer.entities.add({id: index,position: Cesium.Cartesian3.fromDegrees(res[0], res[1]),wall: {positions: new Cesium.CallbackProperty(() > {return Cesiu…

配网故障定位技术的研究与实现:提高配网运行效率的必要手段

随着电力系统的不断发展&#xff0c;配电网作为电力系统的重要组成部分&#xff0c;其安全性和稳定性对于整个电力系统的运行具有重要意义。然而&#xff0c;配电网在运行过程中&#xff0c;由于各种原因导致的故障事件时有发生&#xff0c;严重影响了配网的运行效率和供电质量…

QT上位机开发(简易图像处理软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 大家都知道图像处理非常地重要&#xff0c;因为它不仅仅是可以用于拍照美颜&#xff0c;而且在工业、医疗和军事等方面也发挥着巨大的作用。另外一…

聊聊分布式会话及实现方案

鲁大猿&#xff0c;寻找精品资料&#xff0c;帮你构建Java全栈知识体系 http://www.jiagoujishu.cn 基础概念 Session Cookie 会话方案比较简单&#xff0c;这里我在网上找了点资料&#xff0c;再回顾下基础吧。 为什么要产生Session http协议本身是无状态的&#xff0c;客户…