Clojure Web开发–最新技术–第2部分

这是我的“ Clojure Web开发”系列的第2部分。 您可以在 Reddit线程上讨论第一部分。 阅读这些评论后,我必须解释我编写本系列文章的两个假设:

  • 让Clojure以外的人(尤其是Java开发人员)易于理解。 这就是为什么我使用REST / JSON来支持传递和组件作为“依赖注入”实现的原因,可以很容易地将其解释为等效于Spring框架。 Om有点冗长,也是如此,但我认为它比其他React包装器更容易理解,并且被广泛采用。
  • 使事情易于在开发人员机器上引导。 这是一个动手实践,所有单独的步骤都已提交给GitHub。 这就是为什么我使用MongoDB的原因,它不是将应用程序扩展到数百万用户的最佳选择,但是它非常适合引导-无需模式,表,仅插入数据即可开始工作。 我强烈推荐Honza Kral 多语种持久性演讲,他鼓励在项目开始时就从简单开始并进行优化,以使开发人员感到满意。

在上一篇文章中,我们使用Clojurescript前端引导了一个基本的Web应用程序,该应用程序使用REST前端(目前为静态)来提供REST数据,由于重新加载了repl和figwheel,它们都可以完全重新加载。 您可以在此分支中找到它的最终工作版本。

今天,我们将显示存储在MongoDB中的联系人列表。 我假设您已安装MongoDB(如果未安装)–与docker无关紧要。

从数据库提供联系列表

好的,让我们开始吧。 在后端,我们需要向project.clj添加一些依赖项:

:dependencies
   ...
   [org.danielsz/system "0.1.9"]
   [com.novemberain/monger "2.0.0"]]

monger是Mongo Java驱动程序的惯用Clojure包装器,而system是包括Mongo(类似于Spring的Spring Data)在内的各种数据存储组件的不错集合。

为了与数据存储进行交互,我喜欢使用抽象存储库的概念。 这应该对调用者隐藏实现细节,并允许将来切换到另一个商店。 因此,让我们在components/repo.clj创建一个抽象接口(在Clojure –协议中):

(ns modern-clj-web.component.repo)

(defprotocol ContactRepository
  (find-all [this]))

我们需要此参数作为参数,以允许Clojure运行时调度此存储库的正确实现。 使用Monger实施Mongo非常简单:

(ns modern-clj-web.component.repo
   (:require [monger.collection :as mc]
             [monger.json]))
...

(defrecord ContactRepoComponent [mongo]
  ContactRepository
  (find-all [this]
    (mc/find-maps (:db mongo) "contacts")))

(defn new-contact-repo-component []
  (->ContactRepoComponent {}))

这里要注意的事情:

  • mc/find-maps仅将集合中的所有记录作为Clojure映射返回
  • ContactComponent注入了由系统库创建的mongo组件,该组件在:db键下添加了Mongo客户端
  • 由于此组件是无状态的,因此我们无需实现component/Lifecycle接口,但仍可以像典型的了解生命周期的组件那样将其连接到系统中
  • 需要monger.json添加了对Mongo类型(例如ObjectId )的JSON序列化支持。

好的,现在该在终端节点/example.clj中使用我们的新组件了:

(:require
  ...
  [modern-clj-web.component.repo :as r])

(defn example-endpoint [{repo :contact-repo}]
 (routes
...
   (GET "/contacts" [] (response (r/find-all repo)))

{repo :contact-repo}标记(解构)会自动将系统地图中的:contact-repo键绑定到repo值。 因此,我们需要将组件分配给system.clj中的键:

(:require
  ...
  [modern-clj-web.component.repo :refer [new-contact-repo-component]]
  [system.components.mongo :refer [new-mongo-db]])

 (-> (component/system-map
          :app  (handler-component (:app config))
          :http (jetty-server (:http config))
          :example (endpoint-component example-endpoint)
          :mongo (new-mongo-db (:mongo-uri config))
          :contact-repo (new-contact-repo-component))
         (component/system-using
          {:http [:app]
           :app  [:example]
           :example [:contact-repo]
           :contact-repo [:mongo]}))))

简而言之–我们使用系统的new-mongo-db创建Mongo组件,使其成为存储库的依赖项,而存储库本身就是示例端点的依赖项。

最后,我们需要在config.clj配置:mongo-uri config属性:

(def environ
  {:http {:port (some-> env :port Integer.)}}
   :mongo-uri "mongodb://localhost:27017/contacts"})

要检查它是否工作正常,请重新启动repl,再次输入(go)并进行GET到http:// localhost:3000 / contacts

curl http://localhost:3000/contacts
[]

好的,因为我们在Mongo数据库中没有任何数据,所以我们得到了一个空列表。 让我们用mongo控制台添加一些内容:

mongo localhost:27017/contacts
MongoDB shell version: 2.4.9
connecting to: localhost:27017/contacts
>  db.contacts.insert({firstname: "Al", lastname: "Pacino"});
>  db.contacts.insert({firstname: "Johnny", lastname: "Depp"});

最后,我们的端点应返回以下两个记录:

curl http://localhost:3000/contacts
[{"lastname":"Pacino","firstname":"Al","_id":"56158345fd2dabeddfb18799"},{"lastname":"Depp","firstname":"Johnny","_id":"56158355fd2dabeddfb1879a"}]

甜! 再次-如有任何问题,请检查此commit

从ClojureScript获取联系人

在这一步中,我们将在ClojureScript前端上通过AJAX调用获取联系人。 像往常一样,我们需要很少的project.clj依赖项作为开始:

:dependencies 
     ...
       [org.clojure/clojurescript "1.7.48"]
       [org.clojure/core.async "0.1.346.0-17112a-alpha"]
       [cljs-http "0.1.37"]

使用figwheel应该已经可以看到figwheel ,但是最好显式地要求特定的版本。 cljs-http是ClojureScript和core.async的HTTP客户端core.async为CSP模型中的异步通信提供了便利,在ClojureScript中特别有用。 让我们看看它在实践中是如何工作的。

要进行AJAX调用,我们需要从cljs-http.client调用方法,因此我们将其添加到core.cljs

(ns ^:figwheel-always modern-clj-web.core
  (:require [cljs-http.client :as http]))

(println (http/get "/contacts"))

您应该看到#object[cljs.core.async.impl.channels.ManyToManyChannel] 。 那是什么疯狂???

这是我们进入core.async的时间。 处理来自Javascript的异步网络调用的最常见方法是使用回调或Promise。 core.async方法是使用通道。 它使您的代码看起来更像是一系列同步调用,并且更容易推理。 因此, http/get函数返回一个通道,当响应到达时,将在该通道上发布结果。 为了接收该消息,我们需要使用<! 功能。 由于这阻塞了,所以我们也需要像go语言一样用go宏包围这个调用。 因此,获取联系的正确方法如下所示:

(:require
...
  [cljs.core.async :refer [<! >! chan]])

(go
  (let [response (<! (http/get "/contacts"))]
    (println (:body response))))

添加Om组件

在不引入任何结构的情况下处理前端代码可能很快成为一场噩梦。 在2015年末,我们在该领域基本上拥有两个主要的JS框架:Angular nad React。 ClojureScript范例(功能编程,不可变数据结构)非常适合React哲学。 简而言之,React应用程序由将数据作为输入并渲染HTML作为输出的组件组成。 输出不是真实的DOM,而是所谓的虚拟DOM ,它有助于计算从当前视图到更新视图的差异。

在很多人的反应在ClojureScript我喜欢的包装使用OM-工具 ,以减少一些冗长。 让我们将其介绍到我们的project.clj

:dependencies 
     ...
   [org.omcljs/om "0.9.0"]
   [prismatic/om-tools "0.3.12"]

要渲染“ hello world”组件,我们需要在core.cljs添加一些代码:

(:require 
   ...
            [om.core :as om]
            [om-tools.core :refer-macros [defcomponent]]
            [om-tools.dom :as dom :include-macros true]))

(def app-state (atom {:message "hello from om"}))

(defcomponent app [data owner]
  (render [_]
    (dom/div (:message data))))

(om/root app app-state
         {:target (.getElementById js/document "main")})

这里发生了什么? Om的主要概念是将整个应用程序状态保持在一个全局原子中 ,这是Clojure的状态管理方式。 因此,我们将此app-state映射(包装在atom )作为参数传递给om/root ,该参数将组件安装到实际DOM中(来自index.html <div id="main"/> )。 该app组件仅显示:message值,因此您应该看到“来自om的问候”。 如果您正在运行fighweel ,则可以更改消息值,并且该消息值应立即更新。

最后,让我们与Om建立联系:

(defn get-contacts []
  (go
    (let [response (<! (http/get "/contacts"))]
      (:body response))))

(defcomponent contact-comp [contact _]
  (render [_]
    (dom/li (str (:firstname contact) " " (:lastname contact)))))

(defcomponent app [data _]
  (will-mount [_]
    (go
      (let [contacts (<! (get-contacts))]
        (om/update! data :contacts contacts))))
  (render [_]
    (dom/div
      (dom/h2 (:message data))
      (dom/ul
        (om/build-all contact-comp (:contacts data))))))

因此, contact-comp仅呈现单个联系人。 我们使用om/build-all使所有联系人在全局状态下的:contacts字段中可见。 最棘手的部分–当app组件即将被安装到DOM时,我们will-mount使用will-mount生命周期方法从服务器获取联系人。

同样,在出现任何问题的情况下, 此提交应为工作版本。

而且,如果您喜欢Om,我强烈建议您使用官方教程和“ 零至Om”系列。

翻译自: https://www.javacodegeeks.com/2015/10/clojure-web-development-state-of-the-art-part-2.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值