clojure-web中的resources

不管是springboot项目,还是我们每天都在玩的luminus项目,做web项目免不了处理一些资源文件,本篇介绍原因和常用案例。

Ring(一定要了解下)

Ring是一个Clojure Web程序库,有点类似与Java的servlet。
公司目前用的都是用luminus 框架new出来的web项目,也是用Ring把我们的代码编译到一个java servlet运行的,所以必须去了解(有中文版)。但是本文只说Resources的使用。

Ring框架里对静态资源的文档介绍确实不多,在静态资源(Static Resources)

案例一:dev模式可以,打包后找不到文件

一些新手经常会说:“我本地没问题”。是的,本地确实没问题,所谓的没问题的代码是这样的,
比如要拷贝resources里的一个文件

(with-open [in (io/input-stream (io/resource "abc/file.dat"))]   ;; resources/abc/file.dat
    (io/copy in (io/file "/path/to/your/target/path")))

这段代码本地是没问题,但是以jar方式运行就会找不到文件。

这要了解下打包干了啥,有点深。
简单说就是本地运行时确实这个路径下有这个文件。但是打成jar以后可以解压看看,这个路径不是你脑子的那个路径了。

  • 原因:jar本身就是一个文件,不是一个目录,代码中拼接的文件路径变成了xxx.jar!abc/file.dat,这是一个伪地址,解压下jar也可以看到,确实不是这样的,所以找不到路径。

那怎么写呢?就是用io/resource代替赤裸裸的路径,下面这个函数接收一个路径,只要是项目根目录下resouces里的地址,就不会有问题。

(defn- reader-excel-template
  "读入模板"
  [t-path]
  (let [resource (io/resource t-path)
        file-name (str (common-utils/uuid) ".xlsx")]
    (with-open [in (io/input-stream resource)]
      (io/copy in (io/file file-name)))
    (io/as-file file-name)))

案例二:写个接口把resources里的文件读出来

比如我们resources里有这些文件。

$ tree -c -L 3
.
├── doc
├── migrations
├── public
│   ├── img
│   │   ├── img_index.png
│   │   ├── img_index_icon.png
│   │   └── warning_clojure.png
└── sql
    ├── queries.sql

写一个接口:

["/download"
     {:get {:summary "downloads a file"
            :swagger {:produces ["image/png"]}
            :handler (fn [_]
                       {:status  200
                        :body    (-> "public/img/warning_clojure.png"
                                     (io/resource)
                                     (io/input-stream))})}}]

上面这个接口,可以是resources目录里的任意文件,只是我们按照常规放在了public目录里了。浏览器访问这个接口时,像pdf,图片,视频等浏览器会直接打开,其他不支持的格式,会开始下载。
如果格式明确,向让调用者知道类型,可以在handler指定类型,比如这个获取图片的,可以加:

  :headers {"Content-Type" "image/png"}

案例三:把静态文件让jar服务带起来

我们有个build好的前端项目,当然包括了index.html,js,css,images等。想要让jar启动时,作为server同时把这个前端项目,不需要使用nginx,python等。

  • 前端代码全部复制到resources/public目录下。
    可能如下:
$ pwd
/Users/mahaiqiang/git/redcreation/chutian/src/clj-backend/resources/public

$ ll
total 352
-rw-r--r--  1 mahaiqiang  staff    96K Sep  8 16:00 256x256.icns
-rw-r--r--  1 mahaiqiang  staff   1.7K Sep  8 16:00 32x32.icns
-rw-r--r--  1 mahaiqiang  staff   1.3K Sep  8 16:00 asset-manifest.json
-rw-r--r--  1 mahaiqiang  staff   5.7K Sep  8 16:00 electron.js
-rw-r--r--  1 mahaiqiang  staff    40K Sep  8 16:00 icon.png
-rw-r--r--  1 mahaiqiang  staff   536B Sep  8 16:00 index.html
-rw-r--r--  1 mahaiqiang  staff   532B Sep  8 16:00 log.js
-rw-r--r--  1 mahaiqiang  staff   284B Sep  8 16:00 manifest.json
-rw-r--r--  1 mahaiqiang  staff   525B Sep  8 16:00 preload.js
-rw-r--r--  1 mahaiqiang  staff   1.8K Sep  8 16:00 product.js
drwxr-xr-x  5 mahaiqiang  staff   160B Sep  8 16:00 static

  • 配置handler,用warp-resource函数把静态资源加进来。
(:require [ring.middleware.resource :as resource])

(defn- async-aware-default-handler
  ([_] nil)
  ([_ respond _] (respond nil)))

;;静态资源放在resources/public/目录下.注意:index.html里引入的static前不能有斜线这个绝对路径
(defn- create-resource-handler []
  (resource/wrap-resource "/" {:root "resources/public"}))

(mount/defstate app-routes
  :start
  (ring/ring-handler
   (ring/router
    [(conj (base/service-routes)
           (base/swagger-routes)
           (api-public-routes)
           (api-routes)
           (api-callback-routes)
           (admin-routes)
           (admin-pulic-routes))])
   (ring/routes
    (create-resource-handler)
    (wrap-content-type (wrap-webjars async-aware-default-handler))
    (ring/create-default-handler))))

案例四:用jar代理本地指定目录下的任意文件

我们可能把本地一个目录当成了文件服务器,上传时上传到这个目录,上传以后查看当然也要能访问到。
Ring框架,也有静态资源(Static Resources),写了也不点进去看,搬过来吧.

Web应用经常需要服务静态内容,例如图片或者样式表.Ring提供了两个中间件函数来做这个事情.

一个是wrap-file.它服务来自当前文件系统一个目录的静态内容:

(use 'ring.middleware.file)
(def app
  (wrap-file your-handler "/var/www/public"))

另一个是wrap-resource.它服务来自JVM classpath下的静态内容:

(use 'ring.middleware.resource)
(def app
  (wrap-resource your-handler "public"))

改造下我们的项目,

(:require [ring.middleware.resource :as resource]
              [ring.middleware.webjars :refer [wrap-webjars]])

(mount/defstate app-routes
  :start
  (ring/ring-handler
   (ring/router
    [(conj (base/service-routes)
           (base/swagger-routes)
           (api-routes))])
   (ring/routes
    (wrap-file (ring/create-resource-handler {:path "/"})
               "/Users/mahaiqiang/Downloads/")  ;;把本地下载目录当成文件存储服务器
    (wrap-content-type (wrap-webjars (constantly nil)))
    (ring/create-default-handler))))

案例三和案例四可以同时使用,不冲突。

推荐资料

Ring 静态资源
Clojure Resources

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容