| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- package main
-
- import (
- "database/sql"
- "encoding/json"
- "fmt"
- "log"
- "net/http"
- "time"
-
- "git.x2erp.com/qdy/go-base/types"
- // 注意:这里要使用 factory 包的正确导入路径(和你原代码一致)
- "git.x2erp.com/qdy/go-db/factory"
- "github.com/gorilla/mux"
- )
-
- // 全局变量,只初始化一次(复用原逻辑,确保工厂和DB连接单例)
- var dbFactory *factory.DBFactory
- var db *sql.DB
-
- // QueryRequest 请求结构体(接收前端SQL参数)
- type QueryRequest struct {
- SQL string `json:"sql"`
- }
-
- func main() {
- var err error
-
- // 1. 创建数据库工厂(只执行一次)
- dbFactory, err = factory.NewDBFactory()
- if err != nil {
- log.Fatalf("Failed to create DB factory: %v", err)
- }
-
- // 2. 显示基础信息(保留原日志输出)
- drivers := dbFactory.GetAvailableDrivers()
- fmt.Printf("Available database drivers: %v\n", drivers)
-
- config := dbFactory.GetConfig()
- fmt.Printf("Using database type: %s\n", config.Database.Type)
- fmt.Printf("Database host: %s:%d\n", config.Database.Host, config.Database.Port)
- fmt.Printf("Database name: %s\n", config.Database.Database)
-
- // 3. 创建数据库连接(全局复用)
- db, err = dbFactory.CreateDB()
- if err != nil {
- log.Fatalf("Failed to create database connection: %v", err)
- }
- defer db.Close()
-
- // 4. 测试连接(保留原校验逻辑)
- if err := testConnection(db, config.Database.Type); err != nil {
- log.Fatalf("Database connection test failed: %v", err)
- } else {
- fmt.Println("Database connection test passed!")
- }
-
- // 5. 启动HTTP服务
- startHTTPServer()
- }
-
- // 启动HTTP服务器(简化,直接使用全局DB连接)
- func startHTTPServer() {
- router := mux.NewRouter()
-
- // 核心路由:SQL查询(POST)- 直接返回 types.QueryResult
- router.HandleFunc("/api/query", queryHandler).Methods("POST")
- // 辅助路由:健康检查、数据库信息(保留原功能)
- router.HandleFunc("/api/health", healthHandler).Methods("GET")
- router.HandleFunc("/api/info", infoHandler).Methods("GET")
-
- // 服务器配置(保留原超时设置)
- server := &http.Server{
- Addr: ":8080",
- Handler: router,
- ReadTimeout: 30 * time.Second,
- WriteTimeout: 30 * time.Second,
- IdleTimeout: 60 * time.Second,
- }
-
- // 启动日志(保留原格式)
- fmt.Println("Database microservice starting on :8080")
- fmt.Println("Endpoints:")
- fmt.Println(" POST /api/query - Execute SQL query (return types.QueryResult)")
- fmt.Println(" GET /api/health - Health check")
- fmt.Println(" GET /api/info - Database info")
-
- log.Fatal(server.ListenAndServe())
- }
-
- // queryHandler SQL查询处理(核心修改)
- // 1. 修复 factory.QuickQueryToJSON 调用(确保导入路径正确)
- // 2. 直接返回 types.QueryResult,不二次封装
- func queryHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
-
- // 1. 解析请求参数
- var req QueryRequest
- if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
- // 参数错误时,返回 types.QueryResult 格式的错误响应
- json.NewEncoder(w).Encode(&types.QueryResult{
- Success: false,
- Error: fmt.Sprintf("Invalid request body: %v", err),
- Data: nil,
- })
- return
- }
-
- // 2. 校验SQL非空
- if req.SQL == "" {
- json.NewEncoder(w).Encode(&types.QueryResult{
- Success: false,
- Error: "SQL statement cannot be empty",
- Data: nil,
- })
- return
- }
-
- // 3. 核心逻辑:调用 factory.QuickQueryToJSON(确保工厂包导出了该方法)
- // 注意:如果仍提示 undefined,检查 factory 包是否真的导出了 QuickQueryToJSON(首字母大写)
- result := factory.QuickQueryToJSON(db, req.SQL)
-
- // 4. 直接返回结果(types.QueryResult 原生格式)
- json.NewEncoder(w).Encode(result)
- }
-
- // healthHandler 健康检查(修复语法错误,保持返回格式统一)
- func healthHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
-
- // 校验DB连接状态
- err := db.Ping()
- success := err == nil
-
- // 标准 if-else 赋值状态
- var status string
- if success {
- status = "UP"
- } else {
- status = "DOWN"
- }
-
- // 返回 types.QueryResult 格式(和查询接口保持一致)
- json.NewEncoder(w).Encode(&types.QueryResult{
- Success: success,
- Data: map[string]interface{}{
- "status": status,
- "time": time.Now().Format(time.RFC3339),
- "database": dbFactory.GetConfig().Database.Type,
- },
- Error: func() string {
- if err != nil {
- return err.Error()
- }
- return ""
- }(),
- })
- }
-
- // infoHandler 数据库信息(返回 types.QueryResult 格式)
- func infoHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
-
- config := dbFactory.GetConfig()
- drivers := dbFactory.GetAvailableDrivers()
-
- // 直接返回 types.QueryResult 格式
- json.NewEncoder(w).Encode(&types.QueryResult{
- Success: true,
- Data: map[string]interface{}{
- "database_type": config.Database.Type,
- "database_host": fmt.Sprintf("%s:%d", config.Database.Host, config.Database.Port),
- "database_name": config.Database.Database,
- "available_drivers": drivers,
- "service_time": time.Now().Format(time.RFC3339),
- },
- Error: "",
- })
- }
-
- // testConnection 测试数据库连接(保留原逻辑)
- func testConnection(db *sql.DB, dbType string) error {
- var query string
- switch dbType {
- case "mysql", "postgres", "sqlserver":
- query = "SELECT 1"
- case "oracle":
- query = "SELECT 1 FROM DUAL"
- default:
- query = "SELECT 1"
- }
-
- var result int
- err := db.QueryRow(query).Scan(&result)
- if err != nil {
- return fmt.Errorf("test query failed: %v", err)
- }
-
- if result != 1 {
- return fmt.Errorf("unexpected test result: %d", result)
- }
-
- return nil
- }
|