Jelajahi Sumber

添加图片上传下载删除功能

huangyh 6 tahun lalu
induk
melakukan
b06da17e39

+ 165 - 0
controllers/SysAttachmentController.go

@@ -0,0 +1,165 @@
+package controllers
+
+import (
+	"bytes"
+	"fmt"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/logs"
+	"io"
+	"mime"
+	"strconv"
+	"strings"
+
+	sysmodel "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
+	"log"
+	"path"
+	"time"
+)
+
+// _Upload
+// @Title _Upload
+// @Description 上传文件
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+func SysAttachment_Upload(c *SysAttachmentController) {
+
+	// 单文件
+	file, _ := c.Ctx.FormFile("file")
+	f, _ := file.Open()
+	log.Println(file.Filename)
+
+	download, hash, length, err := utils.PostFile(f)
+
+	if err != nil {
+		logs.Error("PostFile err: ", err.Error())
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	attach := &sysmodel.SysAttachment{}
+	attach.Id = utils.NewUUID()
+	attach.Name = file.Filename
+	attach.Size = length
+	attach.Url = download
+	attach.CreateTime = time.Now()
+	attach.Ext = path.Ext(attach.Name)
+	attach.Hash = hash
+
+	//插入数据库
+	_, err = c.Db.Insert(attach)
+	if err != nil {
+		logs.Error("Insert Attachment err: ", err.Error())
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	ret := __none_func_sys_attachment__()
+	if ret {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", attach.Id})
+	} else {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, "", nil})
+	}
+}
+
+// _Download
+// @Title _Download
+// @Description 下载文件
+// @Param	id      false  "文件ID"
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+func SysAttachment_Download(c *SysAttachmentController) {
+	gt := c.Ctx.GetString("get_thumb")
+	attrId := c.Ctx.Param("attrId")
+	fmt.Println("--------", attrId)
+	var attach sysmodel.SysAttachment
+	_, err := c.Db.Id(attrId).Get(&attach)
+	if err != nil {
+		logs.Error("获取附件出错了:", err)
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	logs.Debug("开始下载附件:", attach.Name, attach.Size)
+
+	durl := attach.Url
+	if gt != "" {
+		durl += "?getthumb=" + gt
+	}
+
+	resultBody, err := utils.GetFile(durl)
+	if err != nil {
+		logs.Error("下载附件出错了:", err)
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+	defer resultBody.Close()
+
+	bbuf := bytes.NewBuffer([]byte{})
+
+	c.Ctx.Header("Content-Disposition", "attachment;filename=\""+utils.FormatForBrowse(c.Ctx.Request.UserAgent(), attach.Name)+"\"")
+	c.Ctx.Header("Content-Type", strings.Replace(mime.TypeByExtension(attach.Ext), "charset=utf-8", "", -1))
+
+	buff := make([]byte, 1024)
+	var ssize int64 = 0
+
+	for {
+		n, err := io.ReadFull(resultBody, buff)
+		if err != nil && err != io.ErrUnexpectedEOF && err != io.EOF {
+			logs.Error("下载附件出错了:", err)
+			c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+			return
+		}
+		if n <= 0 {
+			break
+		}
+		bbuf.Write(buff[:n])
+		ssize += int64(n)
+	}
+
+	c.Ctx.Header("Content-Length", strconv.FormatInt(ssize, 10))
+	_, err = c.Ctx.Writer.Write(bbuf.Bytes())
+
+	if err != nil {
+		logs.Error("输出流断开:", attach.Name, attach.Size)
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	logs.Debug("下载附件成功:", attach.Name, attach.Size)
+
+	ret := __none_func_sys_attachment__(attrId)
+
+	if ret {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
+	} else {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, "", nil})
+	}
+}
+
+// _Delete
+// @Title _Delete
+// @Description 删除文件
+// @Param	id      false  "文件ID"
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+func SysAttachment_Delete(c *SysAttachmentController) {
+	attrId := c.Ctx.Param("attrId")
+	var attach sysmodel.SysAttachment
+	_, err := c.Db.ID(attrId).Delete(&attach)
+
+	if err != nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	ret := __none_func_sys_attachment__(attrId)
+	if ret {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
+	} else {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, "", nil})
+	}
+}
+
+func __none_func_sys_attachment__(params ...interface{}) bool {
+	return true
+}

+ 58 - 0
controllers/SysAttachmentController_gen.go

@@ -0,0 +1,58 @@
+
+package controllers
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/xormplus/xorm"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/engine"
+)
+
+// SysAttachmentController operations for SysAttachment
+type SysAttachmentController struct {
+	Ctx *gin.Context
+	Db *xorm.Engine
+	engine *engine.ApiEngine
+}
+
+func NewSysAttachmentController(c *gin.Context, e *engine.ApiEngine) *SysAttachmentController {
+	controller := &SysAttachmentController{c,e.OrmEngine,e}
+	return controller
+}
+
+
+
+// Upload
+// @Title Upload
+// @Description 上传文件         
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+// @router /upload  [post]
+func (c *SysAttachmentController) Upload() {
+	//
+	SysAttachment_Upload(c)
+}
+
+// Download
+// @Title Download
+// @Description 下载文件         
+// @Param	id    string  false  "文件ID"  
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+// @router /download  [get]
+func (c *SysAttachmentController) Download() {
+	//
+	SysAttachment_Download(c)
+}
+
+// Delete
+// @Title Delete
+// @Description 删除文件         
+// @Param	id    string  false  "文件ID"  
+// @Success 200 {object} models.Account
+// @Failure 403 :id is empty
+// @router /delete  [get]
+func (c *SysAttachmentController) Delete() {
+	//
+	SysAttachment_Delete(c)
+}
+

+ 11 - 0
models/Sql_SysAttachment_gen.go

@@ -0,0 +1,11 @@
+package models
+
+var Insert_sys_attachment = "insert into sys_attachment(`id`,`name`,`size`,`ext`,`hash`,`url`,`create_by`,`create_time`,`del_flag`) values (?id,?name,?size,?ext,?hash,?url,?create_by,?create_time,?del_flag)"
+
+var Update_sys_attachment = "update sys_attachment set `name` = ?name,`size` = ?size,`ext` = ?ext,`hash` = ?hash,`url` = ?url,`create_by` = ?create_by,`create_time` = ?create_time,`del_flag` = ?del_flag where id = ?id"
+
+var Deleteone_sys_attachment = "delete from sys_attachmentwhere id =?id"
+
+var Selectone_sys_attachment = "select `id`,`name`,`size`,`ext`,`hash`,`url`,`create_by`,`create_time`,`del_flag` from sys_attachment where id = ?"
+
+var Selectall_sys_attachment = "select `id`,`name`,`size`,`ext`,`hash`,`url`,`create_by`,`create_time`,`del_flag` from sys_attachment"

+ 21 - 0
models/StorageResult_gen.go

@@ -0,0 +1,21 @@
+package models
+
+import ()
+
+type StorageResult struct {
+
+	//result
+	Result int32 `json:"result"`
+	//ip
+	Ip string `json:"ip"`
+	//port
+	Port int32 `json:"port"`
+	//id
+	Id int32 `json:"id"`
+	//hash
+	Hash string `json:"hash"`
+	//len
+	Len int32 `json:"len"`
+	//error
+	Error string `json:"error"`
+}

+ 31 - 0
models/SysAttachment_gen.go

@@ -0,0 +1,31 @@
+
+package models
+import (
+"time"
+)
+
+type SysAttachment struct {
+	//主键
+	Id   string    `xorm:"'id' varchar(36) pk notnull "json:"id"`
+	//名称
+	Name   string    `xorm:"'name' varchar(36) notnull "json:"name"`
+	//大小
+	Size   int32    `xorm:"'size' notnull "json:"size"`
+	//ext
+	Ext   string    `xorm:"'ext' varchar(36) notnull "json:"ext"`
+	//哈希值
+	Hash   string    `xorm:"'hash' notnull "json:"hash"`
+	//链接地址
+	Url   string    `xorm:"'url' varchar(200) notnull "json:"url"`
+	//创建人
+	CreateBy   string    `xorm:"'create_by' varchar(36) notnull "json:"create_by"`
+	//创建时间
+	CreateTime   time.Time    `xorm:"'create_time' notnull "json:"create_time"`
+	//是否删除 0:删除   1:正常
+	DelFlag   int32    `xorm:"'del_flag' notnull "json:"del_flag"`
+
+}
+
+func (t *SysAttachment) TableName() string {
+	return "sys_attachment"
+}

+ 27 - 4
routers/router_gen.go

@@ -15,6 +15,18 @@ func init() {
 	utils.GlobalTokenStore = utils.NewTokenStore()
 }
 
+func sys_attachmentController_upload(c *gin.Context) {
+	controllers.NewSysAttachmentController(c, g_engine).Upload()
+}
+
+func sys_attachmentController_download(c *gin.Context) {
+	controllers.NewSysAttachmentController(c, g_engine).Download()
+}
+
+func sys_attachmentController_delete(c *gin.Context) {
+	controllers.NewSysAttachmentController(c, g_engine).Delete()
+}
+
 func systemController_login(c *gin.Context) {
 	controllers.NewSystemController(c, g_engine).Login()
 }
@@ -117,11 +129,14 @@ func SyncDb(e *engine.ApiEngine) {
 
 	e.OrmEngine.Sync2(new(models.SysRolePermission))
 
+	e.OrmEngine.Sync2(new(models.SysAttachment))
+
 }
 
 func InitRouter(e *engine.ApiEngine) {
 	g_engine = e
 	SyncDb(e)
+
 	api := e.GinEngine.Group("/api")
 	v1 := api.Group("/v1")
 
@@ -132,11 +147,19 @@ func InitRouter(e *engine.ApiEngine) {
 	system.GET("/logout", systemController_logout)
 	system.POST("/logout", systemController_logout)
 
-	v1.Use(middleware.LoginWare())
+	//system.GET("/sys_attachment/upload",sys_attachmentController_upload)
+	system.POST("/upload", sys_attachmentController_upload)
+	//system.PUT("/sys_attachment/upload",sys_attachmentController_upload)
 
-	//v1.GET("/system/login", systemController_login)
-	//v1.POST("/system/login", systemController_login)
-	//v1.PUT("/system/login", systemController_login)
+	system.GET("/download/:attrId", sys_attachmentController_download)
+	//system.POST("/sys_attachment/download",sys_attachmentController_download)
+	//system.PUT("/sys_attachment/download",sys_attachmentController_download)
+
+	system.GET("/delete/:attrId", sys_attachmentController_delete)
+	//system.POST("/sys_attachment/delete",sys_attachmentController_delete)
+	//system.PUT("/sys_attachment/delete",sys_attachmentController_delete)
+
+	v1.Use(middleware.LoginWare())
 
 	v1.GET("/system/get_nav_tree", systemController_get_nav_tree)
 	v1.POST("/system/get_nav_tree", systemController_get_nav_tree)

+ 139 - 0
utils/http_util.go

@@ -0,0 +1,139 @@
+// Copyright (c) 2015 qianqiusoft.com
+// Licensed to You under the GNU Affero GPL v3
+// See the LICENSE file at git.qianqiusoft.com/qianqiusoft/light-vocation/LICENSE
+// http://www.gnu.org/licenses/why-affero-gpl.en.html
+
+package utils
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"mime/multipart"
+	"net/http"
+	"os"
+	"strings"
+	"crypto/tls"
+	"time"
+)
+
+type HttpUtil struct {
+}
+
+func NewHttpUtil() *HttpUtil {
+	return &HttpUtil{}
+}
+
+// 使用body post提交数据
+func (this *HttpUtil) PostBytes(url string, data []byte) ([]byte, error) {
+
+	body := bytes.NewReader(data)
+	request, err := http.NewRequest("POST", url, body)
+	if err != nil {
+		//log.Println("http.NewRequest,[err=%s][url=%s]", err, url)
+		return []byte(""), err
+	}
+	request.Header.Set("Connection", "Keep-Alive")
+
+	return this.getResponse(request)
+}
+
+// 模拟form提交数据,包含,上传文件
+func (this *HttpUtil)PostFormWithReader(url string, params map[string]string, fileField, fileName string, r io.Reader) ([]byte, error) {
+	body := &bytes.Buffer{}
+	writer := multipart.NewWriter(body)
+	part, err := writer.CreateFormFile(fileField, fileName)
+	if err != nil {
+		return nil, err
+	}
+	_, err = io.Copy(part, r)
+
+	for key, val := range params {
+		_ = writer.WriteField(key, val)
+	}
+	err = writer.Close()
+	if err != nil {
+		return nil, err
+	}
+	request, err := http.NewRequest("POST", url, body)
+	request.Header.Set("Content-Type", writer.FormDataContentType())
+
+	return this.getResponse(request)
+}
+
+// 模拟form提交数据,包含,上传文件
+func (this *HttpUtil) PostFormWithFile(url string, params map[string]string, paramName, path string) ([]byte, error) {
+	file, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	return this.PostFormWithReader(url, params, paramName, path, file)
+}
+
+// post
+func (this *HttpUtil) Post(url string, params map[string]string, headers map[string]string) ([]byte, error) {
+	return this.doRequest("POST", url, params, headers)
+}
+
+// get
+func (this *HttpUtil) Get(url string, params map[string]string, headers map[string]string) ([]byte, error) {
+	return this.doRequest("GET", url, params, headers)
+}
+
+// 一般数据提交
+func (this *HttpUtil) doRequest(method string, url string, params map[string]string, headers map[string]string) ([]byte, error) {
+	var r http.Request
+	r.ParseForm()
+	if params != nil {
+		for k, v := range params {
+			r.Form.Add(k, v)
+		}
+	}
+	bodystr := strings.TrimSpace(r.Form.Encode())
+	request, err := http.NewRequest(method, url, strings.NewReader(bodystr))
+	if err != nil {
+		return []byte(""), err
+	}
+
+	if headers == nil || len(headers) <= 0 {
+		request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+		request.Header.Set("Connection", "Keep-Alive")
+	} else {
+		for k, v := range headers {
+			request.Header.Set(k, v)
+		}
+	}
+
+	return this.getResponse(request)
+}
+
+func (this *HttpUtil) getResponse(request *http.Request) ([]byte, error) {
+	if request == nil {
+		return []byte(""), errors.New("request is nil")
+	}
+
+	tr := &http.Transport{
+		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
+		ResponseHeaderTimeout: time.Second * 60,
+		DisableKeepAlives:     true,
+	}
+
+	client := http.Client{Transport: tr}
+
+	var resp *http.Response
+	var err error
+	resp, err = client.Do(request)
+	if err != nil {
+		//log.Println("http.Do failed,[err=%s][url=%s]", err, url)
+		return []byte(""), err
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return []byte(""), err
+	}
+	return b, err
+}

+ 117 - 0
utils/other.go

@@ -0,0 +1,117 @@
+// Copyright (c) 2015 qianqiusoft.com
+// Licensed to You under the GNU Affero GPL v3
+// See the LICENSE file at git.qianqiusoft.com/qianqiusoft/light-vocation/LICENSE
+// http://www.gnu.org/licenses/why-affero-gpl.en.html
+
+package utils
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/logs"
+)
+
+func SubString(str string, begin, length int) (substr string) {
+	//将字符串的转换成[]rune
+	rs := []rune(str)
+	lth := len(rs)
+	// 简单的越界判断
+	if begin < 0 {
+		begin = 0
+	}
+	if begin >= lth {
+		begin = lth
+	}
+	end := begin + length
+	if end > lth {
+		end = lth
+	}
+	// 返回子串
+	return string(rs[begin:end])
+}
+
+func FormatCamelString(str string) string {
+	res := ""
+	array := strings.Split(str, "_")
+	for _, val := range array {
+		if len(val) > 0 {
+			res += strings.ToUpper(SubString(val, 0, 1)) + strings.ToLower(SubString(val, 1, len(str)-1))
+		}
+	}
+	return res
+}
+
+func FormatFieldAndJsonString(columnName string) string {
+	return strings.ToLower(columnName)
+}
+
+func GetSizeOfColumn(size int) string {
+	//fmt.Printf(".............size is %d", size)
+	if size <= 0 {
+		return ""
+	} else {
+		ss := fmt.Sprintf("size(%d);", size)
+		//fmt.Println(ss)
+		return ss
+	}
+}
+
+func ConvertColTypeToDBType(colType string) string {
+	colType = strings.ToLower(colType)
+	switch colType {
+	case "string":
+		return "varchar"
+	case "text":
+		return "text"
+	case "datetime":
+		return "datetime"
+	default:
+		return colType
+	}
+}
+
+func ConvertColType(colType string) string {
+	colType = strings.ToLower(colType)
+	switch colType {
+	case "string-text":
+		return "string"
+	case "time.Time-date":
+		return "time.Time"
+	case "text":
+		return "string"
+	case "string":
+		return "string"
+	case "datetime":
+		return "time.Time"
+	default:
+		return colType
+	}
+}
+
+func TotalPage(record, size int) int {
+	tp := record / size
+	if tp < 0 {
+		return 1
+	}
+	if record%size == 0 {
+		return tp
+	}
+	return tp + 1
+}
+
+func FormatForBrowse(agent, val string) string {
+	if strings.Contains(strings.ToLower(agent), "safari/") && !strings.Contains(strings.ToLower(agent), "chrome/") {
+		logs.Debug("Safari浏览器编码")
+	} else if strings.Contains(strings.ToLower(agent), "firefox/") {
+		logs.Debug("Firefox浏览器编码")
+	} else if strings.Contains(strings.ToLower(agent), "chrome/") && strings.Contains(strings.ToLower(agent), "safari/") && !strings.Contains(strings.ToLower(agent), "edge/") {
+		logs.Debug("Chrome浏览器编码")
+	} else {
+		logs.Debug("IE浏览器编码")
+		val = url.QueryEscape(val)
+		val = strings.Replace(val, "+", "%20", -1)
+	}
+	return val
+}

+ 125 - 0
utils/storage.go

@@ -0,0 +1,125 @@
+// Copyright (c) 2015 qianqiusoft.com
+// Licensed to You under the GNU Affero GPL v3
+// See the LICENSE file at git.qianqiusoft.com/qianqiusoft/light-vocation/LICENSE
+// http://www.gnu.org/licenses/why-affero-gpl.en.html
+
+package utils
+
+import (
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+
+	sysmodels "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
+
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/config"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/logs"
+)
+
+func PostFile(reader io.Reader) (string, string, int32, error) {
+	urlStr := config.AppConfig.GetKey("storage")
+	params := make(map[string]string)
+	params["genthumb"] = "1"
+
+	bytess, err := NewHttpUtil().PostFormWithReader(urlStr, params, "file", "11", reader)
+	if err != nil {
+		return "", "", 0, err
+	}
+
+	fmt.Println(string(bytess))
+	result := &sysmodels.StorageResult{}
+
+	err = json.Unmarshal(bytess, result)
+	if err != nil {
+		return "", "", 0, err
+	}
+
+	download := fmt.Sprintf("http://%s:%d/v1/fs_file/%d", result.Ip, result.Port, result.Id)
+	logs.Debug("下载地址:", download)
+
+	return download, result.Hash, result.Len, nil
+}
+
+func PutFile(reader io.Reader, length int64) (string, string, int32, error) {
+	urlStr := config.AppConfig.GetKey("storage") //beego.AppConfig.String("storage")
+	hreq := http.Request{}
+
+	fmt.Println(urlStr + "?genthumb=1")
+
+	hreq.URL, _ = url.Parse(urlStr + "?genthumb=1")
+	hreq.Method = "PUT"
+	hreq.ContentLength = length
+
+	hreq.Body = ioutil.NopCloser(reader)
+
+	tr := &http.Transport{
+		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
+		ResponseHeaderTimeout: time.Second * 60,
+		DisableKeepAlives:     true,
+	}
+
+	client := http.Client{Transport: tr}
+
+	hresp, err := client.Do(&hreq)
+	if err != nil {
+		return "", "", 0, err
+	}
+
+	defer hresp.Body.Close()
+
+	resBody, err := ioutil.ReadAll(hresp.Body)
+	if err != nil {
+		return "", "", 0, err
+	}
+
+	logs.Debug("上传返回:", string(resBody))
+
+	result := &sysmodels.StorageResult{}
+
+	err = json.Unmarshal(resBody, result)
+	if err != nil {
+		return "", "", 0, err
+	}
+
+	download := fmt.Sprintf("http://%s:%d/v1/fs_file/%d", result.Ip, result.Port, result.Id)
+	logs.Debug("下载地址:", download)
+
+	return download, result.Hash, result.Len, nil
+}
+
+func GetFile(urlStr string) (io.ReadCloser, error) {
+	if strings.Index(urlStr, "fs_file/") > 0 {
+		i := strings.LastIndex(urlStr, "/")
+		fileid := urlStr[i+1:]
+		storageurl := config.AppConfig.GetKey("storage") //beego.AppConfig.String("storage")
+		urlStr = strings.TrimRight(storageurl, "/") + "/" + fileid
+		fmt.Println(".................................................................." + urlStr)
+	}
+
+	hreq := http.Request{}
+
+	hreq.URL, _ = url.Parse(urlStr)
+	hreq.Method = "GET"
+
+	tr := &http.Transport{
+		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
+		ResponseHeaderTimeout: time.Second * 60,
+		DisableKeepAlives:     true,
+	}
+
+	client := http.Client{Transport: tr}
+
+	hresp, err := client.Do(&hreq)
+	if err != nil {
+		return nil, err
+	}
+
+	return hresp.Body, nil
+}