本文来自博客园,作者:Arway,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/16478717.html
. ├── db │ ├── file.go │ └── mysql │ └── conn.go ├── doc │ └── 建表语句.sql ├── go.mod ├── go.sum ├── handler │ └── handler.go ├── main.go ├── meta │ └── filemeta.go ├── static │ └── view │ └── index.html └── util └── util.go
create database fileserver; use fileserver; CREATE TABLE `tbl_file` ( `id` int(11) NOT NULL AUTO_INCREMENT, `file_sha1` char(40) NOT NULL DEFAULT '' COMMENT '文件hash', `file_name` varchar(256) NOT NULL DEFAULT '' COMMENT '文件名', `file_size` bigint(20) DEFAULT '0' COMMENT '文件大小', `file_addr` varchar(1024) NOT NULL DEFAULT '' COMMENT '文件存储位置', `create_at` datetime DEFAULT NOW() COMMENT '创建日期', `update_at` datetime DEFAULT NOW() on update current_timestamp() COMMENT '更新日期', `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态(可用|禁用|已删除等状态)', `ext1` int(11) DEFAULT '0' COMMENT '备用字段1', `ext2` text COMMENT '备用字段2', PRIMARY KEY (`id`), UNIQUE KEY `idx_file_hash` (`file_sha1`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
db/mysql/conn.go
package mysql import ( "database/sql" "log" _ "github.com/go-sql-driver/mysql" // 导入mysql驱动 ) // 声明mysql连接对象 var db *sql.DB func init() { db, _ = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3307)/fileserver?charset=utf8") db.SetConnMaxIdleTime(1000) err := db.Ping() // test connection if err != nil { log.Fatal("Failed to connect to mysql, err: " + err.Error()) } } // DBConn返回数据库连接对象 func DBConn() *sql.DB { return db }
文件上传完后,保存文件元信息到mysql
db/file.go
// OnFileUploadOK: 文件上传完成,保存meta到数据库 func OnFileUploadOK(fsha1, filename, fileaddr string, filesize int64) bool { stmt, err := mydb.DBConn().Prepare( "insert ignore into tbll_file(`file_sha1`, `file_name`, `file_size`, " + "`file_addr`, `status`)values(?,?,?,?,1)") if err != nil { fmt.Println("Failed to prepare statement, err: " + err.Error()) return false } defer stmt.Close() ret, err := stmt.Exec(fsha1, filename, filesize, fileaddr) if err != nil { fmt.Println(err.Error()) return false } // 判断是否已经插入过相同fsha1的记录, 插入相同的会直接忽略 if rf, err := ret.RowsAffected(); nil == err { if rf <= 0 { // sql 执行成功了,但没有产生新的记录,抛个warning fmt.Printf("File with hash: %s has been upload before", fsha1) } return true } return false }
meta/filemeta.go
// UpdateFileMetaDB: 新增/更新文件元信息到数据库 func UpdateFileMetaToDB(fm FileMeta) bool { return mydb.OnFileUploadOK(fm.FileSha1, fm.FileName, fm.Location, fm.FileSize) }
handler/handler.go
// UploadHandler: 文件上传接口 func UploadHandler(w http.ResponseWriter, r *http.Request) { ... else if r.Method == "POST" { ... // meta.UpdateFileMeta(fileMeta) // 持久化到数据库 _ = meta.UpdateFileMetaToDB(fileMeta) ...
db/file.go
func GetFileMeta(fhash string) (*TableFile, error) { stmt, err := mydb.DBConn().Prepare( "SELECT file_sha1, file_name, file_addr, file_size "+ "FROM tbll_file where file_sha1=? limit 1") if err != nil { fmt.Println(err.Error()) return nil, err } defer stmt.Close() tf := TableFile{} // Scan可以把数据库取出的字段值赋值给指定的数据结构 err = stmt.QueryRow(fhash).Scan(&tf.FileSha1, &tf.FileName, &tf.FileAddr, &tf.FileSize) if err != nil { fmt.Println(err.Error()) return nil, err } return &tf, nil }
``
meta/filemeta.go
// GetFileMetaDB:从mysql获取元信息 func GetFileMetaFromDB(fhash string) (FileMeta, error) { tf, err := mydb.GetFileMeta(fhash) if err != nil { return FileMeta{}, err } fm := FileMeta{ FileSha1: tf.FileSha1, FileName: tf.FileName.String, Location: tf.FileAddr.String, FileSize: tf.FileSize.Int64, } return fm, nil }
handler/handler.go
// GetFileMetaHandler:通过文件sha1值获取文件元信息的接口 func GetFileMetaHandler(w http.ResponseWriter, r *http.Request) { ... // fm := meta.GetFileMeta(fh) fm, err := meta.GetFileMetaFromDB(fh) if err != nil { w.WriteHeader(http.StatusInternalServerError) } ...
测试:
http://localhost:8080/file/meta?filehash=1ce11ed4a3f0ebae4d78e0b66faf32ecc2c82ea7