zoukankan      html  css  js  c++  java
  • Clojure Web 开发 (一)

    使用Clojure做Web开发需要的工具链还是比较特殊的,本文主要描述一下其中牵涉到的框架。

    需要指出的是,Clojure可以把自己封装成jar包供java调用,因此最坏情况下还是可以用java servlet来调用Clojure的库的,但是这显然不是我想要达到的效果,因此本文的基本出发点是,核心语言用Clojure,需要调用java库的情况。

    首先要介绍的就是Ring    API文档

    Ring是一个Clojure Web程序库,有点类似与Java的servlet。为什么要用Ring呢?Wiki里面列了几个好处:

    • Write your application using Clojure functions and maps
    • Run your application in a auto-reloading development server
    • Compile your application into a Java servlet
    • Package your application into a Java war file
    • Take advantage of a large selection of pre-written middleware
    • Deploy your application in cloud environments like Amazon Elastic Beanstalk and Heroku

    事实上,Ring是大部分Clojure的Web Framework的基础。包括了:Compojure、Moustache和Noir。

    真正在开始用Ring之前,首先要介绍的就是Leiningen。这个玩意也是个挺牛b的东西,而且作者也比较有意思,用户问答文档里面全面嘲笑了Ant和Maven,虽然Leiningen就是基于他们的。按照我现在的理解,基本上,用这个玩意,只要你指定好了依赖关系,它就会自动下载对应的库,并且放在正确的地方,然后还可以编译你的项目,执行你的项目。下面我们用的所有库都是用Leiningen实现的。

    -------------

    RING

    使用leiningen创建一个项目:

    lein new hello-world
    cd hello-world

    紧接着就要修改project.clj,指定依赖关系。

    (defproject hello-world "1.0.0-SNAPSHOT"
    :description "FIXME: write"
    :dependencies [[org.clojure/clojure "1.2.0"]
    [org.clojure/clojure-contrib "1.2.0"]
    [ring/ring-core "0.3.4"]
    [ring/ring-jetty-adapter "0.3.4"]])

    然后调用deps来告诉leiningen下载需要的数据:

    lein deps

    接着修改项目文件夹src目录下的core.clj文件如下:

    (ns hello-world.core)

    (defn handler [request]
    {:status 200
    :headers {"Content-Type" "text/html"}
    :body "Hello World"})

    之后便可以调用

    lein repl

    调用出REPL,接着就可以在命令行中启动服务器

    => (use 'ring.adapter.jetty)
    => (use 'hello-world.core)
    => (run-jetty handler {:port 3000})

    在Ring的抽象中,一个web程序分为4个部分,Handler、Request、Response、MiddleWare

    其中Handler即为定义web程序的函数,该函数只有一个参数:一个代表了Http请求的Map,最后返回一个代表HTTP返回值的map。比如:

    (defn what-is-my-ip [request]
    {:status 200
    :headers {"Content-Type" "text/plain"}
    :body (:remote-addr request)})

    Request也就是http请求也是一个Map,下面主要描述了其自带的key的情况。在ring中,可以使用middleware添加用户自定义的key:

    • :server-port The port on which the request is being handled.
    • :server-name The resolved server name, or the server IP address.
    • :remote-addr The IP address of the client or the last proxy that sent the request.
    • :uri The request URI (the full path after the domain name).
    • :query-string The query string, if present.
    • :scheme The transport protocol, either :http or :https.
    • :request-method The HTTP request method, which is one of :get, :head, :options, :put, :post, or :delete.
    • :content-type The MIME type of the request body, if known.
    • :content-length The number of bytes in the request body, if known.
    • :character-encoding The name of the character encoding used in the request body, if known.
    • :headers A Clojure map of lowercase header name strings to corresponding header value strings.
    • :body An InputStream for the request body, if present.
    Response与Reqeust类似,包含了三个Key:
    • :status The HTTP status code, such as 200, 302, 404 etc.
    • :headers A Clojure map of HTTP header names to header values. These values may either be strings, in which case one name/value header will be sent in the HTTP response, or a collection of strings, in which case a name/value header will be sent for each value.
    • :body A representation of the response body, if a response body is appropriate for the response's status code. The body can be one of four types:
      • String The body is sent directly to the client.
      • ISeq Each element of the seq is sent to the client as a string.
      • File The contents of the referenced file is sent to the client.
      • InputStream The contents of the stream is sent to the file. When the stream is exhausted, the stream is closed.
    Middleware是一个高阶函数,该函数第一个参数是一个handler,给该函数做一些处理之后,返回一个新的handler函数。比如:
    (defn wrap-content-type [handler content-type]
    (fn [request]
    (let [response (handler request)]
    (assoc-in response [:headers "Content-Type"] content-type))))
    而在Ring中,通常使用宏:-> 来将多个middleware串联起来,形成:Ring?
    Ring中如何产生Response。
    Ring提供了ring.util.response来帮助生成一下response。但事实上,我们通常会使用专门的render库来生成返回数据,这里先不表,只列出一下Ring提供的Response函数 (API文档):
    (response "Hello World")

    (-> (response "Hello World")
    (content-type "text/plain"))

    (redirect "http://example.com")

    (file-response "readme.html" {:root "public"})

    (resource-response "readme.html" {:root "public"})

    ring也支持cookie和session。最重要的是Ring支持交互式的开发,这个也是Lisp的强项。

    进行交互式开发的三种方法,我们这里主要引述一下使用lein-ring插件的方法:

    1,首先在project.clj文件中指明:

    :dev-dependencies [[lein-ring "0.4.5"]]

    2, 运行lein deps,下载对应的库

    3,在Project.clj文件最后添加:

    :ring {:handler your-app.core/handler}))

    4,调用下面命令启动服务器:

    lein ring server

    5,该服务器会自动重新加载src中任何修改过的文件。



    介绍了Ring之后,我们需要了解,大部分情况下我们不需要在Ring之上写web程序,因为已经有人帮我们弄了一些框架,这些框架能够极大的简化开发流程,这些框架中比较流行的包括:

    • Compojure: A concise DSL to generate Ring handler functions
    • Moustache: A micro DSL to wire Ring handlers and middlewares
    • fjord: A minimal Ring app framework
    • clocks: Clojure Web DSL build on top of compojure, ring and scripture
    • Ringfinger: RESTful resources with multiple outputs (HTML, XML, JSON), database and email abstraction, pre-made authorization system (form-based + HTTP Basic), security middleware, etc.
    • Noir: A micro-framework that allows you to rapidly develop websites in Clojure.
    下一篇我们将主要介绍Compojure以及render lib。





  • 相关阅读:
    Android源码之Gallery专题研究(2)
    Android源码之Gallery专题研究(1)
    Android UI 优化——使用HierarchyViewer工具
    如何打开USB OTG功能:
    JavaSE入门学习5:Java基础语法之keyword,标识符,凝视,常量和变量
    Multiply Strings
    android动态控制组件的位置、大小和新的动画
    linux系统编程:线程同步-信号量(semaphore)
    imx6q GPIO功能的用法
    NoSQL数据库概览及其与SQL语法的比較
  • 原文地址:https://www.cnblogs.com/mmjx/p/2220774.html
Copyright © 2011-2022 走看看