【REST2SQL】06 GO 跨包接口重构代码

【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

控制台执行日志:

浏览器请求及返回:

《06 完》

相关推荐
奋斗的小花生33 分钟前
c++ 多态性
开发语言·c++
魔道不误砍柴功35 分钟前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨38 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程1 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk2 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*2 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue2 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man2 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸3 小时前
【一些关于Python的信息和帮助】
开发语言·python