123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- package rest
- import (
- "context"
- "encoding/csv"
- "encoding/json"
- "fmt"
- "git.nspix.com/golang/micro/gateway/http"
- errpkg "git.nspix.com/golang/rest/v3/error"
- "git.nspix.com/golang/rest/v3/inflector"
- "gorm.io/gorm"
- "gorm.io/gorm/clause"
- "path"
- "reflect"
- "strconv"
- "strings"
- )
- const (
- HttpAccessDenied = 8004 //拒绝访问
- HttpInvalidPayload = 8002 //请求内容无效
- HttpRequestCallbackFailed = 8003 //执行回调失败
- HttpValidateFailed = 8008 //数据校验失败
- HttpDatabaseQueryFailed = 8010 //查询失败
- HttpDatabaseFindFailed = 8011 //查找失败
- HttpDatabaseCreateFailed = 8012 //创建失败
- HttpDatabaseUpdateFailed = 8013 //更新失败
- HttpDatabaseDeleteFailed = 8014 //删除失败
- HttpDatabaseExportFailed = 8015 //数据导出失败
- HTTPUnknownFailed = 9001 //未知错误
- )
- const (
- ErrorAccessDeniedMessage = "access denied"
- )
- type (
- DiffAttr struct {
- Column string `json:"column"`
- Label string `json:"label"`
- OldValue interface{} `json:"old_value"`
- NewValue interface{} `json:"new_value"`
- }
- Restful struct {
- model Model
- opts *Options
- reflectType reflect.Type
- reflectValue reflect.Value
- singularName string
- pluralizeName string
- statement *gorm.Statement
- primaryKey string
- }
- )
- // getScenarioUrl 获取某个场景下HTTP请求的URL
- func (r *Restful) getScenarioUrl(scenario string) string {
- var uri string
- switch scenario {
- case ScenarioList:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.pluralizeName
- case ScenarioView:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
- case ScenarioCreate:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName
- case ScenarioUpdate:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
- case ScenarioDelete:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
- case ScenarioExport:
- uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "-export"
- }
- return path.Clean(uri)
- }
- // getScenarioHandle 获取某个场景下HTTP请求的处理回调
- func (r *Restful) getScenarioHandle(scenario string) http.HandleFunc {
- var handleFunc http.HandleFunc
- switch scenario {
- case ScenarioList:
- handleFunc = r.actionIndex
- case ScenarioView:
- handleFunc = r.actionView
- case ScenarioCreate:
- handleFunc = r.actionCreate
- case ScenarioUpdate:
- handleFunc = r.actionUpdate
- case ScenarioDelete:
- handleFunc = r.actionDelete
- case ScenarioExport:
- handleFunc = r.actionExport
- }
- return handleFunc
- }
- func (r *Restful) setFieldValue(model reflect.Value, column string, value interface{}) {
- var (
- name string
- )
- refVal := reflect.Indirect(model)
- for _, field := range r.statement.Schema.Fields {
- if field.DBName == column {
- name = field.Name
- break
- } else if field.Name == column {
- name = column
- break
- }
- }
- if name == "" {
- return
- }
- fieldVal := refVal.FieldByName(name)
- if fieldVal.CanSet() {
- fieldVal.Set(reflect.ValueOf(value))
- }
- }
- //getFieldValue get field value from reflect value
- func (r *Restful) getFieldValue(model reflect.Value, column string) interface{} {
- var (
- name string
- )
- refVal := reflect.Indirect(model)
- for _, field := range r.statement.Schema.Fields {
- if field.DBName == column {
- name = field.Name
- break
- } else if field.Name == column {
- name = column
- break
- }
- }
- if name == "" {
- return nil
- }
- fieldVal := refVal.FieldByName(name)
- return fieldVal.Interface()
- }
- func (r *Restful) hasScenario(s string) bool {
- if v, ok := r.model.(FlexibleModel); ok {
- for _, n := range v.Scenarios() {
- if s == n {
- return true
- }
- }
- return false
- }
- return true
- }
- func (r *Restful) prepareConditions(ctx context.Context, requestCtx *http.Context, query *Query, schemas []*Schema) (err error) {
- var (
- ok bool
- skip bool
- formValue string
- model interface{}
- activeModel ActiveModel
- )
- model = reflect.New(r.reflectType).Interface()
- if r.opts.Delegate != nil {
- if err = r.opts.Delegate.BeforeQuery(ctx, query); err != nil {
- return
- }
- }
- if activeModel, ok = model.(ActiveModel); ok {
- if err = activeModel.BeforeQuery(ctx, query); err != nil {
- return
- }
- }
- //处理默认的搜索
- for _, schema := range schemas {
- skip = false
- if skip {
- continue
- }
- if schema.Native == 0 {
- continue
- }
- formValue = requestCtx.FormValue(schema.Column)
- switch schema.Format {
- case FormatString, FormatText:
- if schema.Attribute.Match == MatchExactly {
- query.AndFilterWhere(NewCond(schema.Column, formValue))
- } else {
- query.AndFilterWhere(NewCond(schema.Column, formValue).WithExpr("LIKE"))
- }
- case FormatTime, FormatDate, FormatDatetime, FormatTimestamp:
- var sep string
- seps := []byte{',', '/'}
- for _, s := range seps {
- if strings.IndexByte(formValue, s) > -1 {
- sep = string(s)
- }
- }
- if ss := strings.Split(formValue, sep); len(ss) == 2 {
- query.AndFilterWhere(
- NewCond(schema.Column, strings.TrimSpace(ss[0])).WithExpr(">="),
- NewCond(schema.Column, strings.TrimSpace(ss[1])).WithExpr("<="),
- )
- } else {
- query.AndFilterWhere(NewCond(schema.Column, formValue))
- }
- case FormatInteger, FormatFloat:
- query.AndFilterWhere(NewCond(schema.Column, formValue))
- default:
- if schema.Type == TypeString {
- if schema.Attribute.Match == MatchExactly {
- query.AndFilterWhere(NewCond(schema.Column, formValue))
- } else {
- query.AndFilterWhere(NewCond(schema.Column, formValue).WithExpr("LIKE"))
- }
- } else {
- query.AndFilterWhere(NewCond(schema.Column, formValue))
- }
- }
- }
- //处理排序
- sortPar := requestCtx.FormValue("sort")
- if sortPar != "" {
- sorts := strings.Split(sortPar, ",")
- for _, s := range sorts {
- if s[0] == '-' {
- query.OrderBy(s[1:], "DESC")
- } else {
- if s[0] == '+' {
- query.OrderBy(s[1:], "ASC")
- } else {
- query.OrderBy(s, "ASC")
- }
- }
- }
- }
- if activeModel, ok = model.(ActiveModel); ok {
- err = activeModel.AfterQuery(ctx, query)
- }
- if r.opts.Delegate != nil {
- err = r.opts.Delegate.AfterQuery(ctx, query)
- }
- return
- }
- func (r *Restful) actionIndex(httpCtx *http.Context) (err error) {
- var (
- page int
- pageSize int
- pageIndex int
- query *Query
- namespace string
- )
- if !r.hasScenario(ScenarioList) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- ctx := httpCtx.Request().Context()
- if ctx == nil {
- ctx = context.Background()
- }
- namespace = httpCtx.ParamValue(NamespaceVariable)
- ctx = context.WithValue(ctx, NamespaceField, namespace)
- ctx = context.WithValue(ctx, "request", httpCtx.Request())
- page, _ = strconv.Atoi(httpCtx.FormValue("page"))
- pageSize, _ = strconv.Atoi(httpCtx.FormValue("pagesize"))
- if pageSize <= 0 {
- pageSize = 15
- }
- pageIndex = page
- if pageIndex > 0 {
- pageIndex--
- }
- sliceValue := reflect.MakeSlice(reflect.SliceOf(r.reflectType), 0, 0)
- models := reflect.New(sliceValue.Type())
- models.Elem().Set(sliceValue)
- query = NewQuery(r.opts.DB)
- searchSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioSearch)
- indexSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioList)
- if err = r.prepareConditions(ctx, httpCtx, query, searchSchemas); err != nil {
- return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
- }
- if r.opts.EnableNamespace {
- query.AndFilterWhere(NewQueryCondition(NamespaceField, namespace))
- }
- query.Offset(pageIndex * pageSize).Limit(pageSize)
- if err = query.All(models.Interface()); err != nil {
- return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
- }
- resp := &ListResponse{
- Page: page,
- PageSize: pageSize,
- TotalCount: query.Limit(0).Offset(0).Count(r.model),
- }
- if resp.TotalCount > 0 {
- resp.Data = r.opts.Formatter.formatModels(ctx, models.Interface(), indexSchemas, r.statement)
- } else {
- resp.Data = make([]string, 0)
- }
- return httpCtx.Success(resp)
- }
- func (r *Restful) actionCreate(httpCtx *http.Context) (err error) {
- var (
- errTx error
- namespace string
- model interface{}
- schemas []*Schema
- refModel reflect.Value
- diffAttrs []*DiffAttr
- )
- ctx := httpCtx.Request().Context()
- if ctx == nil {
- ctx = context.Background()
- }
- diffAttrs = make([]*DiffAttr, 0, 10)
- if !r.hasScenario(ScenarioCreate) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- namespace = httpCtx.ParamValue(NamespaceVariable)
- refModel = reflect.New(r.reflectType)
- model = refModel.Interface()
- if err = httpCtx.Bind(model); err != nil {
- return httpCtx.Error(HttpInvalidPayload, err.Error())
- }
- schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioCreate)
- //global set field value
- r.setFieldValue(refModel, NamespaceField, namespace)
- r.setFieldValue(refModel, CreatedByField, httpCtx.ParamValue(UserVariable))
- r.setFieldValue(refModel, CreatedDeptField, httpCtx.ParamValue(DepartmentVariable))
- r.setFieldValue(refModel, UpdatedByField, httpCtx.ParamValue(UserVariable))
- r.setFieldValue(refModel, UpdatedDeptField, httpCtx.ParamValue(DepartmentVariable))
- if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.BeforeCreate(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = r.opts.Delegate.BeforeSave(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.BeforeCreate(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = activeModel.BeforeSave(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- //创建数据
- if errTx = tx.Create(model).Error; errTx != nil {
- return errTx
- }
- //对比差异数据
- for _, scm := range schemas {
- diffAttrs = append(diffAttrs, &DiffAttr{
- Column: scm.Column,
- Label: scm.Label,
- OldValue: nil,
- NewValue: r.getFieldValue(refModel, scm.Column),
- })
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.AfterCreate(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
- }
- if errTx = activeModel.AfterSave(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
- }
- }
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.AfterCreate(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
- }
- if errTx = r.opts.Delegate.AfterSave(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
- }
- }
- return errTx
- }); err == nil {
- pkVal := r.getFieldValue(refModel, r.primaryKey)
- return httpCtx.Success(&CreateResponse{
- ID: pkVal,
- Topic: r.model.TableName(),
- State: "created",
- })
- }
- //form validation
- if validateError, ok := err.(*errpkg.StructError); ok {
- httpCtx.Response().Header().Set("Content-Type", "application/json")
- return json.NewEncoder(httpCtx.Response()).Encode(map[string]interface{}{
- "errno": HttpValidateFailed,
- "result": validateError,
- })
- }
- return httpCtx.Error(HttpDatabaseCreateFailed, err.Error())
- }
- func (r *Restful) actionUpdate(httpCtx *http.Context) (err error) {
- var (
- errTx error
- namespace string
- model interface{}
- schemas []*Schema
- refModel reflect.Value
- oldValues = make(map[string]interface{})
- diffs = make(map[string]interface{})
- diffAttrs = make([]*DiffAttr, 0)
- )
- ctx := httpCtx.Request().Context()
- if ctx == nil {
- ctx = context.Background()
- }
- if !r.hasScenario(ScenarioUpdate) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- namespace = httpCtx.ParamValue(NamespaceVariable)
- idStr := httpCtx.ParamValue("id")
- refModel = reflect.New(r.reflectType)
- model = refModel.Interface()
- //默认设置更新用户
- r.setFieldValue(refModel, UpdatedByField, httpCtx.ParamValue(UserVariable))
- r.setFieldValue(refModel, UpdatedDeptField, httpCtx.ParamValue(DepartmentVariable))
- conditions := map[string]interface{}{
- r.primaryKey: idStr,
- }
- if r.opts.EnableNamespace {
- conditions[NamespaceField] = namespace
- }
- if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
- return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
- }
- schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioUpdate)
- for _, scm := range schemas {
- oldValues[scm.Column] = r.getFieldValue(refModel, scm.Column)
- }
- if err = httpCtx.Bind(model); err != nil {
- return httpCtx.Error(HttpInvalidPayload, err.Error())
- }
- if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.BeforeUpdate(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = r.opts.Delegate.BeforeSave(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.BeforeUpdate(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = activeModel.BeforeSave(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- //对比差异数据
- for _, scm := range schemas {
- v := r.getFieldValue(refModel, scm.Column)
- if oldValues[scm.Column] != v {
- diffs[scm.Column] = v
- diffAttrs = append(diffAttrs, &DiffAttr{
- Column: scm.Column,
- Label: scm.Label,
- OldValue: oldValues[scm.Column],
- NewValue: v,
- })
- }
- }
- //进行局部数据更新
- if len(diffs) > 0 {
- if errTx = tx.Model(model).Updates(diffs).Error; errTx != nil {
- return errTx
- }
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.AfterUpdate(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = activeModel.AfterSave(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.AfterUpdate(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- if errTx = r.opts.Delegate.AfterSave(ctx, model, diffAttrs); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- return errTx
- }); err == nil {
- pkVal := r.getFieldValue(refModel, r.primaryKey)
- return httpCtx.Success(&UpdateResponse{
- ID: pkVal,
- Topic: r.model.TableName(),
- State: "updated",
- })
- }
- //form validation
- if validateError, ok := err.(*errpkg.StructError); ok {
- httpCtx.Response().Header().Set("Content-Type", "application/json")
- return json.NewEncoder(httpCtx.Response()).Encode(map[string]interface{}{
- "errno": HttpValidateFailed,
- "result": validateError,
- })
- }
- return httpCtx.Error(HttpDatabaseUpdateFailed, err.Error())
- }
- func (r *Restful) actionDelete(httpCtx *http.Context) (err error) {
- var (
- errTx error
- model interface{}
- namespace string
- )
- if !r.hasScenario(ScenarioDelete) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- ctx := httpCtx.Request().Context()
- if ctx == nil {
- ctx = context.Background()
- }
- idStr := httpCtx.ParamValue("id")
- namespace = httpCtx.ParamValue(NamespaceVariable)
- model = reflect.New(r.reflectType).Interface()
- conditions := map[string]interface{}{
- r.primaryKey: idStr,
- }
- if r.opts.EnableNamespace {
- conditions[NamespaceField] = namespace
- }
- if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
- return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
- }
- if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.BeforeDelete(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.BeforeDelete(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if errTx = tx.Delete(model).Error; errTx != nil {
- return errTx
- }
- if activeModel, ok := model.(ActiveModel); ok {
- if errTx = activeModel.AfterDelete(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- if r.opts.Delegate != nil {
- if errTx = r.opts.Delegate.AfterDelete(ctx, model); errTx != nil {
- return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
- }
- }
- return errTx
- }); err == nil {
- return httpCtx.Success(&DeleteResponse{
- ID: r.getFieldValue(reflect.ValueOf(model), r.primaryKey),
- Topic: r.model.TableName(),
- State: "updated",
- })
- } else {
- return httpCtx.Error(HttpDatabaseDeleteFailed, err.Error())
- }
- }
- func (r *Restful) actionExport(httpCtx *http.Context) (err error) {
- var (
- query *Query
- namespace string
- )
- if !r.hasScenario(ScenarioExport) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- ctx := httpCtx.Request().Context()
- if ctx == nil {
- ctx = context.Background()
- }
- ctx = context.WithValue(ctx, NamespaceVariable, namespace)
- namespace = httpCtx.ParamValue(NamespaceVariable)
- sliceValue := reflect.MakeSlice(reflect.SliceOf(r.reflectType), 0, 0)
- models := reflect.New(sliceValue.Type())
- models.Elem().Set(sliceValue)
- query = NewQuery(r.opts.DB)
- searchSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioSearch)
- exportSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioList)
- if err = r.prepareConditions(ctx, httpCtx, query, searchSchemas); err != nil {
- return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
- }
- if r.opts.EnableNamespace {
- query.AndFilterWhere(NewQueryCondition(NamespaceVariable, namespace))
- }
- if err = query.All(models.Interface()); err != nil {
- return httpCtx.Error(HttpDatabaseExportFailed, err.Error())
- }
- httpCtx.Response().Header().Set("Content-Type", "text/csv")
- httpCtx.Response().Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
- httpCtx.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", r.singularName))
- value := r.opts.Formatter.formatModels(ctx, models.Interface(), exportSchemas, r.statement)
- writer := csv.NewWriter(httpCtx.Response())
- ss := make([]string, len(exportSchemas))
- for i, field := range exportSchemas {
- ss[i] = field.Label
- }
- _ = writer.Write(ss)
- if values, ok := value.([]interface{}); ok {
- for _, val := range values {
- row, ok2 := val.(map[string]interface{})
- if !ok2 {
- continue
- }
- for i, field := range exportSchemas {
- if v, ok := row[field.Column]; ok {
- ss[i] = fmt.Sprint(v)
- } else {
- ss[i] = ""
- }
- }
- _ = writer.Write(ss)
- }
- }
- writer.Flush()
- return
- }
- func (r *Restful) actionView(httpCtx *http.Context) (err error) {
- var (
- model interface{}
- namespace string
- )
- if !r.hasScenario(ScenarioView) {
- return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
- }
- namespace = httpCtx.ParamValue(NamespaceVariable)
- scenario := httpCtx.FormValue("scenario")
- idStr := httpCtx.ParamValue("id")
- model = reflect.New(r.reflectType).Interface()
- conditions := map[string]interface{}{
- r.primaryKey: idStr,
- }
- if r.opts.EnableNamespace {
- conditions[NamespaceField] = namespace
- }
- if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
- return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
- }
- if httpCtx.FormValue("format") != "" {
- //获取指定场景下面的字段进行渲染显示
- var schemas []*Schema
- if scenario == "" {
- schemas = r.opts.LookupFunc(httpCtx.Request().Context(), namespace, r.model.ModuleName(), r.model.TableName(), ScenarioView)
- } else {
- schemas = r.opts.LookupFunc(httpCtx.Request().Context(), namespace, r.model.ModuleName(), r.model.TableName(), scenario)
- }
- requestCtx := httpCtx.Request().Context()
- if requestCtx == nil {
- requestCtx = context.Background()
- }
- requestCtx = context.WithValue(requestCtx, NamespaceVariable, namespace)
- return httpCtx.Success(r.opts.Formatter.formatModel(requestCtx, model, schemas, r.statement))
- }
- return httpCtx.Success(model)
- }
- func newRestful(model Model, opts *Options) *Restful {
- var (
- err error
- tableName string
- )
- r := &Restful{
- opts: opts,
- model: model,
- reflectValue: reflect.Indirect(reflect.ValueOf(model)),
- }
- r.reflectType = r.reflectValue.Type()
- tableName = model.TableName()
- r.singularName = inflector.Singularize(tableName)
- r.pluralizeName = inflector.Pluralize(tableName)
- r.statement = &gorm.Statement{
- DB: r.opts.DB,
- ConnPool: r.opts.DB.ConnPool,
- Clauses: map[string]clause.Clause{},
- }
- if err = r.statement.Parse(model); err == nil {
- if r.statement.Schema != nil {
- if r.statement.Schema.PrimaryFieldDBNames != nil && len(r.statement.Schema.PrimaryFieldDBNames) > 0 {
- r.primaryKey = r.statement.Schema.PrimaryFieldDBNames[0]
- }
- }
- }
- return r
- }
|