转载我的个人博客:tomonori.cc
最近公司在写数据可视化平台的一个项目,提供给公司运营内部使用。关于运营用户这方面,打算直接使用对应app的运营管理平台(另外一个使用java服务端)调用登陆接口,java服务端已经编写好接口,这边golang直接调用他们那的接口,这边处理存储请求获取到的用户信息和存储token的功能,就有了redis缓存相关的操作。在测试中,本来是用的运营管理平台的redis缓存服务器,不过我打算在我自己的服务器,直接搭建个redis缓存数据库。仅记此文章,作为查询和学习的记录。
安装
- 在redis官网中下载tar.gz压缩包,保证最新版,在你当前的目录下(我的是在/home/download/中)
# 解压缩
tar xzf redis-x.x.xx.tar.gz
# cd进去进行编译
cd redis-x.x.xx.tar.gz
make
复制代码
- 编译完,在当前目录下会生成src的目录,编译完成的所有项都在这里面(redis-server、redis-cli)
# 当前目录:/home/download/redis-x.x.xx
# 将redis文件移动到/usr/local/目录下,不移动也可以,我不打算做环境变量,保证我每次都能记得文件包在哪
# 请务必记得也移动redis.conf配置文件
cp -r ./src /usr/local/redis
cp ./redis.conf /usr/local/redis/config/
复制代码
配置
- 修改redis.conf配置文件
# /usr/local/redis/config/redis.conf
vi redis.conf
# 关于redis.conf中的项,可以去查询文档,这边修改这些项
requirepass xxxxxxxx # 开启auth密码验证(如果在服务端中设置了密码登陆,这边不设置的话,会出现“ERR Client sent AUTH, but no password is set”)
bind 0.0.0.0 # 如果在服务器厂商那开放了6379端口,任然不能从本地连接服务器redis的话,可以进行设置
daemon yes # 设置为守护进程,这个不多说
复制代码
使用
- 开启持久化和配置文件启动
# /usr/local/redis
./redis-server ./config/redis.conf --appendonly yes
复制代码
# 接上
# 使用redis终端进行测试
./redis-cli
复制代码
- 在本地中的使用,本地使用的是windwos端的RedisDesktopManager
Golang代码编写
直接上代码吧
# Config/config.ini
[redis]
ADDR = your server address:6379
PASSWORD = 123456
DB = 0
复制代码
// Middlewares/Cache/redis.go
package Cache
import (
"fmt"
"sync"
"github.com/go-redis/redis"
"time"
"virtual-data/Middlewares/setting"
)
type RedisStorage struct {
}
var (
instance *RedisStorage
once sync.Once
client *redis.Client
err error
)
func Instance() *RedisStorage {
once.Do(func() {
instance = &RedisStorage{}
})
return instance
}
func (r *RedisStorage) Init() (issue error) {
var (
addr, password string
db int
)
sec, err := setting.Cfg.GetSection("redis")
if err != nil {
fmt.Errorf("Fial to get config section 'redis': %s\n", err)
}
addr = sec.Key("ADDR").String()
password = sec.Key("PASSWORD").String()
db, _ = sec.Key("DB").Int()
client = redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})
_, err = client.Ping().Result()
if err != nil {
return err
}
return nil
}
// 存
func (r *RedisStorage) Set(key, value string, expiration time.Duration) error {
err := client.Set(key, value, expiration).Err()
return err
}
// 查
func (r *RedisStorage) Get(key string) (string, error) {
result, err := client.Get(key).Result()
return result, err
}
// 删
func (r *RedisStorage) Del(key string) error {
err := client.Del(key).Err()
return err
}
复制代码
在登陆控制器中使用
- ViewModel 返回数据格式声明
// ViewModel/Login/v_login.go
package Login
type ResultData struct {
CreateTime int64 `json:"createTime"`
UserId int `json:"userId"`
Token string `json:"token"`
RealName string `json:realName`
}
type Vresult struct {
Code int `json:"code"`
Data ResultData `json:"data"`
}
type Verror struct {
Code int `json:"code"`
ThrowType string `json:"throwType"`
Message string `json:"message"`
}
复制代码
- LoginController 登陆接口方法编写
// Controllers/LoginController.go
package Controllers
import (
"encoding/json"
"fmt"
"github.com/astaxie/beego/validation"
"github.com/kataras/iris"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"virtual-data/Middlewares/Cache"
"virtual-data/Middlewares/setting"
VMlogin "virtual-data/ViewModel/Login"
)
func Login(ctx iris.Context) {
userName := ctx.Request().FormValue("username")
passWord := ctx.Request().FormValue("password")
valid := validation.Validation{}
valid.Required(userName, "username").Message("账号不能为空")
valid.Required(passWord, "password").Message("密码不能为空")
if !valid.HasErrors() {
result, err := requestJavaServerService(userName, passWord)
if err != nil {
ctx.JSON(Result(http.StatusBadGateway, err))
} else {
ctx.JSON(result)
}
} else {
ctx.JSON(Result(http.StatusBadRequest, valid.Errors[0].Message))
}
}
/**
* 请求java服务端接口,返回请求成功或错误的值
* @method requestJavaServerService
* @param username string
* @param password string
* @return interface{}
* @return error
*/
func requestJavaServerService(username, password string) (interface{}, error) {
client := &http.Client{}
var err error
var urlAddr string
userInfo := url.Values{}
userInfo.Add("userName", username)
userInfo.Add("password", password)
sec, err := setting.Cfg.GetSection("request")
if err != nil {
fmt.Errorf("Fial to get config section 'request': %s\n", err)
}
// 在配置文件中配置好的请求地址
urlAddr = sec.Key("url").String()
request, err := http.NewRequest(
"POST",
urlAddr,
strings.NewReader(userInfo.Encode()),
)
request.Header.Set("Content-type", "application/x-www-form-urlencoded")
request.Header.Set("cms-token", "null")
request.Header.Set("cms-channel", "0")
if err != nil {
return nil, err
}
parseObj, err := parseResponseBody(client, request)
if err != nil {
return nil, err
}
return parseObj, nil
}
type tempBody struct {
Code int `json:"code"`
Data interface{} `json:"data"`
}
/**
* 处理请求成功的body
* @method parseResponseBody
* @param client *http.Client
* @param request *http.Request
* @return obj interface{}
* @return err error
*/
func parseResponseBody(client *http.Client, request *http.Request) (obj interface{}, err error) {
var resultObj VMlogin.Vresult
var errorObj VMlogin.Verror
var tempObj tempBody
resp, err := client.Do(request)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(body, &tempObj)
if err != nil {
return nil, err
}
if tempObj.Code == 200 {
_ = json.Unmarshal(body, &resultObj)
obj = resultObj
if err = cacheManagerService(resultObj); err != nil {
return nil, err
}
} else {
_ = json.Unmarshal(body, &errorObj)
obj = errorObj
}
return obj, nil
}
/**
* 设置处理缓存的工厂
* @method cacheManagerService
* @param resultObj VMlogin.Vresult
* @return error
*/
func cacheManagerService(resultObj VMlogin.Vresult) error {
var oldResultObj VMlogin.Vresult
var redisKey string
var redisValue string
var err error
// 组合查询用户信息的声明和赋值
redisKey = FormatRedisString(REDIS_KEY_USER, resultObj.Data.UserId)
redisJsonValue, _ := json.Marshal(resultObj.Data)
redisValue = string(redisJsonValue)
// 查询是否存在此用户
infoVal, _ := Cache.Instance().Get(redisKey)
// json反序列化查询到的json字符串,将存储在缓存中的值赋值到一个变量上
_ = json.Unmarshal([]byte(infoVal), &oldResultObj.Data)
// 如果返回空字符串,则是新用户,创建新的缓存
// 否则根据缓存的token组合去将旧的缓存删除,覆盖新的用户信息和创建新的token
if infoVal == "" {
// 设置新的用户信息缓存
err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
if err != nil {
return err
}
// 设置新的token信息缓存
redisKey = FormatRedisString(REDIS_KEY_TOKEN, resultObj.Data.Token)
redisValue = strconv.Itoa(resultObj.Data.UserId)
err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
if err != nil {
return err
}
} else {
// 声明并赋值旧的token信息
oldToken := oldResultObj.Data.Token
// 删除旧的token
err = Cache.Instance().Del(FormatRedisString(REDIS_KEY_TOKEN, oldToken))
if err != nil {
return err
}
// 设置覆盖新的用户信息
err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
if err != nil {
return err
}
// 设置新的token
redisKey = FormatRedisString(REDIS_KEY_TOKEN, resultObj.Data.Token)
redisValue = strconv.Itoa(resultObj.Data.UserId)
err = Cache.Instance().Set(redisKey, redisValue, 744 * time.Hour)
if err != nil {
return err
}
}
return nil
}
复制代码