这是我的“ 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

Clojure Web开发–最新技术–第2部分相关推荐

  1. clojure 开发工具_Clojure Web开发–最新技术–第2部分

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

  2. Clojure Web 开发 (一)

    使用Clojure做Web开发需要的工具链还是比较特殊的,本文主要描述一下其中牵涉到的框架. 需要指出的是,Clojure可以把自己封装成jar包供java调用,因此最坏情况下还是可以用java se ...

  3. Clojure Web 开发 -- Ring 使用指南

    在 Clojure 众多的 Web 框架中,Ring 以其简单统一的 HTTP 抽象模型脱颖而出.Ring 充分体现了函数式编程的思想--通过一系列函数的组合形成了一个易于理解.扩展的 HTTP 处理 ...

  4. web 开发最新技术

    1.Woocommerce  :WooCommerce是全球最受欢迎的开源免费电子商务系统,已超过8712025次下载,全球系统占有率已超过29%,很多外贸行业和在线商城都会选择这个插件作为得力的助手 ...

  5. Web开发人员必读的12个网站

    The more you actually create, the more you'll learn.(创造的越多,学习的越多),世界上有无数个开发人员会在网上分享他们的开发经验,我们无法向所有人学 ...

  6. 用于Web开发的8 个最好的跨平台编辑器

    1) Best Cross Platform IDE - Brackets Brackets是一个在前端Web开发和设计人员中最流行的开放源码IDE/代码编辑器之一.它拥有一些实用工具能够将HTML ...

  7. 在web开发中,为什么前端比后端更得到转行程序员的青睐?

    通过各大招聘网站上都可以看出,前端工程师是一个很大的缺口,很多企业愿意用高薪来聘请优秀的前端开发工程师.前端在互联网中越来越受到大家的青睐,所以,近几年学前端的人也逐渐增多.具体前端比后端有哪些可见优 ...

  8. 为什么说 Web 开发永远不会退出历史舞台?

    早在 PC 崛起之际,Web 从蹒跚学步一路走到了主导市场的地位,但是随着移动互联网时代的来临,业界曾有不少人猜测,"Web 应该被杀死,App 才是未来".不过时间是检验真理的唯 ...

  9. [转载] Python Web开发—进阶提升 490集超强Python视频教程 真正零基础学习Python视频教程

    参考链接: 在Python中创建代理Web服务器 2 Python Web开发-进阶提升 490集超强Python视频教程 真正零基础学习Python视频教程 [课程简介] 这是一门Python We ...

最新文章

  1. 《Effective Java》读书笔记--创建和销毁对象
  2. Lucene 的四大索引查询 ——bool 域搜索 通配符 范围搜索
  3. public、protected、default、private区别
  4. Spring 事务用法示例与实现原理
  5. AI:人工智能概念之机器学习中常用算法的思维导图集合(非常经典、建议收藏)之详细攻略
  6. 蓝桥杯 历届试题 分考场(DFS+枚举)
  7. backgroundworder 简单使用
  8. 如何清空android ListView控件的内容
  9. ncbi查找目的基因序列_NCBI gene: 基因相关信息查询
  10. python3记录(2)— if __name__ == '__main__'
  11. 使用CURL出现certificate verify failed错误的解决方法
  12. 暴力破解QQ空间设置的问题
  13. numpy与scipy安装
  14. 【物理学】扫描隧道显微镜(Scanning Tunneling Microscope)
  15. 独木舟上的旅行(贪心算法)
  16. 次模优化·第〇集:简介
  17. mac正常连wifi,无法解析域名
  18. java 统一日志_基于log4j实现统一日志管理
  19. 如何一键生成字幕,如何快速处理生肉资源?借助whisper语音识别系统生成.srt字幕文件 手把手教学在Windows、CPU版本下whisper的安装与使用,快速上手!
  20. 应用及实例,在信用卡业务中的数据挖掘技术分析

热门文章

  1. 2007noip提高组初赛总结
  2. WEB编程开发常用的代码[转]
  3. Passper for PDF v3.6.1.1
  4. layui外部引入_layui use 定义js外部引用函数的方法
  5. Mercury mw150us(8188eu) debian wireless driver
  6. 前端云原生——微信小程序云服务配置
  7. 3-动态规划:数字三角形
  8. html自动请求favicon,浏览器默认请求的favicon.ico文件,可能带来的问题
  9. 学python必须得英语精通吗_Python无用武之地?只能说你是真的没有精通Python语言(附教程)...
  10. Linux系统磁盘分区及挂载 - fdisk