Go实现短url项目的方法示例
程序员文章站
2022-03-29 17:25:04
首先说一下这种业务的应用场景:
1.把一个长url转换为一个短url网址
2.主要用于微博,二维码,等有字数限制的场景
主要实现的功能分析:
1.把长url的地址转...
首先说一下这种业务的应用场景:
1.把一个长url转换为一个短url网址
2.主要用于微博,二维码,等有字数限制的场景
主要实现的功能分析:
1.把长url的地址转换为短url地址
2.通过短url获取对应的原始长url地址
3.相同长url地址是否需要同样的短url地址
这里实现的是一个api服务
数据库设计
数据库的设计其实也没有非常复杂,如图所示:
这里有个设置需要主要就是关于数据库表中id的设计,需要设置为自增的
并且这里有个问题需要提前知道,我们的思路是根据id的值会转换为62进制关于进制转换的代码为:
// 将十进制转换为62进制 0-9a-za-z 六十二进制 func transto62(id int64)string{ // 1 -- > 1 // 10-- > a // 61-- > z charset := "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" var shorturl []byte for{ var result byte number := id % 62 result = charset[number] var tmp []byte tmp = append(tmp,result) shorturl = append(tmp,shorturl...) id = id / 62 if id == 0{ break } } fmt.println(string(shorturl)) return string(shorturl) }
所以这里需要设置一下数据库id的起始值,可以设置的大一点,这样转换为62进制之后不至于太短
代码逻辑
项目完整的代码git地址:
当然这里的代码还有待后面继续做优化,但是这里通过golang内置的net/http 库实现了一个简单的api功能
代码的目录结构
|____logic | |____logic.go |____model | |____data.go |____api | |____api.go |____client | |____client.go
logic目录为主要的处理逻辑
model是定义了request和response结构体
api目录为程序的入口程序
client 为测试请求,进行地址的转换
model 代码为:
package model type long2shortrequest struct { originurl string `json:"origin_url"` } type responseheader struct { code int `json:"code"` message string `json:"message"` } type long2shortresponse struct { responseheader shorturl string `json:"short_url"` } type short2longrequest struct { shorturl string `json:"short_url"` } type short2longresponse struct { responseheader originurl string `json:"origin_url"` }
logic的代码为:
package logic import( "go_dev/11/short_url/model" "github.com/jmoiron/sqlx" "fmt" "crypto/md5" "database/sql" ) var ( db *sqlx.db ) type shorturl struct { id int64 `db:"id"` shorturl string `db:"short_url"` originurl string `db:"origin_url"` hashcode string `db:"hash_code"` } func initdb(dsn string)(err error) { // 数据库初始化 db, err = sqlx.open("mysql",dsn) if err != nil{ fmt.println("connect to mysql failed:",err) return } return } func long2short(req *model.long2shortrequest) (response *model.long2shortresponse, err error) { response = &model.long2shortresponse{} urlmd5 := fmt.sprintf("%x",md5.sum([]byte(req.originurl))) var short shorturl err = db.get(&short,"select id,short_url,origin_url,hash_code from short_url where hash_code=?",urlmd5) if err == sql.errnorows{ err = nil // 数据库中没有记录,重新生成一个新的短url shorturl,errret := generateshorturl(req,urlmd5) if errret != nil{ err = errret return } response.shorturl = shorturl return } if err != nil{ return } response.shorturl = short.shorturl return } func generateshorturl(req *model.long2shortrequest,hashcode string)(shorturl string,err error){ result,err := db.exec("insert into short_url(origin_url,hash_code)values (?,?)",req.originurl,hashcode) if err != nil{ return } // 0-9a-za-z 六十二进制 insertid,_:= result.lastinsertid() shorturl = transto62(insertid) _,err = db.exec("update short_url set short_url=? where id=?",shorturl,insertid) if err != nil{ fmt.println(err) return } return } // 将十进制转换为62进制 0-9a-za-z 六十二进制 func transto62(id int64)string{ // 1 -- > 1 // 10-- > a // 61-- > z charset := "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" var shorturl []byte for{ var result byte number := id % 62 result = charset[number] var tmp []byte tmp = append(tmp,result) shorturl = append(tmp,shorturl...) id = id / 62 if id == 0{ break } } fmt.println(string(shorturl)) return string(shorturl) } func short2long(req *model.short2longrequest) (response *model.short2longresponse, err error) { response = &model.short2longresponse{} var short shorturl err = db.get(&short,"select id,short_url,origin_url,hash_code from short_url where short_url=?",req.shorturl) if err == sql.errnorows{ response.code = 404 return } if err != nil{ response.code = 500 return } response.originurl = short.originurl return }
api的代码为:
package main import ( "io/ioutil" "net/http" "fmt" "encoding/json" "go_dev/11/short_url/logic" "go_dev/11/short_url/model" _ "github.com/go-sql-driver/mysql" ) const ( errsuccess = 0 errinvalidparameter = 1001 errserverbusy = 1002 ) func getmessage(code int) (msg string){ switch code { case errsuccess: msg = "success" case errinvalidparameter: msg = "invalid parameter" case errserverbusy: msg = "server busy" default: msg = "unknown error" } return } // 用于将返回序列化数据,失败的返回 func responseerror(w http.responsewriter, code int) { var response model.responseheader response.code = code response.message = getmessage(code) data, err := json.marshal(response) if err != nil { w.write([]byte("{\"code\":500, \"message\": \"server busy\"}")) return } w.write(data) } // 用于将返回序列化数据,成功的返回 func responsesuccess(w http.responsewriter, data interface{}) { databyte, err := json.marshal(data) if err != nil { w.write([]byte("{\"code\":500, \"message\": \"server busy\"}")) return } w.write(databyte) } // 长地址到短地址 func long2short(w http.responsewriter, r *http.request) { // 这里需要说明的是发来的数据是通过post发过来一个json格式的数据 data, err := ioutil.readall(r.body) if err != nil { fmt.println("read all failded, ", err) responseerror(w, 1001) return } var req model.long2shortrequest // 将反序列化的数据保存在结构体中 err = json.unmarshal(data, &req) if err != nil { fmt.println("unmarshal failded, ", err) responseerror(w, 1002) return } resp, err := logic.long2short(&req) if err != nil { fmt.println("long2short failded, ", err) responseerror(w, 1003) return } responsesuccess(w, resp) } // 短地址到长地址 func short2long(w http.responsewriter, r *http.request) { // 这里需要说明的是发来的数据是通过post发过来一个json格式的数据 data, err := ioutil.readall(r.body) if err != nil { fmt.println("read all failded, ", err) responseerror(w, 1001) return } var req model.short2longrequest // 将反序列化的数据保存在结构体中 err = json.unmarshal(data, &req) if err != nil { fmt.println("unmarshal failded, ", err) responseerror(w, 1002) return } resp, err := logic.short2long(&req) if err != nil { fmt.println("long2short failded, ", err) responseerror(w, 1003) return } responsesuccess(w, resp) } func main(){ err := logic.initdb("root:123456@tcp(192.168.50.145:3306)/short_url?parsetime=true") if err != nil{ fmt.printf("init db failed,err:%v\n",err) return } http.handlefunc("/trans/long2short", long2short) http.handlefunc("/trans/short2long", short2long) http.listenandserve(":18888", nil) }
小结
这次通过这个小代码对go也有了一个初步的认识和使用,同时也通过net/http 包实现了api的功能,也对其基本使用有了大致了解
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。