Package datatablessrv handles the server side processing of an AJAX request for DataTables For details on the parameters and the results, read the datatables documentation at

全局模块 定义了一些 API 的正确错误返回格式 通过session jwt 获取用户uid 日志 markdown 等功能

global log 日志处理包 @since 0.0.4



const (
	ModelErr     int64 = -3
	BindErr      int64 = 40002
	NormalizeErr int64 = 40009



var APIR *gin.RouterGroup

var APIV2R *gin.RouterGroup

var AdminR *gin.RouterGroup

AdminR 后台routerGroup

var Ctx = context.TODO()

Ctx 空的 ctx

var ErrNotDataTablesReq = errors.New("Not a DataTables request")

ErrNotDataTablesReq indicates that this is not being requested by Datatables

var Errs = map[int64]JSONErr{}

Errs 错误代码

var Log *logrus.Logger

Log *logrus.Logger

var R *gin.Engine

R *gin.Engine

var TablePrefix = ""

var WechatR *gin.RouterGroup


func AppendFuncMap

func AppendFuncMap(funcName string, funcmap interface{}) error

AppendFuncMap 添加模板函数 @since 0.0.1

func CheckAdminLogin

func CheckAdminLogin(c *gin.Context)

CheckAdminLogin 检查后台是否登录 @since 0.0.1

func CheckBindErr

func CheckBindErr(c *gin.Context, errLevel ErrLevel, errName string, err error) (hasErr bool)

CheckBindErr 检查绑定表单错误

func CheckErr

func CheckErr(c *gin.Context, errType ErrType, errLevel ErrLevel, errName string, err error) (hasErr bool)

@since 0.0.1 @since 0.0.4 增加应用之间不过请求的调用 @since 0.0.9 如果 c 为 nil 则打印日志 避免内部调用的过程中有日志一楼

func CheckModelErr

func CheckModelErr(c *gin.Context, errLevel ErrLevel, errName string, err error) (hasErr bool)

CheckModelErr 检查数据库操作错误

func CheckNormalizeErr

func CheckNormalizeErr(c *gin.Context, errLevel ErrLevel, errName string, err error) (hasErr bool)

CheckNormalizeErr 检查业务约束错误

func CheckReq

func CheckReq(i interface{}) error

func CheckTxErr

func CheckTxErr(tx *sql.Tx) error

func ErrsMapAction

func ErrsMapAction(c *gin.Context)

ErrsMapAction 全局错误

func ExecErr

func ExecErr(sqlStr string, Args []interface{}, err error) error

ExecErr 执行sql语句出错 @since 0.0.17

func Funcs

func Funcs() template.FuncMap

Funcs 返回模板函数 @since 0.0.1

func GetRequestID

func GetRequestID(c *gin.Context) string

GetRequestID 获取请求ID @since 0.0.1

func GetUserID

func GetUserID(c *gin.Context) (ui64 uint64)

GetUserID 获取当前请求的用户 ID @since 0.0.10 从 token 获取

func Init

func Init()

Init 初始化 @since 0.0.1 func Init(ctx context.Context) {

func InitLogDB

func InitLogDB(db *sql.DB, h interface{}) error

func LogWithFields

func LogWithFields(c *gin.Context, fields logrus.Fields) *logrus.Entry

LogWithFields 复写 logrus.WithFields 自动传入 request_id @since 0.0.1 @since 0.0.4

func Markdown

func Markdown(content []byte) []byte

Markdown 将 md 转换为 html @since 0.0.3

func QueryErr

func QueryErr(sqlStr string, Args []interface{}, err error) error

QueryErr 执行查询类SQL失败的通用错误格式 @since 0.0.12

func RetDTJSON

func RetDTJSON(c *gin.Context, data interface{}, recordsTotal int, recordsFiltered int)

RetDTJSON 表格的通用返回结构 @since 0.0.4 by self

func RetErrJSON

func RetErrJSON(c *gin.Context, code int64, err error)

RetErrJSON 直接返回错误 json 调用后记得 return , Abort 如有需要自行处理

func RetJSON

func RetJSON(c *gin.Context, data interface{})

func RetTableJSON

func RetTableJSON(c *gin.Context, data interface{}, total uint64)

RetTableJSON 返回表格用的通用结构体 处理分页的问题 @since 0.0.12

func SQLLog

func SQLLog(sqlStr string, Args []interface{})

SQLLog 用于记录 sql @since 0.0.12

func ScanErr

func ScanErr(sqlStr string, Args []interface{}, err error) error

QueryErr 查询结果绑定时失败的通用错误格式 @since 0.0.12

func ToSQLErr

func ToSQLErr(sqlStr string, Args []interface{}, err error) error

ToSQLErr 生成SQL失败的通用错误格式 @since 0.0.12

func Uint64ArrToInterfaceArr

func Uint64ArrToInterfaceArr(arr []uint64) []interface{}

Uint64ArrToInterfaceArr 用于数据库 in 查询 @since 0.0.12

func WarnSQL

func WarnSQL(msg string, sqlStr string, args []interface{}, err error)

WarnSQL 错误的 sql 日志 @since 0.0.9


type ColData

type ColData struct {
	// columns[i][name] Column's name, as defined by
	Name string
	// columns[i][data] Column's data source, as defined by
	// It is poss
	Data string
	// columns[i][searchable]	boolean	Flag to indicate if this column is searchable (true) or not (false).
	// This is controlled by columns.searchable.
	Searchable bool
	// columns[i][orderable] Flag to indicate if this column is orderable (true) or not (false).
	// This is controlled by columns.orderable.
	Orderable bool
	// columns[i][search][value] Search value to apply to this specific column.
	Searchval string
	// columns[i][search][regex]
	// Flag to indicate if the search term for this column should be treated as regular expression (true) or not (false).
	// As with global search, normally server-side processing scripts will not perform regular expression searching
	// for performance reasons on large data sets, but it is technically possible and at the discretion of your script.
	UseRegex bool

ColData tracks all of the columns requested by DataTables

type DataTablesInfo

type DataTablesInfo struct {
	// HasFilter Indicates there is a filter on the data to apply.  It is used to optimize generating
	// the query filters
	HasFilter bool
	// Draw counter. This is used by DataTables to ensure that the Ajax returns
	// from server-side processing requests are drawn in sequence by DataTables
	// (Ajax requests are asynchronous and thus can return out of sequence).
	// This is used as part of the draw return parameter (see below).
	Draw int
	// Start is the paging first record indicator.
	// This is the start point in the current data set (0 index based - i.e. 0 is the first record).
	Start int
	// Length is the number of records that the table can display in the current draw.
	// It is expected that the number of records returned will be equal to this number, unless the server has fewer records to return.
	//  Note that this can be -1 to indicate that all records should be returned (although that negates any benefits of server-side processing!)
	Length int
	// Searchval holds the global search value. To be applied to all columns which have searchable as true.
	Searchval string
	// UseRegex is true if the global filter should be treated as a regular expression for advanced searching.
	//  Note that normally server-side processing scripts will not perform regular expression
	//  searching for performance reasons on large data sets, but it is technically possible and at the discretion of your script.
	UseRegex bool
	// Order provides information about what columns are to be ordered in the results and which direction
	Order []OrderInfo
	// Columns provides a mapping of what fields are to be searched
	Columns []ColData

DataTablesInfo represents all of the information that was requested by DataTables

func ParseDatatablesRequest

func ParseDatatablesRequest(r *http.Request) (res *DataTablesInfo, err error)

ParseDatatablesRequest checks the HTTP request to see if it corresponds to a datatables AJAX data request and parses the request data into the DataTablesInfo structure.

This structure can be used by MySQLFilter and MySQLOrderby to generate a MySQL query to run against a database.

For example assuming you are going to fill in a response structure to DataTables such as:

type QueryResponse struct {
    DateAdded   time.Time
    Status      string
    Email       struct {
        Name      string
        Email     string
var emailQueueFields = map[string]string{
    "DateAdded":          "t1.dateadded",
    "Status":             "t1.status",
    "Email.Name":         "t2.Name",
    "Email.Email":        "t2.Email",

const baseQuery = `
    SELECT t1.dateadded
    FROM infotable t1
    LEFT JOIN usertable t2
      ON t1.key = t2.key`

    // See if we have a where clause to add to the base query
    query := baseQuery
    sqlPart, err := di.MySQLFilter(sqlFields)
    // If we did have a where filter, append it.  Note that it doesn't put the " WHERE "
    // in front because we might be doing a boolean operation.
    if sqlPart != "" {
        query += " WHERE " + sqlPart
    sqlPart, err = di.MySQLOrderby(sqlFields)
    query += sqlPart

At that point you have a query that you can send straight to mySQL

func (*DataTablesInfo) MySQLFilter

func (di *DataTablesInfo) MySQLFilter(SQLFieldMap map[string]string) (res string, err error)

MySQLFilter generates the filter for a mySQL query based on the request and a map of the strings to the database entries. Note if the field is searchable and we don't have a map, this generates an error It is assumed that there is a fulltext index on fields in very large tables in order to optimize performance of this generated query We have several things that we can generate here. For the global string, (in di.Searchval) with no Regex we would generate something like

MATCH (field1,field2,field3) AGAINST('searchval')

If an individual entry has a searchval with no Regex we generate

MATCH (field1) AGAINST('searchval')

If we have a global string with a regex, we generate

field1 REGEX 'searchval' OR field2 REGEX 'searchval' OR field3 REGEX 'searchval'

Likewise for individual entries with a searchval we generate

field1 REGEX 'searchval'

Note: If the searchval doesn't actually contain wildcard values (^$.*+|(){}[]?) then the search value bit is actually cleared by ParseDatatablesRequest so that we never actually see it NOTE: It is the responsibility of the caller to put the " WHERE " in front of the string when it is non-null. This allows the filter to be used in other situations or where it may need to be part of a more complex logical operation NOTE: We assume that the Searchval strings have all been escaped and quoted so that we can put in the string with no potential SQL injection

func (*DataTablesInfo) MySQLLimit

func (di *DataTablesInfo) MySQLLimit() (res string, err error)

MySQLLimit @since 0.0.4

func (*DataTablesInfo) MySQLOrderby

func (di *DataTablesInfo) MySQLOrderby(SQLFieldMap map[string]string) (res string, err error)

MySQLOrderby generates the order by clause for a mySQL query based on the request and a map of the strings to the database entries. Note if the field is orderable and we don't have a map, this generates an error. The string IS prefixed by a space so that you can just append it.

type ErrLevel

type ErrLevel int
const (
	// PanicLevel level, highest level of severity. Logs and then calls panic with the
	// message passed to Debug, Info, ...
	Panic ErrLevel = iota
	// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
	// logging level is set to Panic.
	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
	// Commonly used for hooks to send errors to an error tracking service.
	// WarnLevel level. Non-critical entries that deserve eyes.
	// InfoLevel level. General operational entries about what's going on inside the
	// application.
	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
	// TraceLevel level. Designates finer-grained informational events than the Debug.

on your instance of logger, obtained with `logrus.New()`.

type ErrType

type ErrType int
const (
	// 绑定表单出错
	BindForm ErrType = iota
	// 数据库操作出错
	// 业务调用合规检查

todo 查证作用

type JSONErr

type JSONErr struct {
	Errcode   int64       `json:"errcode"` // 可能会用到负数编码
	Errmsg    string      `json:"errmsg"`
	RequestID string      `json:"request_id"`
	Data      interface{} `json:"data"` // data object

JSONErr 错误结构体 code = 0 为正确

func GetErr

func GetErr(c *gin.Context, code int64, err error) JSONErr

GetErr 获取错误结构体

func GetJSONErr

func GetJSONErr(c *gin.Context) *JSONErr

GetJSONErr 获取通用的 API 返回结果的 json 格式 @since 0.0.1 TODO 这个是为了返回 0 ok 正常的api结构体 需要替换为 RetJSON

type LogDBHook

type LogDBHook struct{}

func (*LogDBHook) Fire

func (h *LogDBHook) Fire(*logrus.Entry) error

func (*LogDBHook) Levels

func (h *LogDBHook) Levels() []logrus.Level


type OrderInfo

type OrderInfo struct {
	// ColNum indicates Which column to apply sorting to (zero based index to the Columns data)
	ColNum int
	// Direction tells us which way to sort
	Direction SortDir

OrderInfo tracks the list of columns to sort by and in which direction to sort them.

type SortDir

type SortDir int

SortDir is the direction of the sort (ascending/descending)

const (
	// Asc for ascending sorting
	Asc SortDir = iota
	// Desc for descending sorting

type Valid

type Valid interface{}

TODO 这里是想把 表单绑定的结构体和程序内部调用校验用的结构体合并