first commit

master
18650180552 2019-01-25 17:11:15 +08:00
parent 038862eaec
commit edd5a83d3d
13 changed files with 2592 additions and 0 deletions

75
config/config.go Normal file
View File

@ -0,0 +1,75 @@
package config
import (
"log"
"gopkg.in/yaml.v2"
"os"
"runtime"
)
var ostype = runtime.GOOS
var conf ConfAPI
type ConfAPI struct {
ListenSvr int `yaml:"listen_svr"` // 服务监听端口
ListenApi int `yaml:"listen_api"` // 服务监听端口
RunMode string `yaml:"runmode"` // 服务运行模式
MaxConn int `yaml:"max_conn"`
Logs LogConfig `yaml:"logs"` // 日志
Redis RedisConfig `yaml:"redis"`
Mysql MysqlConfig `yaml:"mysql"` // 认证配置
init bool
}
type RedisConfig struct {
Addr string `yaml:"addr"`
Pwd string `yaml:"password"`
DB int64 `yaml:"db"`
}
type LogConfig struct {
Dir string `yaml:"dir"`
File string `yaml:"file"`
Level int `yaml:"level"`
SaveFile bool `yaml:"savefile"`
}
type MysqlConfig struct {
Addr string `yaml:"addr"`
UserName string `yaml:"user"`
Password string `yaml:"password"`
Db string `yaml:"db"`
MaxOpen int `yaml:"max_open"`
MaxIdle int `yaml:"max_idle"`
}
var gConf ConfAPI
func Init(path string) error {
file,e := os.Open(path)
if nil != e{
log.Println(e.Error())
return e
}
stat,_ := file.Stat()
filec := make([]byte, stat.Size())
file.Read(filec)
e = yaml.Unmarshal(filec,&gConf)
if nil != e{
log.Println(e.Error())
}
gConf.init = true
return nil
}
func GetPort() int {
if gConf.init{
return gConf.ListenApi
}else {
return 8001
}
}
func GetMysqlConfig() *MysqlConfig{
if gConf.init{
return &gConf.Mysql
}else {
return nil
}
}

550
controller/hanlder.go Normal file
View File

@ -0,0 +1,550 @@
package controller
import (
"bytes"
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"github.com/fatih/structs"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"github.com/tommy351/gin-sessions"
"io"
"strconv"
"time"
"user/logs"
"log"
"math/rand"
"net/http"
"net/smtp"
"regexp"
"strings"
"user/redis"
"user/model"
"user/db"
)
type ReqSendEmailCode struct {
EmailAdress string `json:"email_address"`
}
type SetUserGroupReq struct {
Id int64 `json:"id,omitempty"`
Description string `json:"description"`
GroupName string `json:"group_name"`
UserIds []int `json:"user_ids"`
}
type RespBase struct {
Msg string
Status int
Data interface{}
}
func Auth(c *gin.Context) {
var resp RespBase
var statuscode int
statuscode = 200
var userinfo map[string] interface{}
//var userSockToken map[string] interface{}
defer func() {
c.JSON(statuscode, resp)
}()
socketToken := c.Query("socketToken")
struserinfo ,e := redis.Get(socketToken)
if e != nil{
logs.Error(e.Error())
return
}
e = json.Unmarshal([]byte(struserinfo),userinfo)
if nil != e{
logs.Error(e.Error())
return
}
}
// SetUser godoc
// @Summary SetUser
// @Description set userinfo
// @Accept json
// @Produce json
// @Param q query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Failure 400 {object} util.RespBase
// @Failure 404 {object} util.RespBase
// @Failure 500 {object} util.RespBase
// @Router /accounts [get]
func SetUser(c *gin.Context){
}
func DelUser(c *gin.Context){
}
func GetUser(c *gin.Context) {
var resp RespBase
resp.Msg = "操作失败"
resp.Status = 20
defer func() {
c.JSON(200,resp)
}()
session := sessions.Get(c)
userinfo := session.Get("")
if userinfo == nil{
logs.Error("error could not find key")
return
}
var users map[string] interface{}
e := json.Unmarshal([]byte(userinfo.(string)),&users)
if nil != e {
logs.Error(e.Error())
}
delete(users,"socketToken")
resp.Status = 0
resp.Msg = "操作成功"
resp.Data = users
}
// GetUsers godoc
// @Summary GetUsers
// @Description Get all user with query
// @Accept json
// @Produce json
// @Param page query int 1 "分页的页数"
// @Param pageSize query int 10 "name search by q"
// @Param displayname query string false "name search by q"
// @Param department_id query string false "name search by q"
// @Param permission_type query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Failure 400 {object} util.RespBase
// @Failure 404 {object} util.RespBase
// @Failure 500 {object} util.RespBase
// @Router /api/users [get]
func GetUsers(c *gin.Context) {
var statuscode int
var resp RespBase
resp.Msg = "获取失败"
resp.Status = 0
statuscode = 200
defer func() {
c.JSON(statuscode,resp)
}()
//获取用户组信息
var page int
var pageSize int
var displayname string
var department_id string
var permission_type string
displayname = c.Query("displayname")
department_id = c.Query("department_id")
permission_type = c.Query("permission_type")
if c.Query("page") == ""{
page = 0
}else {
var err error
page,err = strconv.Atoi(c.Query("page"))
if err != nil{
logs.Error("error ato i ")
}
}
log.Println(pageSize,page)
if c.Query("pageSize") == ""{
pageSize = 10
}else {
var err error
pageSize,err = strconv.Atoi(c.Query("pageSize"))
if err != nil{
logs.Error("error ato i ")
}
}
session := sessions.Get(c)
userinfo := session.Get("")
var users map[string] interface{}
e := json.Unmarshal([]byte(userinfo.(string)),&users)
if nil != e {
logs.Error(e.Error())
}
permission,ok := users["PermissionType"]
if !ok{
logs.Error("error could not find permission_type")
return
}
// 部门组长只允许查看自己所在部门成员列表,且要过滤超级管理员
if permission == 1 && department_id != ""{
d ,_ := users["DepartmentId"]
department_id = d.(string)
}
respdata := make(map[string]interface{},1)
var usersinfo []model.Users
if permission != 0{
query := "select * from users "
if displayname != "" || department_id != "" ||permission_type != ""{
query += " where "
}
if displayname != ""{
query += fmt.Sprintf("display_name like '%%%s%%'",displayname)
}
if department_id != ""{
query += fmt.Sprintf("and department_id = %s",department_id)
}
if permission_type != ""{
query += fmt.Sprintf("and permission_type = %s ",permission_type)
}
query += "order by id ASC "
query += fmt.Sprintf("limit %d ",pageSize)
query += fmt.Sprintf(" offset %d ",pageSize*page)
e := db.GetMysqlClient().Query2(query,&usersinfo)
if e != nil{
log.Println(e.Error())
}
respdata["rows"] = usersinfo
respdata["total"] = len(usersinfo)
respdata["page"] = page
respdata["pageSize"] = pageSize
}
resp.Msg = "OK"
resp.Data = respdata
}
func CreateVerify(length int32) string{
strAry := []byte{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
result := string("")
for i := int32(0); i < length; i++ {
x := rand.Intn(len(strAry))
result += string(strAry[x])
}
return result
}
/**
* Token
* @param {Number} length Token
* @return {string} Token
*/
func createToken(length int32) string{
strAry := []byte{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_' };
result := string("")
for i := int32(0); i < length; i++ {
x := rand.Intn(len(strAry))
result += string(strAry[x])
}
return result
}
func ByteSliceToString(b []byte) string {
var ret string
for i := 0;i < len(b) ;i++{
s := fmt.Sprintf("%02x",b[i])
ret += string(s)
}
return ret
}
func DefaultOption(c *gin.Context) {
var resp RespBase
defer func() {
c.JSON(204, resp)
}()
}
// Login godoc
// @Summary Login
// @Description login
// @Accept json
// @Produce json
// @Param logininfo query {object} LoginReq "登录请求参数"
// @Success 200 {array} util.RespBase
// @Failure 400 {object} util.RespBase
// @Failure 404 {object} util.RespBase
// @Failure 500 {object} util.RespBase
// @Router /api/login [post]
func Login(c *gin.Context) {
type LoginReq struct {
RememberMe int32 `json:"remember_me"`
UserName string `json:"user_name"`
UserPwd string `json:"user_pwd"`
}
var req LoginReq
statusCode := 200
var resp RespBase
defer func() {
c.JSON(statusCode, resp)
}()
e := c.Bind(&req)
if e!= nil{
log.Println(e.Error())
return
}
h := md5.New()
h.Write([]byte(req.UserPwd)) // 需要加密的字符串为 123456
passmd5 := h.Sum(nil)
var result []model.Users
er := db.GetMysqlClient().Query2("select * from users where user_name = ?",
&result,req.UserName)
if nil != er{
log.Println(er.Error())
}
strpassmd5 := ByteSliceToString(passmd5)
if len(result) == 1 {
if result[0].UserPwd == strpassmd5 {
socketToken := md5.New()
socketToken.Write([]byte(createToken(6))) // 需要加密的字符串为 123456
socketTokenMd5 := socketToken.Sum(nil)
m := structs.Map(result[0])
m["socketToken"] = ByteSliceToString(socketTokenMd5);
sessionInfo,err := json.Marshal(m)
if err != nil{
log.Println(err.Error())
}
if req.RememberMe == 1{
redis.Set(string(socketTokenMd5),string(sessionInfo),time.Second *2 * 24 * 3600 * 1000 )
}else {
redis.Set(string(socketTokenMd5),string(sessionInfo),time.Second *8 * 3600 * 1000 )
}
//存储session
session := sessions.Get(c)
session.Set("",string(sessionInfo))
//session.
var Options *sessions.Options
if req.RememberMe == 1{
Options = &sessions.Options{
MaxAge: 2 * 24 * 3600 * 1000,
}
}else {
Options = &sessions.Options{
MaxAge: 8 * 3600 * 1000,
}
}
session.Options(*Options)
session.Save()
resp.Msg = "登录成功"
resp.Status = 0
resp.Data = string(sessionInfo)
}else {
statusCode = 422
resp.Msg = "用户密码不正确"
}
}else {
statusCode = 422
resp.Msg = "登录账号不存在,请重新输入"
}
}
func Register(c *gin.Context) {
type RegisterReq struct {
DisplayName string `json:"display_name"`
EmailAdress string `json:"email_address"`
EmailCode string `json:"email_code"`
UserName string `json:"user_name"`
UserPwd string `json:"user_pwd"`
}
var req RegisterReq
statusCode := 200
var resp RespBase
var user model.Users
resp.Msg = "失败"
resp.Status = 1
defer func() {
c.JSON(statusCode, resp)
}()
e := c.Bind(&req)
if e!= nil{
log.Println(e.Error())
return
}
session := sessions.Get(c)
email_code := session.Get(req.EmailAdress)
if email_code != req.EmailCode{
resp.Msg = "验证码错误"
resp.Status = 20
return
}
user.UserName = req.UserName
user.EmailAddress = req.EmailAdress
user.DisplayName = req.DisplayName
h := md5.New()
h.Write([]byte(req.UserPwd))
passwdmd5 := h.Sum(nil)
strpassmd5 := ByteSliceToString(passwdmd5)
user.UserPwd = strpassmd5
user.UpdatedDate = time.Now().String()
user.CreatedDate = time.Now().String()
n,er := db.GetMysqlClient().Insert("insert into users(user_name,user_pwd,created_date," +
"updated_date,display_name,email_address) values (?,?,?,?,?,?)",
user.UserName,user.UserPwd,user.CreatedDate,user.UpdatedDate,
user.DisplayName,user.EmailAddress)
if n == 0 || n < 0{
statusCode = 422
logs.Error(er.Error())
resp.Msg = "失败,账号已经存在"
resp.Status = 20
return
}
if nil != er{
statusCode = 422
logs.Error(er.Error())
resp.Msg = "失败"
resp.Status = 20
return
}
resp.Msg = "成功"
resp.Status = 0
}
func Logout(c *gin.Context) {
var resp RespBase
resp.Msg = "退出成功"
resp.Status = 0
defer func() {
c.JSON(200,resp)
}()
session := sessions.Get(c)
session.Delete("")
session.Save()
}
func Reader2Json(r io.ReadCloser) string{
var ret string
for i := 0;;i++{
s := make([]byte,10)
_,e := r.Read(s)
ret += string(s)
if e != nil{
break
}
}
return ret
}
func SendExternalEmail(msg interface{}) error{
req := make(map[string] interface{},1)
req["type"] = "text"
req["action"] = "smtp-sys"
req["apiType"] = "send"
content ,err := json.Marshal(msg)
if err != nil{
log.Println(err.Error())
return errors.New("Json marshal error")
}
req["content"] = string(content)
var buffer bytes.Buffer
b,e := json.Marshal(req)
if e != nil{
log.Println(e.Error())
}
buffer.Write(b)
resp,err := http.Post("http://47.93.230.163:8091/msg/v1/send","application/json",&buffer)
if resp.StatusCode != 200{
return errors.New("error send emain")
}
if err != nil{
logs.Error("error send email")
return err
}
return nil
}
func SendToMail(title,user string, password string, host string, to string, content string,
ifgenerate bool) error {
var content_type string
hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", user, password, hp[0])
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
msg := []byte("To: " + to + "\r\nFrom: " + user + "\r\nSubject: " + title + "\r\n" +
content_type + "\r\n\r\n"+ content + "\r\n" )
send_to := strings.Split(to, ";")
//检测是否是邮件地址
for k,_ := range send_to{
match, _ := regexp.MatchString("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?", send_to[k])
if !match{
return errors.New("Format Error")
}
}
err := smtp.SendMail(host, auth, user,send_to, msg)
if err !=nil{
return err
}
return err
}
func SendEmailCode(c *gin.Context) {
var req ReqSendEmailCode
var resp RespBase = RespBase{Msg:"邮件已经存在",Status:0}
statusCode := 200
defer func() {
c.JSON(statusCode, resp)
}()
e := c.Bind(&req)
if nil != e{
log.Println(e.Error())
resp.Msg = "请求参数错误"
return
}
//判断邮箱是否存在
var users []model.Users
db.GetMysqlClient().Query2("select * from users where email_adress = ?",&users,req.EmailAdress)
if len(users) != 0{
statusCode = 422
return
}
//产生验证码
verify := CreateVerify(6)
session := sessions.Get(c)
session.Set(req.EmailAdress,verify)
/*
var Options *sessions.Options
Options = &sessions.Options{
MaxAge: 60,
}
session.Options(*Options)*/
session.Save()
sendcontent := make( map[string] interface{},1)
sendcontent["subject"] = "邮箱验证码,请注意查收"
sendcontent["receivers"] = req.EmailAdress
sendcontent["content"] = string("您本次注册的验证码为:") + verify + string(",工作人员不会向您索取,请勿泄露。请尽快完成操作。")
e = SendExternalEmail(sendcontent)
if e != nil{
log.Println(e.Error())
return
}
//成功
resp.Msg = "发送成功"
}

0
db/README.md Normal file
View File

598
db/db.go Normal file
View File

@ -0,0 +1,598 @@
// 数据库工具包
package db
import (
"database/sql"
"document/logs"
"errors"
"fmt"
"reflect"
"strconv"
"sync"
"time"
)
// 数据容器抽象对象定义
type Database struct {
Type string // 用来给SqlBuilder进行一些特殊的判断 (空值或mysql 皆表示这是一个MySQL实例)
DB *sql.DB
}
// SQL异步执行队列定义
type queueList struct {
list []*QueueItem //队列列表
sleeping chan bool
loop chan bool
lock sync.RWMutex
quit chan bool
quited bool
}
// SQL异步执行队列子元素定义
type QueueItem struct {
DB *Database //数据库对象
Query string //SQL语句字符串
Params []interface{} //参数列表
}
// 缓存数据对象定义
type cache struct {
data map[string]map[string]interface{}
}
func (this *cache) Init() {
this.data["default"] = make(map[string]interface{})
}
// 设置缓存
func (this *cache) Set(key string, value interface{}, args ...string) {
var group string
if len(args) > 0 {
group = args[0]
if _, exist := this.data[group]; !exist {
this.data[group] = make(map[string]interface{})
}
} else {
group = "default"
}
this.data[group][key] = value
}
// 获取缓存数据
func (this *cache) Get(key string, args ...string) interface{} {
var group string
if len(args) > 0 {
group = args[0]
} else {
group = "default"
}
if g, exist := this.data[group]; exist {
if v, ok := g[key]; ok {
return v
}
}
return nil
}
// 删除缓存数据
func (this *cache) Del(key string, args ...string) {
var group string
if len(args) > 0 {
group = args[0]
} else {
group = "default"
}
if g, exist := this.data[group]; exist {
if _, ok := g[key]; ok {
delete(this.data[group], key)
}
}
}
var (
lastError error
Cache *cache
queue *queueList
Obj *Database
)
func init() {
Cache = &cache{data: make(map[string]map[string]interface{})}
Cache.Init()
queue = &queueList{}
go queue.Start()
}
// 关闭数据库连接
func (this *Database) Close() {
this.DB.Close()
}
// 获取最后发生的错误字符串
func LastErr() string {
if lastError != nil {
return lastError.Error()
}
return ""
}
// 执行语句
func (this *Database) Exec(query string, args ...interface{}) (sql.Result, error) {
return this.DB.Exec(query, args...)
}
// 查询单条记录
func (this *Database) Query(query string, args ...interface{}) (*sql.Rows, error) {
return this.DB.Query(query, args...)
}
// 查询单条记录
func (this *Database) QueryRow(query string, args ...interface{}) *sql.Row {
return this.DB.QueryRow(query, args...)
}
// Query2 查询实体集合
// obj 为接收数据的实体指针
func (this *Database) Query2(sql string, obj interface{}, args ...interface{}) error {
var tagMap map[string]int
var tp, tps reflect.Type
var n, i int
var err error
var ret reflect.Value
// 检测val参数是否为我们所想要的参数
tp = reflect.TypeOf(obj)
if reflect.Ptr != tp.Kind() {
return errors.New("is not pointer")
}
if reflect.Slice != tp.Elem().Kind() {
return errors.New("is not slice pointer")
}
tp = tp.Elem()
tps = tp.Elem()
if reflect.Struct != tps.Kind() {
return errors.New("is not struct slice pointer")
}
tagMap = make(map[string]int)
n = tps.NumField()
for i = 0; i < n; i++ {
tag := tps.Field(i).Tag.Get("sql")
if len(tag) > 0 {
tagMap[tag] = i + 1
}
}
// 执行查询
ret, err = this.queryAndReflect(sql, tagMap, tp, args...)
if nil != err {
return err
}
// 返回结果
reflect.ValueOf(obj).Elem().Set(ret)
return nil
}
// queryAndReflect 查询并将结果反射成实体集合
func (this *Database) queryAndReflect(sql string,
tagMap map[string]int,
tpSlice reflect.Type, args ...interface{}) (reflect.Value, error) {
var ret reflect.Value
// 执行sql语句
rows, err := this.DB.Query(sql, args...)
if nil != err {
return reflect.Value{}, err
}
defer rows.Close()
// 开始枚举结果
cols, err := rows.Columns()
if nil != err {
return reflect.Value{}, err
}
ret = reflect.MakeSlice(tpSlice, 0, 50)
// 构建接收队列
scan := make([]interface{}, len(cols))
row := make([]interface{}, len(cols))
for r := range row {
scan[r] = &row[r]
}
for rows.Next() {
feild := reflect.New(tpSlice.Elem()).Elem()
// 取得结果
err = rows.Scan(scan...)
// 开始遍历结果
for i := 0; i < len(cols); i++ {
n := tagMap[cols[i]] - 1
if n < 0 {
continue
}
switch feild.Type().Field(n).Type.Kind() {
case reflect.Bool:
if nil != row[i] {
feild.Field(n).SetBool("false" != string(row[i].([]byte)))
} else {
feild.Field(n).SetBool(false)
}
case reflect.String:
if nil != row[i] {
feild.Field(n).SetString(string(row[i].([]byte)))
} else {
feild.Field(n).SetString("")
}
case reflect.Float32:
if nil != row[i] {
//log.Println(row[i].(float32))
switch reflect.TypeOf(row[i]).Kind(){
case reflect.Slice:
v, e := strconv.ParseFloat(string(row[i].([]byte)), 0)
if nil == e {
feild.Field(n).SetFloat(float64(v))
//feild.Field(n).SetFloat(float64(row[i].(float32)))
}
break
case reflect.Float64:
feild.Field(n).SetFloat(float64(row[i].(float32)))
}
} else {
feild.Field(n).SetFloat(0)
}
case reflect.Float64:
if nil != row[i] {
//log.Println(row[i].(float32))
//v, e := strconv.ParseFloat(string(row[i].([]byte)), 0)
//if nil == e {
feild.Field(n).SetFloat(row[i].(float64))
//}
} else {
feild.Field(n).SetFloat(0)
}
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
fallthrough
case reflect.Int:
if nil != row[i] {
byRow, ok := row[i].([]byte)
if ok {
v, e := strconv.ParseInt(string(byRow), 10, 64)
if nil == e {
feild.Field(n).SetInt(v)
}
} else {
v, e := strconv.ParseInt(fmt.Sprint(row[i]), 10, 64)
if nil == e {
feild.Field(n).SetInt(v)
}
}
} else {
feild.Field(n).SetInt(0)
}
}
}
ret = reflect.Append(ret, feild)
}
return ret, nil
}
// 执行UPDATE语句并返回受影响的行数
// 返回0表示没有出错, 但没有被更新的行
// 返回-1表示出错
func (this *Database) Update(query string, args ...interface{}) (int64, error) {
ret, err := this.Exec(query, args...)
if err != nil {
return -1, err
}
aff, err := ret.RowsAffected()
if err != nil {
return -1, err
}
return aff, nil
}
// 执行DELETE语句并返回受影响的行数
// 返回0表示没有出错, 但没有被删除的行
// 返回-1表示出错
func (this *Database) Delete(query string, args ...interface{}) (int64, error) {
return this.Update(query, args...)
}
func GenSql(obj interface{}) (string,error) {
ret := ""
typ := reflect.TypeOf(obj).Kind()
if typ != reflect.Struct{
return (""),errors.New("not a struct")
}
value := obj.(reflect.Value)
num := value.NumField()
for i := 0;i < num;i++{
if i == 0{
ret += "("
}
switch (value.Field(i).Type().Kind()){
case reflect.String:
str := value.Field(i).Interface().(string)
if str[0] != '"'{
ret += "\""
str += "\""
ret += str
}else{
ret += value.Field(i).Interface().(string)
}
case reflect.Int:
ret += fmt.Sprintf("%d",value.Field(i).Interface().(int))
case reflect.Int8:
ret += fmt.Sprintf("%d",value.Field(i).Interface().(int8))
case reflect.Int32:
ret += fmt.Sprintf("%d",value.Field(i).Interface().(int32))
case reflect.Int64:
ret += fmt.Sprintf("%d",value.Field(i).Interface().(int64))
case reflect.Int16:
ret += fmt.Sprintf("%d",value.Field(i).Interface().(int16))
case reflect.Bool:
if value.Field(i).Interface().(bool) {
ret += fmt.Sprintf("true",)
}else {
ret += fmt.Sprintf("false",)
}
case reflect.Float32:
ret += fmt.Sprintf("%x",value.Field(i).Interface().(float32))
case reflect.Float64:
ret += fmt.Sprintf("true",value.Field(i).Interface().(float64))
}
if i == num - 1{
ret += ")"
}else {
ret += ","
}
}
return ret,nil
}
func (this *Database) InsertObejct(tb_name string,obj interface{}) (int64,error) {
var tagMap map[int]string
var tp, tps reflect.Type
var n, i int
// 检测val参数是否为我们所想要的参数
tp = reflect.TypeOf(obj)
if reflect.Ptr != tp.Kind() {
return 0,errors.New("is not pointer")
}
if reflect.Slice != tp.Elem().Kind() {
return 0,errors.New("is not slice pointer")
}
tp = tp.Elem()
tps = tp.Elem()
value := reflect.ValueOf(obj).Elem()
if reflect.Struct != tps.Kind() {
return 0,errors.New("is not struct slice pointer")
}
for z := 0; z < value.Len();z ++ {
tagMap = make(map[int]string)
n = tps.NumField()
var query_struct string
for i = 0; i < n; i++ {
tag := tps.Field(i).Tag.Get("sql")
if len(tag) > 0 {
tagMap[i] = tag
}
if i == 0{
query_struct += "("
}
query_struct += tagMap[i]
if i == n -1{
query_struct += ")"
}else {
query_struct += ","
}
}
vs ,e := GenSql(value.Index(z))
if nil != e{
logs.Error(e.Error())
}
query := "insert into " + tb_name + query_struct + "values " + vs
_, e = this.Insert(query)
if e != nil{
logs.Error(e.Error())
}
}
return 0,nil
}
// 执行INSERT语句并返回最后生成的自增ID
// 返回0表示没有出错, 但没生成自增ID
// 返回-1表示出错
func (this *Database) Insert(query string, args ...interface{}) (int64, error) {
ret, err := this.Exec(query, args...)
if err != nil {
return -1, err
}
last, err := ret.LastInsertId()
if err != nil {
return -1, err
}
return last, nil
}
type OneRow map[string]string
type Results []OneRow
// 判断字段是否存在
func (row OneRow) Exist(field string) bool {
if _, ok := row[field]; ok {
return true
}
return false
}
// 获取指定字段的值
func (row OneRow) Get(field string) string {
if v, ok := row[field]; ok {
return v
}
return ""
}
// 获取指定字段的整数值, 注意, 如果该字段不存在则会返回0
func (row OneRow) GetInt(field string) int {
if v, ok := row[field]; ok {
return Atoi(v)
}
return 0
}
// 获取指定字段的整数值, 注意, 如果该字段不存在则会返回0
func (row OneRow) GetInt64(field string) int64 {
if v, ok := row[field]; ok {
return Atoi64(v)
}
return 0
}
// 设置值
func (row OneRow) Set(key, val string) {
row[key] = val
}
// 查询不定字段的结果集
func (this *Database) Select(query string, args ...interface{}) (Results, error) {
rows, err := this.DB.Query(query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
cols, err := rows.Columns()
if err != nil {
return nil, err
}
colNum := len(cols)
rawValues := make([][]byte, colNum)
scans := make([]interface{}, len(cols)) //query.Scan的参数因为每次查询出来的列是不定长的所以传入长度固定当次查询的长度
// 将每行数据填充到[][]byte里
for i := range rawValues {
scans[i] = &rawValues[i]
}
results := make(Results, 0)
for rows.Next() {
err = rows.Scan(scans...)
if err != nil {
return nil, err
}
row := make(map[string]string)
for k, raw := range rawValues {
key := cols[k]
/*if raw == nil {
row[key] = "\\N"
} else {*/
row[key] = string(raw)
//}
}
results = append(results, row)
}
return results, nil
}
// 查询一行不定字段的结果
func (this *Database) SelectOne(query string, args ...interface{}) (OneRow, error) {
ret, err := this.Select(query, args...)
if err != nil {
return nil, err
}
if len(ret) > 0 {
return ret[0], nil
}
return make(OneRow), nil
}
// 队列入栈
func (this *queueList) Push(item *QueueItem) {
this.lock.Lock()
this.list = append(this.list, item)
this.lock.Unlock()
}
// 队列出栈
func (this *queueList) Pop() chan *QueueItem {
item := make(chan *QueueItem)
go func() {
defer close(item)
for {
switch {
case len(this.list) == 0:
timeout := time.After(time.Second * 2)
select {
case <-this.quit:
this.quited = true
return
case <-timeout:
//log.Println("SQL Queue polling")
}
default:
this.lock.Lock()
i := this.list[0]
this.list = this.list[1:]
this.lock.Unlock()
select {
case item <- i:
return
case <-this.quit:
this.quited = true
return
}
}
}
}()
return item
}
// 执行开始执行
func (this *queueList) Start() {
for {
if this.quited {
return
}
c := this.Pop()
item := <-c
item.DB.Exec(item.Query, item.Params...)
}
}
// 停止队列
func (this *queueList) Stop() {
this.quit <- true
}
// 向Sql队列中插入一条执行语句
func (this *Database) Queue(query string, args ...interface{}) {
item := &QueueItem{
DB: this,
Query: query,
Params: args,
}
queue.Push(item)
}

76
db/mssql.go Normal file
View File

@ -0,0 +1,76 @@
package db
import (
"database/sql"
_ "github.com/denisenkom/go-mssqldb"
)
// ProcExec 执行存储过程, 返回受影响的行数
func (this *Database) ExecProc(procname string, params ...interface{}) (int64, error) {
result, err := this.Exec("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...)
if err != nil {
return 0, err
}
affected, err := result.RowsAffected()
if err != nil {
return 0, err
}
lastinsertid, err := result.LastInsertId()
if err != nil {
return affected, nil
}
return lastinsertid, nil
}
// GetExecProcErr 执行存储过程, 返回是否在执行过程中出现错误
func (this *Database) GetExecProcErr(procname string, params ...interface{}) error {
_, err := this.ExecProc(procname, params...)
if err != nil {
return err
}
return nil
}
// ProcQuery 通过存储过程查询记录
func (this *Database) ProcQuery(procname string, params ...interface{}) (rows *sql.Rows, err error) {
rows, err = this.Query("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...)
return
}
// ProcQueryRow 通过存储过程查询单条记录
func (this *Database) ProcQueryRow(procname string, params ...interface{}) *sql.Row {
return this.QueryRow("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...)
}
// ProcStatus 调用存储过程并获取最终的执行状态码和提示信息
func (this *Database) ProcStatus(procname string, params ...interface{}) (int, string) {
var status int
var msg string
err := this.QueryRow("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...).Scan(&status, &msg)
if err != nil {
return -99, err.Error()
}
return status, msg
}
// ProcSelect 通过存储过程查询结果集
func (this *Database) ProcSelect(procname string, params ...interface{}) (Results, error) {
return this.Select("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...)
}
// ProcSelectOne 通过存储查询一行不定字段的结果
func (this *Database) ProcSelectOne(procname string, params ...interface{}) (OneRow, error) {
return this.SelectOne("EXEC " + procname + " " + this.GetProcPlaceholder(len(params)), params...)
}
// GetProcPlaceholder 按照指定数量生成调用存储过程时所用的参数占位符
func (this *Database) GetProcPlaceholder(count int) (placeholder string) {
placeholder = ""
for i := 0; i < count; i++ {
if i > 0 {
placeholder += ","
}
placeholder += "?"
}
return
}

33
db/sqlManager.go Normal file
View File

@ -0,0 +1,33 @@
package db
import (
"database/sql"
"user/config"
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
)
var gDb Database
func Init() {
mysqlconf := config.GetMysqlConfig()
log.Println(mysqlconf)
cnn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",mysqlconf.UserName,mysqlconf.Password,
mysqlconf.Addr,mysqlconf.Db)
_db,err := sql.Open("mysql",cnn)
if err != nil{
fmt.Println("connect sql server ",err.Error())
}
e := _db.Ping()
if nil != e{
fmt.Println(e.Error())
}
gDb = Database{Type:string(""),DB:_db}
}
func GetMysqlClient() *Database {
return &gDb
}

542
db/sql_builder.go Normal file
View File

@ -0,0 +1,542 @@
package db
import (
"database/sql"
"errors"
"strconv"
"strings"
"log"
"fmt"
"reflect"
"math/big"
"git.jiaxianghudong.com/go/utils"
)
const (
_ = iota
TYPE_INSERT
TYPE_DELETE
TYPE_UPDATE
TYPE_SELECT
TYPE_INSERTUPDATE
)
var (
WrapSymbol = "`"
DBType = "mysql"
)
// SQL语句构造结构
type SB struct {
db *Database
t int
field, table, where, group, order, limit string
values SBValues
values2 SBValues
ignore bool
fullsql bool
debug bool
unsafe bool //是否进行安全检查, 专门针对无限定的UPDATE和DELETE进行二次验证
args []interface{}
}
// Exec返回结果
type SBResult struct {
Success bool //语句是否执行成功
Code int //错误代码
Msg string //错误提示信息
LastID int64 //最后产生的ID
Affected int64 //受影响的行数
Sql string //最后执行的SQL
}
// 值对象
type SBValues map[string]interface{}
// 增量值
type IncVal struct {
Val int64
BaseField string // 为空表示对当前字段累加
}
// 向值对象中加入值
func (v SBValues) Add(key string, val interface{}) {
v[key] = val
}
// 删除值对象中的某个值
func (v SBValues) Del(key string) {
delete(v, key)
}
// 判断指定键是否存在
func (v SBValues) IsExist(key string) bool {
if _, exist := v[key]; exist {
return true
}
return false
}
// 获取键的整形值
func (v SBValues) Get(key string) interface{} {
if val, exist := v[key]; exist {
return val
}
return nil
}
// 获取键的字符串值
func (v SBValues) GetString(key string) string {
if val, exist := v[key]; exist {
if trueVal, ok := val.(string); ok {
return trueVal
}
}
return ""
}
// 获取键的整形值
func (v SBValues) GetInt(key string) int {
if val, exist := v[key]; exist {
if trueVal, ok := val.(int); ok {
return trueVal
}
}
return 0
}
// 获取键的无符号整形值
func (v SBValues) GetUint(key string) uint {
if val, exist := v[key]; exist {
if trueVal, ok := val.(uint); ok {
return trueVal
}
}
return 0
}
// 获取键的64位整形值
func (v SBValues) GetInt64(key string) int64 {
if val, exist := v[key]; exist {
if trueVal, ok := val.(int64); ok {
return trueVal
}
}
return 0
}
// 返回绑定完参数的完整的SQL语句
func FullSql(str string, args ...interface{}) (string, error) {
if !strings.Contains(str, "?") {
return str, nil
}
sons := strings.Split(str, "?")
var ret string
var argIndex int
var maxArgIndex = len(args)
for _, son := range sons {
ret += son
if argIndex < maxArgIndex {
switch v := args[argIndex].(type) {
case int:
ret += strconv.Itoa(v)
case int8:
ret += strconv.Itoa(int(v))
case int16:
ret += strconv.Itoa(int(v))
case int32:
ret += utils.I64toA(int64(v))
case int64:
ret += utils.I64toA(v)
case uint:
ret += utils.UitoA(v)
case uint8:
ret += utils.UitoA(uint(v))
case uint16:
ret += utils.UitoA(uint(v))
case uint32:
ret += utils.Ui32toA(v)
case uint64:
ret += utils.Ui64toA(v)
case float32:
ret += utils.F32toA(v)
case float64:
ret += utils.F64toA(v)
case *big.Int:
ret += v.String()
case bool:
if v {
ret += "true"
} else {
ret += "false"
}
case string:
ret += "'" + strings.Replace(strings.Replace(v, "'", "", -1), `\`, `\\`, -1) + "'"
case nil:
ret += "NULL"
default:
return "", errors.New(fmt.Sprintf("invalid sql argument type: %v => %v (sql: %s)", reflect.TypeOf(v).String(), v, str))
}
argIndex++
}
}
return ret, nil
}
// 构建SQL语句
// param: returnFullSql 是否返回完整的sql语句(即:绑定参数之后的语句)
func (q *SB) ToSql(returnFullSql ...bool) (str string, err error) {
q.args = make([]interface{}, 0)
switch q.t {
case TYPE_INSERT:
if q.table == "" {
err = errors.New("table cannot be empty.")
return
}
if len(q.values) == 0 {
err = errors.New("values cannot be empty.")
return
}
if q.ignore {
str = "INSERT IGNORE INTO " + q.table
} else {
str = "INSERT INTO " + q.table
}
var fields, placeholder string
for k, v := range q.values {
fields += "," + WrapSymbol + k + WrapSymbol
placeholder += ",?"
q.args = append(q.args, v)
}
str += " (" + utils.Substr(fields, 1) + ") VALUES (" + utils.Substr(placeholder, 1) + ")"
case TYPE_DELETE:
if q.table != "" {
if q.where == "" && !q.unsafe {
err = errors.New("deleting all data is not safe.")
return
}
str = "DELETE " + q.table
if q.table != "" {
str += " FROM " + q.table
}
if q.where != "" {
str += " WHERE " + q.where
}
}
case TYPE_UPDATE:
if q.table != "" {
if q.where == "" && !q.unsafe {
err = errors.New("updating all data is not safe.")
return
}
str = "UPDATE " + q.table
str += " SET " + utils.Substr(q.buildUpdateParams(q.values), 1)
if q.where != "" {
str += " WHERE " + q.where
}
}
case TYPE_INSERTUPDATE:
if q.table != "" {
str = "INSERT INTO " + q.table
var fields, placeholder string
for k, v := range q.values {
fields += "," + WrapSymbol + k + WrapSymbol
placeholder += ",?"
q.args = append(q.args, v)
}
str += " (" + utils.Substr(fields, 1) + ") VALUES (" + utils.Substr(placeholder, 1) + ") ON DUPLICATE KEY UPDATE "
placeholder = q.buildUpdateParams(q.values2)
str += utils.Substr(placeholder, 1)
}
case TYPE_SELECT:
str = "SELECT " + q.field
if q.table != "" {
str += " FROM " + q.table
}
if q.where != "" {
str += " WHERE " + q.where
}
if q.group != "" {
str += " GROUP BY " + q.group
}
if q.order != "" {
str += " ORDER BY " + q.order
}
if q.limit != "" && (q.db.Type == "" || q.db.Type == "mysql") {
str += " LIMIT " + q.limit
}
}
if len(returnFullSql) == 1 && returnFullSql[0] {
str, err = FullSql(str, q.args...)
}
return
}
// 构造Update更新参数
func (q *SB) buildUpdateParams(vals SBValues) string {
var placeholder string
for k, v := range vals {
if iv, ok := v.(IncVal); ok {
placeholder += "," + WrapSymbol + k + WrapSymbol + "=" + utils.Ternary(iv.BaseField == "", k, iv.BaseField).(string)
if iv.Val >= 0 {
placeholder += "+" + utils.I64toA(iv.Val)
} else {
placeholder += utils.I64toA(iv.Val)
}
} else {
placeholder += "," + WrapSymbol + k + WrapSymbol + "=?"
q.args = append(q.args, v)
}
}
return placeholder
}
// 设置数据库对象
func (q *SB) DB(db *Database) *SB {
q.db = db
return q
}
// 设置FROM字句
func (q *SB) From(str string) *SB {
q.table = str
return q
}
// 设置表名
func (q *SB) Table(str string) *SB {
return q.From(str)
}
// 设置WHERE字句
func (q *SB) Where(str string) *SB {
q.where = str
return q
}
// 设置GROUP字句
func (q *SB) Group(str string) *SB {
q.group = str
return q
}
// 设置GROUP字句
func (q *SB) Order(str string) *SB {
q.order = str
return q
}
// 设置LIMIT字句
func (q *SB) Limit(count int, offset ...int) *SB {
if len(offset) > 0 {
q.limit = utils.Itoa(offset[0]) + "," + utils.Itoa(count)
} else {
q.limit = "0," + utils.Itoa(count)
}
return q
}
// 设置安全检查开关
func (q *SB) Unsafe(unsefe ...bool) *SB {
if len(unsefe) == 1 && !unsefe[0] {
q.unsafe = false
} else {
q.unsafe = true
}
return q
}
// 是否Debug
func (q *SB) Debug(debug ...bool) *SB {
if len(debug) == 1 && !debug[0] {
q.debug = false
} else {
q.debug = true
}
return q
}
// 设置值
func (q *SB) Value(m SBValues) *SB {
q.values = m
return q
}
// 设置值2
func (q *SB) Value2(m SBValues) *SB {
q.values2 = m
return q
}
// 添加值
func (q *SB) AddValue(key string, val interface{}) *SB {
q.values.Add(key, val)
return q
}
// 添加值2
func (q *SB) AddValue2(key string, val interface{}) *SB {
q.values2.Add(key, val)
return q
}
// 获取一个值对象
func NewValues() SBValues {
return SBValues{}
}
// 构建INSERT语句
func Insert(ignore ...bool) *SB {
var i bool
if len(ignore) == 1 && ignore[0] {
i = true
}
return &SB{t: TYPE_INSERT, db: Obj, ignore: i, values: SBValues{}, args: make([]interface{}, 0)}
}
// 构建DELETE语句
func Delete() *SB {
return &SB{t: TYPE_DELETE, db: Obj}
}
// 构建UPDATE语句
func Update() *SB {
return &SB{t: TYPE_UPDATE, db: Obj, values: SBValues{}, args: make([]interface{}, 0)}
}
// 构建InsertUpdate语句, 仅针对MySQL有效, 内部使用ON DUPLICATE KEY UPDATE方式实现
func InsertUpdate() *SB {
return &SB{t: TYPE_INSERTUPDATE, db: Obj, values: SBValues{}, values2: SBValues{}, args: make([]interface{}, 0)}
}
// 构建SELECT语句
func Select(str ...string) *SB {
fields := "*"
if len(str) == 1 {
fields = str[0]
}
return &SB{t: TYPE_SELECT, db: Obj, field: fields}
}
// 获取构造SQL后的参数
func (q *SB) GetArgs() []interface{} {
return q.args
}
//
func (q *SB) FullSql(yes ...bool) *SB {
if len(yes) == 1 {
q.fullsql = yes[0]
} else {
q.fullsql = true
}
return q
}
// 执行INSERT、DELETE、UPDATE语句
func (q *SB) Exec(args ...interface{}) *SBResult {
var err error
sbRet := &SBResult{}
sbRet.Sql, err = q.ToSql()
if err != nil {
sbRet.Msg = err.Error()
} else {
if q.debug {
log.Println("\n\tSQL prepare statement:\n\t", sbRet.Sql, "\n\tMap args:\n\t", q.args, "\n\tParams:\n\t", args)
}
var ret sql.Result
var err error
if q.fullsql {
var sqlStr string
sqlStr, err = FullSql(sbRet.Sql, append(q.args, args...)...)
if err == nil {
ret, err = q.db.Exec(sqlStr)
}
} else {
ret, err = q.db.Exec(sbRet.Sql, append(q.args, args...)...)
}
if err != nil {
sbRet.Msg = err.Error()
} else {
sbRet.Success = true
switch q.t {
case TYPE_INSERT:
if DBType == "mysql" {
last, err := ret.LastInsertId()
if (err == nil) {
sbRet.LastID = last;
}
}
case TYPE_DELETE:
fallthrough
case TYPE_UPDATE:
fallthrough
case TYPE_INSERTUPDATE:
aff, err := ret.RowsAffected()
if (err == nil) {
sbRet.Affected = aff
}
}
}
}
return sbRet
}
// 查询记录集
func (q *SB) Query(args ...interface{}) (Results, error) {
s, e := q.ToSql()
if e != nil {
return nil, e
}
if q.debug {
log.Println("\n\tSQL prepare statement:\n\t", s, "\n\tParams:\n\t", args)
}
return q.db.Select(s, args...)
}
// 查询单行数据
func (q *SB) QueryOne(args ...interface{}) (OneRow, error) {
q.Limit(1, 0)
s, e := q.ToSql()
if e != nil {
return nil, e
}
if q.debug {
log.Println("\n\tSQL prepare statement:\n\t", s, "\n\tParams:\n\t", args)
}
return q.db.SelectOne(s, args...)
}
// 查询记录集
func (q *SB) QueryAllRow(args ...interface{}) (*sql.Rows, error) {
s, e := q.ToSql()
if e != nil {
return nil, e
}
if q.debug {
log.Println("\n\tSQL prepare statement:\n\t", s, "\n\tParams:\n\t", args)
}
return q.db.Query(s, args...)
}
// 查询单行数据
func (q *SB) QueryRow(args ...interface{}) *sql.Row {
s, e := q.ToSql()
if e != nil {
return nil
}
if q.debug {
log.Println("\n\tSQL prepare statement:\n\t", s, "\n\tParams:\n\t", args)
}
return q.db.QueryRow(s, args...)
}

66
db/utils.go Normal file
View File

@ -0,0 +1,66 @@
package db
import (
"strings"
"strconv"
"database/sql"
)
// 根据传入的字段列表生成相符数量的占位符
func GetPlaceholderByFields(fileds string) string {
fileds = strings.Replace(fileds, " ", "", -1)
fileds = strings.Trim(fileds, ",")
count := len(strings.Split(fileds, ","))
ret := make([]string, count)
for i := 0; i < count; i++ {
ret[i] = "?"
}
return strings.Join(ret, ",")
}
// Atoi 转换成整型
func Atoi(s string, d ...int) int {
i, err := strconv.Atoi(s)
if err != nil {
if len(d) > 0 {
return d[0]
} else {
return 0
}
}
return i
}
// Atoi64 转换成整型int64
func Atoi64(s string, d ...int64) int64 {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
if len(d) > 0 {
return d[0]
} else {
return 0
}
}
return i
}
// 返回一个带有Null值的数据库字符串
func NewNullString(s string) sql.NullString {
if len(s) == 0 {
return sql.NullString{}
}
return sql.NullString{
String: s,
Valid: true,
}
}
// 返回一个带有Null值的数据库整形
func NewNullInt64(s int64, isNull bool) sql.NullInt64 {
return sql.NullInt64{
Int64: s,
Valid: !isNull,
}
}

148
logs/logs.go Normal file
View File

@ -0,0 +1,148 @@
package logs
import (
"fmt"
"os"
"runtime"
"time"
)
const (
LOG_ERROR = iota
LOG_WARING
LOG_INFO
LOG_DEBUG
)
var log *mylog
/*
*
*/
func init() {
log = newMylog()
}
func Init(dir string, file string, level int, savefile bool) {
log.setDir(dir)
log.setFile(file)
log.setLevel(level)
log.setSavefile(savefile)
}
func Error(err ...interface{}) {
log.write(LOG_ERROR, fmt.Sprint(err...))
}
func Waring(war ...interface{}) {
log.write(LOG_WARING, fmt.Sprint(war...))
}
func SetLevel(level int) {
log.setLevel(level)
}
func Info(info ...interface{}) {
log.write(LOG_INFO, fmt.Sprint(info...))
}
func Debug(deb ...interface{}) {
log.write(LOG_DEBUG, fmt.Sprint(deb...))
}
/*
*
*/
type mylog struct {
log chan string // 日志chan
dir string // 日志存放目录
file string // 日志文件名
savefile bool // 是否保存到文件
level int // 日志级别
}
func newMylog() *mylog {
log := &mylog{}
log.log = make(chan string, 100)
log.dir = "/opt/logs"
log.file = "out"
log.savefile = false
go log.run()
return log
}
func (l *mylog) setDir(dir string) {
l.dir = dir
}
func (l *mylog) setFile(file string) {
l.file = file
}
func (l *mylog) setSavefile(b bool) {
l.savefile = b
}
func (l *mylog) setLevel(level int) {
l.level = level
}
func (l *mylog) getLevelString(level int) string {
switch level {
case LOG_ERROR:
return "ERROR"
case LOG_WARING:
return "WARING"
case LOG_INFO:
return "INFO"
case LOG_DEBUG:
return "DEBUG"
}
return "unknown"
}
func (l *mylog) write(level int, str string) {
// 判断级别
if level > l.level {
return
}
// 输出日志
pc, _, line, _ := runtime.Caller(2)
p := runtime.FuncForPC(pc)
t := time.Now()
str = fmt.Sprintf("[%04d-%02d-%02d %02d:%02d:%02d] [%s] %s(%d): %s\n",
t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(),
l.getLevelString(level), p.Name(), line, str)
// 输出到控制台
if false == l.savefile {
fmt.Print(str)
return
}
// 输出到文件
l.log <- str
}
func (l *mylog) run() {
for {
str := <-l.log
// 判断文件夹是否存在
_, err := os.Stat(l.dir)
if nil != err {
os.MkdirAll(l.dir, os.ModePerm)
}
// 获取时间
t := time.Now()
path := fmt.Sprintf("%s/%s-%04d-%02d-%02d.log", l.dir, l.file,
t.Year(), t.Month(), t.Day())
fp, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm)
if nil == err {
fp.WriteString(str)
fp.Close()
}
}
}

46
main.go Normal file
View File

@ -0,0 +1,46 @@
package main
import (
"github.com/gin-gonic/gin"
"log"
"strconv"
"user/controller"
"user/config"
"user/db"
"user/logs"
)
func InitMysql() {
c := config.GetMysqlConfig()
if c == nil{
logs.Error("cannnot connect mysql server")
}else {
db.Init()
}
}
func main() {
e := config.Init("user.yaml")
if nil != e{
log.Println(e.Error())
}
db.Init()
r := gin.Default()
{
/** 添加或修改用户 **/
r.POST("/api/user", controller.SetUser)
/** 删除用户 **/
r.DELETE("/api/user", controller.DelUser)
/** 获取单独用户详情信息 methods(id) **/
r.GET("/api/user", controller.GetUser)
/** 获取所有用户 **/
r.GET("/api/users", controller.GetUsers)
/** 用户登录 **/
r.POST("/api/login", controller.Login)
/** 用户注册 **/
r.POST("/api/register", controller.Register)
/** 用户退出登陆 **/
r.GET("/api/logout", controller.Logout)
}
r.Run(":" + strconv.Itoa(config.GetPort()))
}

13
model/model.go Normal file
View File

@ -0,0 +1,13 @@
package model
type Users struct {
ID int64 `sql:"id" json:"id"`
UserName string `sql:"user_name" json:"UserName"`
UserPwd string `sql:"user_pwd" json:"UserPwd"`
CreatedDate string `sql:"created_date" json:"CreatedDate"`
UpdatedDate string `sql:"updated_date" json:"UpdatedDate"`
DisplayName string `sql:"display_name" json:"DisplayName"`
EmailAddress string `sql:"email_address" json:"EmailAddress"`
Tel string `sql:"tel" json:"tel"`
Avatar string `sql:"avatar" json:"Avatar"`
}

426
redis/redis.go Normal file
View File

@ -0,0 +1,426 @@
package redis
import (
"errors"
"fmt"
// "errors"
"strconv"
"time"
"gopkg.in/redis.v3"
)
const maxConn = 100
var redisChan chan *redis.Client
var option *redis.Options
func Init(addr string, pwd string, db int64) error {
option = &redis.Options{
Addr: addr,
Password: pwd,
DB: db,
}
redisChan = make(chan *redis.Client, maxConn)
for i := 0; i < maxConn; i++ {
client, err := creatRedisClient(option)
if err != nil {
return err
}
redisChan <- client
}
return nil
}
// 创建redis对象
func creatRedisClient(option *redis.Options) (*redis.Client, error) {
client := redis.NewClient(option)
// 检测client有效性
if nil != client {
_, err := client.Ping().Result()
if nil != err {
client.Close()
return nil, errors.New(fmt.Sprintf("fail to ping redis-svr,addr :%s , pwd :%s ,DB :%d", option.Addr, option.Password, option.DB))
}
} else {
return nil, errors.New(fmt.Sprintf("fail to connect redis-svr,,addr :%s , pwd :%s ,DB :%d", option.Addr, option.Password, option.DB))
}
return client, nil
}
// 获取redis
func getRedis() (*redis.Client, error) {
var client *redis.Client
select {
case <-time.After(time.Second * 10):
case client = <-redisChan:
}
// 检测client有效性
if nil != client {
_, err := client.Ping().Result()
if nil != err {
client.Close()
// 尝试3次重连
for i := 0; i < 3; i++ {
client, err = creatRedisClient(option)
if client != nil {
return client, err
}
}
return nil, err
}
}
return client, nil
}
// 将redis链接放回连接池
func relaseRedis(client *redis.Client) {
select {
case <-time.After(time.Second * 10):
client.Close()
case redisChan <- client:
}
}
func Get(key string) (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.Get(key).Result()
if nil != err {
if err.Error() == "redis: nil" {
return "", nil
}
return "", err
}
return val, nil
}
// redis查询
func Keys(key string) ([]string, error) {
client, err := getRedis()
if err != nil {
return nil, err
}
if client == nil {
return nil, errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.Keys(key).Result()
if nil != err {
var nullResult = []string{""}
return nullResult, err
}
return val, nil
}
func Set(key string, val string, expire ...time.Duration) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
var t time.Duration = 0
if len(expire) == 1 {
t = expire[0]
}
_, err = client.Set(key, val, t).Result()
return err
}
func HSet(key string, filed, val string) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.HSet(key, filed, val).Result()
return err
}
func SIsMember(key string, val int32) (bool, error) {
client, err := getRedis()
if err != nil {
return false, err
}
if client == nil {
return false, errors.New("failed to get rds client")
}
defer relaseRedis(client)
isExist, err := client.SIsMember(key, val).Result()
return isExist, err
}
func SAdd(key string, members ...string) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.SAdd(key, members...).Result()
return err
}
func SRem(key string, members ...string) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.SRem(key, members...).Result()
return err
}
func SMembers(key string) ([]string, error) {
client, err := getRedis()
if err != nil {
return nil, err
}
if client == nil {
return nil, errors.New("failed to get rds client")
}
defer relaseRedis(client)
members, err := client.SMembers(key).Result()
return members, err
}
func HIncrBy(key, filed string, val int64) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.HIncrBy(key, filed, val).Result()
return err
}
func LPush(key string, val ...string) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.LPush(key, val...).Result()
return err
}
func BRPopLPush(source string, dest string, time time.Duration) (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.BRPopLPush(source, dest, time).Result()
return val, err
}
func RPop(key string) (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.RPop(key).Result()
return val, err
}
func LLen(key string) (int64, error) {
client, err := getRedis()
if err != nil {
return 0, err
}
if client == nil {
return 0, errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.LLen(key).Result()
return val, err
}
func LTrim(key string, start, stop int64) (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.LTrim(key, start, stop).Result()
return val, err
}
func LRange(key string, start, stop int64) ([]string, error) {
client, err := getRedis()
if err != nil {
return nil, err
}
if client == nil {
return nil, errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.LRange(key, start, stop).Result()
if nil != err {
return nil, err
}
return val, nil
}
func UpdateExpire(key string, expire time.Duration) error {
client, err := getRedis()
if err != nil {
return err
}
if client == nil {
return errors.New("failed to get rds client")
}
defer relaseRedis(client)
_, err = client.Expire(key, expire).Result()
return err
}
func HGet(key string, hash string) (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.HGet(key, hash).Result()
if nil != err {
return "", err
}
return val, nil
}
func HGetInt64(key string, hash string) (int64, error) {
client, err := getRedis()
if err != nil {
return 0, err
}
if client == nil {
return 0, errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.HGet(key, hash).Int64()
if nil != err {
return 0, err
}
return val, nil
}
func SCard(key string) (int64, error) {
client, err := getRedis()
if err != nil {
return 0, err
}
if client == nil {
return 0, errors.New("failed to get rds client")
}
defer relaseRedis(client)
val, err := client.SCard(key).Result()
if nil != err {
return 0, err
}
return val, nil
}
// 获取时间
func Time() (int64, error) {
client, err := getRedis()
if err != nil {
return 0, err
}
if client == nil {
return 0, errors.New("failed to get rds client")
}
defer relaseRedis(client)
// 读取redis时间
r := client.Time()
if nil == r {
return 0, errors.New("read redis error")
}
if nil != r.Err() {
return 0, r.Err()
}
return strconv.ParseInt(r.Val()[0], 10, 0)
}
// 删除指定key的redis记录
func Del(key string) (int64, error) {
client, err := getRedis()
if err != nil {
return 0, err
}
if client == nil {
return 0, errors.New("failed to get rds client")
}
defer relaseRedis(client)
var iResult int64
cmdResult := client.Del(key)
if nil == cmdResult.Err() {
iResult, _ = cmdResult.Result()
} else {
iResult = 0
}
return iResult, nil
}
// 清空rendis_db
func TruncateDB() (string, error) {
client, err := getRedis()
if err != nil {
return "", err
}
if client == nil {
return "", errors.New("failed to get rds client")
}
defer relaseRedis(client)
cmdResult := client.FlushDb()
if cmdResult.Err() != nil {
return "", cmdResult.Err()
}
return cmdResult.Result()
}

19
user.yaml Normal file
View File

@ -0,0 +1,19 @@
listen_api: 4596
runmode: debug
max_conn: 1500
logs:
dir: "/var/log/user"
file: "user.log"
level: 1
savefile: true
redis:
addr: 118.24.238.198
password: 6379
db: 1
mysql:
addr: 118.24.238.198
user: server
password: 123
db: background
max_open: 100
MaxIdle: 99