diff --git a/features/udm_user/api_udm_user.go b/features/udm_user/api_udm_user.go index 7f113f98..5511572a 100644 --- a/features/udm_user/api_udm_user.go +++ b/features/udm_user/api_udm_user.go @@ -1,11 +1,17 @@ package udmuser import ( + "fmt" "net/http" + "ems.agt/features/udm_user/model" "ems.agt/features/udm_user/service" + "ems.agt/lib/core/file" + mmlclient "ems.agt/lib/core/mml_client" "ems.agt/lib/core/utils/ctx" "ems.agt/lib/core/vo/result" + "ems.agt/lib/dborm" + "ems.agt/lib/log" "ems.agt/lib/services" "ems.agt/restagent/config" ) @@ -19,30 +25,50 @@ func Routers() []services.RouterItem { } rs := [...]services.RouterItem{ + // UDM签约用户 { Method: "GET", - Pattern: "/authUserList", + Pattern: "/auths", Handler: apis.UdmAuthUserList, Middleware: nil, //midware.Authorize(nil), }, { Method: "POST", - Pattern: "/authUserSave", + Pattern: "/auth/getSave", Handler: apis.UdmAuthUserSave, Middleware: nil, //midware.Authorize(nil), }, { Method: "GET", - Pattern: "/subUserList", + Pattern: "/auth/{neId}/{imsi}", + Handler: apis.UdmAuthUserInfo, + Middleware: nil, //midware.Authorize(nil), + }, + { + Method: "POST", + Pattern: "/auth/export", + Handler: apis.UdmAuthUserExport, + Middleware: nil, //midware.Authorize(nil), + }, + // UDM签约用户 + { + Method: "GET", + Pattern: "/subs", Handler: apis.UdmSubUserList, Middleware: nil, //midware.Authorize(nil), }, { Method: "POST", - Pattern: "/subUserSave", + Pattern: "/sub/getSave", Handler: apis.UdmSubUserSave, Middleware: nil, //midware.Authorize(nil), }, + { + Method: "GET", + Pattern: "/sub/{neId}/{imsi}", + Handler: apis.UdmSubUserInfo, + Middleware: nil, //midware.Authorize(nil), + }, // 添加更多的 Router 对象... } @@ -60,6 +86,16 @@ func Routers() []services.RouterItem { return rsPrefix } +// NeInfoByUDM 网元信息 +func NeInfoByUDM(neId string) (*dborm.NeInfo, error) { + neInfo, err := dborm.XormGetNeInfo("UDM", neId) + if err != nil { + log.Error("dborm.XormGetNeInfo is failed:", err) + return nil, err + } + return neInfo, nil +} + // UDM 用户 // // PATH /udmUserManage @@ -70,34 +106,113 @@ type UdmUserApi struct { // UDM鉴权用户 // -// GET /authUserList +// GET /auths func (s *UdmUserApi) UdmAuthUserList(w http.ResponseWriter, r *http.Request) { querys := ctx.QueryMap(r) - data := s.authUser.AuthUserList(querys) + data := s.authUser.Page(querys) ctx.JSON(w, 200, result.Ok(data)) } // UDM鉴权用户-获取全部保存数据库 // -// POST /authUserSave +// POST /auth/getSave func (s *UdmUserApi) UdmAuthUserSave(w http.ResponseWriter, r *http.Request) { - data := s.authUser.AuthUserSave() + data := s.authUser.Save("") ctx.JSON(w, 200, result.OkData(data)) } +// UDM鉴权用户-信息 +// +// GET /{neId}/{imsi} +func (s *UdmUserApi) UdmAuthUserInfo(w http.ResponseWriter, r *http.Request) { + neId := ctx.Param(r, "neId") + imsi := ctx.Param(r, "imsi") + if neId == "" || imsi == "" { + ctx.JSON(w, 400, result.CodeMsg(400, "参数错误")) + return + } + + neInfo, err := NeInfoByUDM(neId) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToMap(neInfo.Ip, msg) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + ctx.JSON(w, 200, result.OkData(data)) +} + +// UDM鉴权用户-导出 +// +// POST /auth/export +func (s *UdmUserApi) UdmAuthUserExport(w http.ResponseWriter, r *http.Request) { + list := s.authUser.List(model.UdmAuthUser{}) + // 文件名 + fileName := "OMC_AUTH_100.csv" + filePath := "C:/AMP/Probject/ems_backend/restagent/OMC_AUTH_100.csv" + // 转换数据 + data := [][]string{} + data = append(data, []string{"ID", "Msisdn", "Imsi", "Amf", "Status", "Ki", "AlgoIndex", "Opc"}) + for _, v := range list { + data = append(data, []string{v.ID, v.Msisdn, v.Imsi, v.Amf, v.Status, v.Ki, v.AlgoIndex, v.Opc}) + } + // 输出到文件 + err := file.WriterCSVFile(data, filePath) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + ctx.FileAttachment(w, r, filePath, fileName) +} + // UDM签约用户 // -// GET /subUserList +// GET /subs func (s *UdmUserApi) UdmSubUserList(w http.ResponseWriter, r *http.Request) { querys := ctx.QueryMap(r) - data := s.subUser.SubUserList(querys) + data := s.subUser.Page(querys) ctx.JSON(w, 200, result.Ok(data)) } // UDM签约用户-获取全部保存数据库 // -// POST /subUserSave +// POST /sub/getSave func (s *UdmUserApi) UdmSubUserSave(w http.ResponseWriter, r *http.Request) { - data := s.subUser.SubUserSave() + data := s.subUser.Save("") + ctx.JSON(w, 200, result.OkData(data)) +} + +// UDM签约用户-信息 +// +// GET /{neId}/{imsi} +func (s *UdmUserApi) UdmSubUserInfo(w http.ResponseWriter, r *http.Request) { + neId := ctx.Param(r, "neId") + imsi := ctx.Param(r, "imsi") + if neId == "" || imsi == "" { + ctx.JSON(w, 400, result.CodeMsg(400, "参数错误")) + return + } + + neInfo, err := NeInfoByUDM(neId) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToMap(neInfo.Ip, msg) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } ctx.JSON(w, 200, result.OkData(data)) } diff --git a/features/udm_user/model/udm_auth_user.go b/features/udm_user/model/udm_auth_user.go index 2a371421..4e72f20d 100644 --- a/features/udm_user/model/udm_auth_user.go +++ b/features/udm_user/model/udm_auth_user.go @@ -10,4 +10,5 @@ type UdmAuthUser struct { Ki string `json:"ki" xorm:"ki"` // ki AlgoIndex string `json:"algoIndex" xorm:"algo_index"` // Opc string `json:"opc" xorm:"opc"` + NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统 } diff --git a/features/udm_user/model/udm_sub_user.go b/features/udm_user/model/udm_sub_user.go index 81371ee6..c43c96de 100644 --- a/features/udm_user/model/udm_sub_user.go +++ b/features/udm_user/model/udm_sub_user.go @@ -13,4 +13,5 @@ type UdmSubUser struct { CnType string `json:"cnType" xorm:"cn_type"` SubData string `json:"subData" xorm:"sub_data"` Eps string `json:"eps" xorm:"eps"` + NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统 } diff --git a/features/udm_user/repo/repo_udm_auth_user.go b/features/udm_user/repo/repo_udm_auth_user.go index abc24344..532d9f74 100644 --- a/features/udm_user/repo/repo_udm_auth_user.go +++ b/features/udm_user/repo/repo_udm_auth_user.go @@ -12,7 +12,7 @@ import ( // 实例化数据层 RepoUdmAuthUser 结构体 var NewRepoUdmAuthUser = &RepoUdmAuthUser{ selectSql: `select - id, msisdn, imsi, amf, status, ki, algo_index, opc + id, msisdn, imsi, amf, status, ki, algo_index, opc, ne_id from u_auth_user`, resultMap: map[string]string{ @@ -24,6 +24,7 @@ var NewRepoUdmAuthUser = &RepoUdmAuthUser{ "ki": "Ki", "algo_index": "AlgoLndex", "opc": "Opc", + "ne_id": "NeID", }, } @@ -50,7 +51,7 @@ func (r *RepoUdmAuthUser) convertResultRows(rows []map[string]any) []model.UdmAu return arr } -// SelectPage 根据条件分页查询字典类型 +// SelectPage 根据条件分页查询 func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any { // 查询条件拼接 var conditions []string @@ -59,6 +60,10 @@ func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any { conditions = append(conditions, "msisdn like concat(?, '%')") params = append(params, v) } + if v, ok := query["neId"]; ok && v != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, v) + } // 构建查询条件语句 whereSql := "" @@ -100,3 +105,56 @@ func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any { "rows": rows, } } + +// SelectList 根据实体查询 +func (r *RepoUdmAuthUser) SelectList(auth model.UdmAuthUser) []model.UdmAuthUser { + // 查询条件拼接 + var conditions []string + var params []any + if auth.Imsi != "" { + conditions = append(conditions, "msisdn like concat(?, '%')") + params = append(params, auth.Imsi) + } + if auth.NeID != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, auth.NeID) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + log.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 清空ne_id后新增实体 +func (r *RepoUdmAuthUser) Inserts(neID string, authArr []model.UdmAuthUser) int64 { + var num int64 = 0 + + // 清空指定ne_id + _, err := datasource.ExecDB("", "DELETE FROM u_auth_user WHERE ne_id = ?", []any{neID}) + if err != nil { + log.Errorf("TRUNCATE err => %v", err) + return num + } + + for _, u := range authArr { + u.NeID = neID + results, err := datasource.DefaultDB().Table("u_auth_user").Insert(u) + if err != nil { + return num + } + num += results + } + return num +} diff --git a/features/udm_user/repo/repo_udm_sub_user.go b/features/udm_user/repo/repo_udm_sub_user.go index f8db0995..e5f95614 100644 --- a/features/udm_user/repo/repo_udm_sub_user.go +++ b/features/udm_user/repo/repo_udm_sub_user.go @@ -12,7 +12,7 @@ import ( // 实例化数据层 RepoUdmSubUser 结构体 var NewRepoUdmSubUser = &RepoUdmSubUser{ selectSql: `select - id, msisdn, imsi, sub_ue_ambr_temp, sub_snssai_temp, rai, forbidden_areas_temp, service_area_restrict_temp, cn_type, sub_data, eps + id, msisdn, imsi, sub_ue_ambr_temp, sub_snssai_temp, rai, forbidden_areas_temp, service_area_restrict_temp, cn_type, sub_data, eps, ne_id from u_sub_user`, resultMap: map[string]string{ @@ -27,6 +27,7 @@ var NewRepoUdmSubUser = &RepoUdmSubUser{ "cn_type": "CnType", "sub_data": "SubData", "eps": "Eps", + "ne_id": "NeID", }, } @@ -66,6 +67,10 @@ func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any { conditions = append(conditions, "imsi like concat(?, '%')") params = append(params, v) } + if v, ok := query["neId"]; ok && v != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, v) + } // 构建查询条件语句 whereSql := "" @@ -107,3 +112,56 @@ func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any { "rows": rows, } } + +// SelectList 根据实体查询 +func (r *RepoUdmSubUser) SelectList(auth model.UdmSubUser) []model.UdmSubUser { + // 查询条件拼接 + var conditions []string + var params []any + if auth.Imsi != "" { + conditions = append(conditions, "msisdn like concat(?, '%')") + params = append(params, auth.Imsi) + } + if auth.NeID != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, auth.NeID) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + log.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 清空ne_id后新增实体 +func (r *RepoUdmSubUser) Inserts(neID string, authArr []model.UdmSubUser) int64 { + var num int64 = 0 + + // 清空指定ne_id + // _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) + _, err := datasource.ExecDB("", "DELETE FROM u_sub_user WHERE ne_id = ?", []any{neID}) + if err != nil { + log.Errorf("TRUNCATE err => %v", err) + } + + for _, u := range authArr { + u.NeID = neID + results, err := datasource.DefaultDB().Table("u_sub_user").Insert(u) + if err != nil { + return num + } + num += results + } + return num +} diff --git a/features/udm_user/service/service_ne_ifno.go b/features/udm_user/service/service_ne_ifno.go new file mode 100644 index 00000000..0299fb6f --- /dev/null +++ b/features/udm_user/service/service_ne_ifno.go @@ -0,0 +1,15 @@ +package service + +import ( + "ems.agt/lib/dborm" + "ems.agt/lib/log" +) + +func UDMNeInfo(neId string) (*dborm.NeInfo, error) { + neInfo, err := dborm.XormGetNeInfo("UDM", neId) + if err != nil { + log.Error("dborm.XormGetNeInfo is failed:", err) + return nil, err + } + return neInfo, nil +} diff --git a/features/udm_user/service/service_udm_auth_user.go b/features/udm_user/service/service_udm_auth_user.go index 26968465..c708ca9c 100644 --- a/features/udm_user/service/service_udm_auth_user.go +++ b/features/udm_user/service/service_udm_auth_user.go @@ -1,9 +1,8 @@ package service import ( + "ems.agt/features/udm_user/model" "ems.agt/features/udm_user/repo" - "ems.agt/lib/core/datasource" - "ems.agt/lib/log" ) // 实例化服务层 ServiceUdmAuthUser 结构体 @@ -16,32 +15,23 @@ type ServiceUdmAuthUser struct { repoAuthUser repo.RepoUdmAuthUser } -// AuthUserSave UDM鉴权用户-获取全部保存数据库 -func (r *ServiceUdmAuthUser) AuthUserSave() int64 { +// Save UDM鉴权用户-获取全部保存数据库 +func (r *ServiceUdmAuthUser) Save(neID string) int64 { var num int64 = 0 authArr := redisUdmAuthUserList() // 有数据才清空 if len(authArr) == 0 { return num } - - _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) - if err != nil { - log.Errorf("TRUNCATE err => %v", err) - } - - for _, u := range authArr { - results, err := datasource.DefaultDB().Table("u_auth_user").Insert(u) - if err != nil { - log.Errorf("Insert err => %v", err) - return 0 - } - num += results - } - return num + return r.repoAuthUser.Inserts(neID, authArr) } -// SubUserSave UDM签约用户-分页查询数据库 -func (r *ServiceUdmAuthUser) AuthUserList(query map[string]any) map[string]any { +// Page UDM签约用户-分页查询数据库 +func (r *ServiceUdmAuthUser) Page(query map[string]any) map[string]any { return r.repoAuthUser.SelectPage(query) } + +// List UDM签约用户-查询数据库 +func (r *ServiceUdmAuthUser) List(authUser model.UdmAuthUser) []model.UdmAuthUser { + return r.repoAuthUser.SelectList(authUser) +} diff --git a/features/udm_user/service/service_udm_sub_user.go b/features/udm_user/service/service_udm_sub_user.go index 660a3d44..9d8d10a4 100644 --- a/features/udm_user/service/service_udm_sub_user.go +++ b/features/udm_user/service/service_udm_sub_user.go @@ -1,49 +1,37 @@ package service import ( + "ems.agt/features/udm_user/model" "ems.agt/features/udm_user/repo" - "ems.agt/lib/core/datasource" - "ems.agt/lib/log" ) // 实例化服务层 ServiceUdmSubUser 结构体 var NewServiceUdmSubUser = &ServiceUdmSubUser{ - repoAuthUser: *repo.NewRepoUdmAuthUser, - repoSunUser: *repo.NewRepoUdmSubUser, + repoSunUser: *repo.NewRepoUdmSubUser, } // ServiceUdmSubUser UDM签约用户 服务层处理 type ServiceUdmSubUser struct { - repoAuthUser repo.RepoUdmAuthUser - repoSunUser repo.RepoUdmSubUser + repoSunUser repo.RepoUdmSubUser } -// SubUserSave UDM签约用户-获取全部保存数据库 -func (r *ServiceUdmSubUser) SubUserSave() int64 { +// Save UDM签约用户-获取全部保存数据库 +func (r *ServiceUdmSubUser) Save(neID string) int64 { var num int64 = 0 subArr := redisUdmSubUserList() // 有数据才清空 if len(subArr) == 0 { return num } - - _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) - if err != nil { - log.Errorf("TRUNCATE err => %v", err) - } - - for _, u := range subArr { - results, err := datasource.DefaultDB().Table("u_sub_user").Insert(u) - if err != nil { - log.Errorf("Insert err => %v", err) - return 0 - } - num += results - } - return num + return r.repoSunUser.Inserts(neID, subArr) } -// SubUserSave UDM签约用户-分页查询数据库 -func (r *ServiceUdmSubUser) SubUserList(query map[string]any) map[string]any { +// Page UDM签约用户-分页查询数据库 +func (r *ServiceUdmSubUser) Page(query map[string]any) map[string]any { return r.repoSunUser.SelectPage(query) } + +// List UDM签约用户-查询数据库 +func (r *ServiceUdmSubUser) List(subUser model.UdmSubUser) []model.UdmSubUser { + return r.repoSunUser.SelectList(subUser) +} diff --git a/lib/core/file/csv.go b/lib/core/file/csv.go new file mode 100644 index 00000000..ad7763f5 --- /dev/null +++ b/lib/core/file/csv.go @@ -0,0 +1,43 @@ +package file + +import ( + "encoding/csv" + "os" + "path/filepath" + + "ems.agt/lib/log" +) + +// 写入CSV文件,需要转换数据 +// 例如: +// data := [][]string{} +// data = append(data, []string{"姓名", "年龄", "城市"}) +// data = append(data, []string{"1", "2", "3"}) +// err := file.WriterCSVFile(data, filePath) +func WriterCSVFile(data [][]string, filePath string) error { + // 获取文件所在的目录路径 + dirPath := filepath.Dir(filePath) + + // 确保文件夹路径存在 + err := os.MkdirAll(dirPath, os.ModePerm) + if err != nil { + log.Errorf("创建文件夹失败 CreateFile %v", err) + } + + // 创建或打开文件 + file, err := os.Create(filePath) + if err != nil { + return err + } + defer file.Close() + + // 创建CSV编写器 + writer := csv.NewWriter(file) + defer writer.Flush() + + // 写入数据 + for _, row := range data { + writer.Write(row) + } + return nil +} diff --git a/lib/core/mml_client/mml_client.go b/lib/core/mml_client/mml_client.go new file mode 100644 index 00000000..5903123d --- /dev/null +++ b/lib/core/mml_client/mml_client.go @@ -0,0 +1,88 @@ +package mmlclient + +import ( + "bufio" + "fmt" + "io" + "net" + "time" + + "ems.agt/lib/core/conf" +) + +// 定义MMLClient结构体 +type MMLClient struct { + awaitTime time.Duration // 等待时间 + conn net.Conn + reader *bufio.Reader + size int // 包含字符 +} + +// 封装NewMMLClient函数,用于创建MMLClient实例 +// 网元UDM的IP地址 "198.51.100.1" +func NewMMLClient(ip string) (*MMLClient, error) { + // 创建TCP连接 + portMML := conf.Get("mml.port").(int) + hostMML := fmt.Sprintf("%s:%d", ip, portMML) + conn, err := net.Dial("tcp", hostMML) + if err != nil { + return nil, err + } + + // 进行登录 + usernameMML := conf.Get("mml.user").(string) + passwordMML := conf.Get("mml.password").(string) + fmt.Fprintln(conn, usernameMML) + fmt.Fprintln(conn, passwordMML) + + // 发送后等待 + sleepTime := conf.Get("mml.sleep").(int) + awaitTime := time.Duration(sleepTime) * time.Millisecond + time.Sleep(awaitTime) + + // 读取内容 + buf := make([]byte, 1024*8) + n, err := conn.Read(buf) + if err != nil { + return nil, err + } + + // 创建MMLClient实例 + client := &MMLClient{ + conn: conn, + reader: bufio.NewReader(conn), + awaitTime: awaitTime, + size: n, + } + + return client, nil +} + +// 封装Send函数,用于向TCP连接发送数据 +func (c *MMLClient) Send(msg string) error { + _, err := fmt.Fprintln(c.conn, msg) + if err != nil { + return err + } + time.Sleep(c.awaitTime) + return nil +} + +// 封装Receive函数,用于从TCP连接中接收数据 +func (c *MMLClient) Receive() (string, error) { + buf := make([]byte, 1024*8) + n, err := c.reader.Read(buf) + if err != nil { + if err == io.EOF { + return "", fmt.Errorf("server closed the connection") + } + return "", err + } + + return string(buf[0:n]), nil +} + +// 封装Close函数,用于关闭TCP连接 +func (c *MMLClient) Close() error { + return c.conn.Close() +} diff --git a/lib/core/mml_client/send.go b/lib/core/mml_client/send.go new file mode 100644 index 00000000..7a637f57 --- /dev/null +++ b/lib/core/mml_client/send.go @@ -0,0 +1,74 @@ +package mmlclient + +import ( + "fmt" + "strings" +) + +// 发送MML +// ip 网元IP地址 +// msg 指令 +func MMLSendMsgToString(ip, msg string) (string, error) { + // 创建MMLClient实例 + client, err := NewMMLClient(ip) + if err != nil { + return "", fmt.Errorf("创建MMLClient实例失败:%v", err) + } + defer client.Close() + + // 发送数据 + err = client.Send(msg) + if err != nil { + return "", fmt.Errorf("发送数据失败:%v", err) + } + + // 接收数据 + data, err := client.Receive() + if err != nil { + return "", fmt.Errorf("接收数据失败:%v", err) + } + + return data, nil +} + +// 发送MML +// ip 网元IP地址 +// msg 指令 +func MMLSendMsgToMap(ip, msg string) (map[string]string, error) { + // 发送获取数据 + str, err := MMLSendMsgToString(ip, msg) + + // 初始化一个map用于存储拆分后的键值对 + m := make(map[string]string) + + var items []string + // 按照分隔符"\r\n"进行拆分 + if strings.Contains(str, "\r\n") { + items = strings.Split(str, "\r\n") + } + // 按照分隔符"\n"进行拆分 + if strings.Contains(str, "\n") { + items = strings.Split(str, "\n") + } + + // 遍历拆分后的结果 + for _, item := range items { + var pair []string + + // 按照分隔符"="进行拆分键值对 + if strings.Contains(item, "=") { + pair = strings.Split(item, "=") + } + + // 按照分隔符":"进行拆分键值对 + if strings.Contains(item, ":") { + pair = strings.Split(item, ":") + } + + if len(pair) == 2 { + // 将键值对存入map中 + m[pair[0]] = pair[1] + } + } + return m, err +} diff --git a/lib/core/utils/ctx/ctx.go b/lib/core/utils/ctx/ctx.go index 21570310..59a5f2e4 100644 --- a/lib/core/utils/ctx/ctx.go +++ b/lib/core/utils/ctx/ctx.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "net/url" "ems.agt/lib/core/vo" "github.com/gorilla/mux" @@ -59,6 +60,13 @@ func JSON(w http.ResponseWriter, code int, data any) { } } +// 将文件导出到外部下载 +func FileAttachment(w http.ResponseWriter, r *http.Request, filepath, filename string) { + w.Header().Set("Content-Disposition", `attachment; filename=`+url.QueryEscape(filename)) + w.Header().Set("Content-Type", "application/octet-stream") + http.ServeFile(w, r, filepath) +} + /// ==== 登录用户信息, 通过中间件后预置入 // 定义自定义类型作为键 diff --git a/lib/midware/cors.go b/lib/midware/cors.go index 9eb024a3..b0a73ad6 100644 --- a/lib/midware/cors.go +++ b/lib/midware/cors.go @@ -48,10 +48,12 @@ func Cors(next http.Handler) http.Handler { // 允许请求头 allowHeaders := []string{ "Accesstoken", + "Content-Type", + "operationtype", } w.Header().Set("Access-Control-Allow-Headers", strings.Join(allowHeaders, ",")) - w.WriteHeader(500) + w.WriteHeader(204) return } diff --git a/lib/services/services.go b/lib/services/services.go index 3222f8a4..dade6a4a 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -883,15 +883,16 @@ func ResponseErrorWithJson(w http.ResponseWriter, code int, nameValue interface{ } func SetCommonResponseHeader(w http.ResponseWriter) { + // 设置Vary头部 + w.Header().Set("Vary", "Origin") + w.Header().Set("Keep-Alive", "timeout=5") // To solve cross domain issue w.Header().Set("Access-Control-Allow-Origin", "*") - // w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Methods", "*") w.Header().Set("Access-Control-Allow-Headers", "*") - // w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - // w.Header().Set("Access-Control-Allow-Headers", "AccessToken") - w.Header().Set("Access-Control-Expose-Headers", "Access-Control-Allow-Headers, Token") w.Header().Set("Access-Control-Allow-Credentials", "true") + // 响应最大时间值 + w.Header().Set("Access-Control-Max-Age", "31536000") } func SetResponseHeader(w http.ResponseWriter) {