【REST2SQL】01RDB关系型数据库REST初设计
【REST2SQL】02 GO连接Oracle数据库
【REST2SQL】03 GO读取JSON文件
【REST2SQL】04 REST2SQL第一版Oracle版实现
【REST2SQL】05 GO 操作 达梦 数据库
对所有关系数据的操作都只有CRUD,采用Go 的接口interface{}重构代码,代码更简洁、易维护。
1 创建接口声明包
在 REST2sql目录下创建一个dbif的子目录,在此子目录下创建dbif.go包,文件组织结构如下图:
接口包代码如下:
// 数据库接口定义
package dbif
// 数据库操作接口
type CRUD interface {
InsertData(string) string //插入,返回影响行数json字符串
SelectData(string) string //查询, 返回查询结果json字符串
UpdateData(string) string //更新,返回影响行数json字符串
DeleteData(string) string //删除,返回影响行数json字符串
IsResource(string) bool //在系统对象表总查找资源是否有效,用户表或视图
}
2 dboracle包重构
2.1 引入接口包dbif
import (
"database/sql/driver"
"encoding/json"
"io"
"log"
"rest2sql/config"
db "rest2sql/dbif" //数据库接口包
"strings"
go_ora "github.com/sijms/go-ora/v2" // 1 go get github.com/sijms/go-ora/v2
)
2.2 声明CRUD4Oracle结构体
作为接口函数的接收者,或者说接口绑定对象。
type CRUD4Oracle struct {
//Oracle的CRUD操作,结构体
}
2.3 创建New()构造函数
直接返回,结构体指针。
func New() db.CRUD {
//创建结构体CRUD4Oracle
return &CRUD4Oracle{}
}
2.4 实现接口的全部函数或方法
原来的CRUD函数加上接受者即可,或者说绑定结构体
// delete
func (crud *CRUD4Oracle) DeleteData(deleteSql string) string {}
// update
func (crud *CRUD4Oracle) UpdateData(updateSql string) string {}
// insert
func (crud *CRUD4Oracle) InsertData(insertSql string) string {}
// select查询,结果为json
func (crud *CRUD4Oracle) SelectData(sqls string) string {}
原来dothing包的资源检查函数 isRes( resName string) bool ,用接口重构,不同数据库实现稍微不同。
// REST请求时检查资源是否有效
func (crud *CRUD4Oracle) IsResource(resName string) bool {
icurd := New()
resname := strings.ToUpper(resName)
resSQL := "select object_name from user_objects where object_type in ('TABLE','VIEW') and object_name = '" + resname + "'"
//执行数据库查询
result := icurd.SelectData(resSQL)
//检查数据库是否有此表
if strings.Contains(result, resname) {
return true
} else {
return false
}
}
3 dbdm包重构
和oracle重构类似,只有结构体和New() 不同
3.1 引入dbif包
import db "rest2sql/dbif"
3.2 声明CRUD4Dm结构体
type CRUD4Dm struct {
//Dm的CRUD操作,结构体
}
3.3 创建New()构造函数
func New() db.CRUD {
//创建结构体CRUD4Dm
return &CRUD4Dm{}
}
3.4 实现接口的全部函数或方法
原来的CRUD函数加上接受者即可,或者说绑定结构体
/* 往表插入数据 */
func (crud *CRUD4Dm) InsertData(insertSql string) string {}
/* 删除表数据 */
func (crud *CRUD4Dm) DeleteData(deleteSql string) string {}
/* 修改表数据 */
func (crud *CRUD4Dm) UpdateData(updateSql string) string {}
/* 查询表数据 */
func (crud *CRUD4Dm) SelectData(sqlSelect string) string {}
// REST请求时检查资源是否有效
func (crud *CRUD4Dm) IsResource(resName string) bool {
icurd := New()
resname := strings.ToUpper(resName)
resSQL := "select object_name from user_objects where object_type in ('TABLE','VIEW') and object_name = '" + resname + "'"
//执行数据库查询
result := icurd.SelectData(resSQL)
//检查数据库是否有此表
if strings.Contains(result, resname) {
return true
} else {
return false
}
}
4 Dothing包的重构
4.1 引入接口和数据库包
// dothing project dothing.go
package dothing
import (
"encoding/json"
"fmt"
"net/http"
"rest2sql/config"
dm "rest2sql/dbdm"
db "rest2sql/dbif"
ora "rest2sql/dboracle"
"strings"
)
4.2 声明接口全局变量
// 当前连接的数据库类型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
)
// 声明CRUD操作的全局接口变量
var Icrud db.CRUD
4.3 创建全局变量构造函数createDBType
// 根据数据库类型,创建crud对象
func createDBType() {
switch DBType {
case "oracle":
Icrud = ora.New()
case "dm":
// 达梦
Icrud = dm.New()
default:
// 不支持的数据库
}
}
// 调用接口函数
// 根据请求类型参数执行不同的操作
func DoThing(w http.ResponseWriter, req map[string]interface{}) {
//创建数据库接口
createDBType()
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)
}
}
4.4 检查资源是否有效的调用
//资源名
resName := req["ResName"].(string)
// 检查是否有效资源
if !Icrud.IsResource(resName) {
//if !isRes(resName) {
w.Write([]byte("\nerror:无效资源" + resName))
return
} else {
//w.Write([]byte("\nresName:" + resName))
}
4.5 doSQL重构
重构了switch case
// 根据请求参数执行不同的操作
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 = Icrud.SelectData(resSQL)
case "INSERT":
result = Icrud.InsertData(resSQL)
case "UPDATE":
result = Icrud.UpdateData(resSQL)
case "DELETE":
result = Icrud.DeleteData(resSQL)
default:
// 过滤sql ,只能执行 SELECT INSERT UPDATE DELETE
result = "\"只能执行 SELECT INSERT UPDATE DELETE\""
}
fmt.Println("SQL://", resSQL)
w.Write([]byte(result))
w.Write([]byte("}"))
}
4.6 REST4种请求的重构
// get
//执行 sql并返回 json 结果
fmt.Println("REST://", selectSQL)
result := Icrud.SelectData(selectSQL)
// post
//执行 insertSQL 并返回 json 结果
fmt.Println("REST://:", insertSQL)
result := Icrud.InsertData(insertSQL)
// put
//执行 insertSQL 并返回 json 结果
fmt.Println("REST://", updateSQL)
result := Icrud.UpdateData(updateSQL)
// delete
//执行 sql并返回 json 结果
fmt.Println("REST://", deleteSQL)
result := Icrud.DeleteData(deleteSQL)
5 测试结果
总体代码组织
Oracle OK
达梦dm OK
控制台执行日志:
浏览器请求及返回: