接触到clojure是在一个月前,当时的我满身心的投入到ROR的学习中去,而且学的还不咋滴,但是迫于工作需要及各种原因,只好硬着头皮学习clojure。
花了几天学习了clojure的基本语法和一些概要,然后准备一点一点的开始写项目。
**
首先是建立project,我使用的是luminus框架。
lein new luminus message
这个可以看luminus的官方文档 http://www.luminusweb.net 里面讲解的比较详细,很受用~~~
我自己也翻译一些 luminus 翻译
**
背景:使用emacs
要求:1.公司原来的消息服务器是用ruby写的,但是有一个问题就是消息服务器没几分钟就会down掉,不稳定,用unicorn作为rails的消息服务器实现,用nginx做前端代理,数据库使用redis。
2.写好后用chrom的插件postman请求,要求得到的数据和以前的一样。
3.postman会传送三个参数 contentType;Cache-Control;LAST_EVENT_ID
**defroutes 的时候遇到问题
:如何将LAST_EVENT_ID在headers中取得?怎么定义URL?怎么传入参数?
-->> (GET "/message/:channel" {{channel :channel} :params {str_last_event_id "last_event_id"} :headers} (get-message channel str_last_event_id))
GET是指请求是get方法,message/:channel 是指请求形式,其中:channel是传入的参数,header中的str_last_event_id对应函数体内的last_event_id;get-message是函数名,这个函数是我用来实现总体功能的函数,后面跟的channel和str_last_event_id是函数的参数,本项目中channel是传入的,str_last_event_id是从header中取得的(事实上也是传入的参数)
**连接redis
从github上查到carmine目前是比较流行的一个 Clojure Redis 客户端& 消息队列,具体自己查。
[com.taoensso/carmine "2.6.2"] ; project.clj
[clj-redis "0.0.12"] ; project.clj
[clj-redis.client :as redis] ; ns
(ns my-app (:require [taoensso.carmine :as car :refer (wcar)])) ; ns
[clj-redis.client :as redis] ; ns
(ns my-app (:require [taoensso.carmine :as car :refer (wcar)])) ; ns
(def redis-connect
{:pool {} :spec {:host "服务器名称"
:port 端口号
:password "密码"
}})
(defmacro wcar* [& body] `(car/wcar redis-connect ~@body))
redis-connect是上面定义的函数
**设置headers
{:headers {"contentType" "text/event-stream"
"Cache-Control" "no-cache" }}
{:headers {"contentType" "text/event-stream"
"Cache-Control" "no-cache" }}
可以自己测试一下
**下面开始操作各种数据的时候遇到的问题
*从redis中取得数据
(def str_server_current_id (.toString (wcar* (car/hget channel "current_id"))))
channel是传入的参数,current_id 是服务器端的内容,从redis中取得当前服务器的id,.toString是将取得的数据转成string类型。
*string 类型转成 Integer类型用 Integer/parseInt
(def server_current_id (Integer/parseInt str_server_current_id))
将str_last_event_id转成Integer类型
*使用换行字符
(def channel_message (str channel_message "data:" str_message_convert "\n" "id:" (.toString index) "\n\n"))
*从redis中取得数据的形式问题
(def h_message (wcar* (car/hgetall* message_transit true))) 这个也很重要,一直得到的数据形式不对,后来翻墙才找到这个解决办法~~~~~~
*后期需要将得到的结果编码
(import [java.net URLEncoder])
*编码格式
(def str_message_convert (URLEncoder/encode str_message_to "UTF-8"))
(def str_message_convert (URLEncoder/encode str_message_to "UTF-8"))
str_message_to 是要编码的字段
*clojure中的hashmap和arraymap,这个搞得我头大了
总之最好使用hash-map
((def str_message (hash-map
:from (get h_message :from)
:channel_name (get h_message :channel_name)
:message_id (.toString index)))
(def str_message_to (json/write-str str_message :escape-unicode false)) 这个很重要啊,之前没有加:escape-unicode false 得到的结果是中文解码后的结果总是不对。
((def str_message (hash-map
:from (get h_message :from)
:channel_name (get h_message :channel_name)
:message_id (.toString index)))
(def str_message_to (json/write-str str_message :escape-unicode false)) 这个很重要啊,之前没有加:escape-unicode false 得到的结果是中文解码后的结果总是不对。
这样的好处就是可以将中文部分不编码,URL等带有'/'的不前加上转义字符,保证解码的正确性。
* 判断channel中是否含有starsworld_star_public,返回true或者false
(.contains channel "starsworld_star_public"))
* 判断channel中是否含有starsworld_star_public,返回true或者false
(.contains channel "starsworld_star_public"))
*clojure语言中的迭代关系
(doseq [index (range min_id max_id)]
(get-hmessage channel index))
(doseq [index (range min_id max_id)]
(get-hmessage channel index))
从min_id到max_id一次循环,每次的值均赋值给index,(get-hmessage channel index)为函数get-message调用
PS:项目小总结,供个人以后参考用。
终于把消息推送写好了,也对clojure多了解了些,接下来在写个复杂的练习下。