ring-middleware拥有良好的可扩展性。ring默认使用内存存储session(基于atom
实现),本文演示如何使用redis存储session。源码地址
实现
首先在project.clj
中引入ring-core
依赖,
:dependencies [[ring/ring-core "1.4.0"]]
定义我们的SessionStore
:
(ns cs.redis.session
(:require
[ring.middleware.session.store :refer [SessionStore]])
(:import [java.util UUID]))
;; redis连接配置
(def rds-session-config (atom nil))
(defn config-rds-session!
[rds-configs]
(reset! rds-session-config rds-configs))
(defmacro wcar* [& body]
`(car/wcar (:server @rds-session-config) ~@body))
;; 实现存、取、删方法
(defn store-code
"Store a `key`-`val` pair. If `val` is nil, a random string
will be generated. If `ttl`(secs) is nil, the code will not expire.
Returns the val stored."
[{:keys [key val ttl]}]
{:pre [key val]}
(wcar*
(car/multi)
(car/set key val)
(when ttl (car/expire key ttl))
(car/exec))
val)
(defn get-code
[{:keys [key]}]
{:pre [key]}
(wcar* (car/get key)))
(defn remove-code
[{:keys [key]}]
{:pre [key]}
(wcar* (car/del key)))
(defn touch
"Touch a key to reset the access time.
Returns nil if the key is already expired, otherwise returns the value of the key."
[{:keys [key ttl]}]
{:pre [key ttl]}
(first
(let [key key]
(wcar*
(when (car/get key)
(car/expire key ttl))))))
;; 定义RedisSessionStore
(defn- make-session-key [key]
(str (or (:session-prefix @rds-session-config) (subs (str (UUID/randomUUID)) 25)) key))
(deftype RedisSessionStore []
SessionStore
(read-session [_ key]
(touch {:key (make-session-key key) :ttl (or (:session-ttl @rds-session-config) 7200)}))
(write-session [_ key data]
(let [key (or key (str (UUID/randomUUID)))]
(store-code {:key (make-session-key key) :val data :ttl (or (:session-ttl @rds-session-config) 7200)})
key))
(delete-session [_ key]
(remove-code {:key (make-session-key key)})
nil))
(defn redis-session-store
"Redis session store. Redis db and session key prefix are configured
in edn files."
[]
(RedisSessionStore.))
如何使用
- Web应用启动时配置redis:
(cs.redis.session/config-rds-session! {:server rds-server-ip ;; redis服务器ip :session-ttl session-ttl-in-secs ;; session超时时间(秒) :session-prefix session-key-prefix ;; session-key的前辍;默认为随机字符串 })
- 配置ring-middleware
;; compojure方式 (-> (compojure.core/routes your-routes) ;;(wrap-other-middlewares) (ring.middleware.defaults/wrap-defaults (assoc-in site-defaults [:session :store] (redis-session-store)))) ;; 或如果用lib-noir时 (noir.util.middleware/app-handler [your-routes] :ring-defaults (assoc-in site-defaults [:session :store] (redis-session-store)))