Clojure创建网站系列一(路由):使用Reitit替换Ring

为什么使用Reitit?嗯~ o(* ̄▽ ̄*)o,因为快!就是因为快!参数解构、参数合法性检查简便,and so on

使用lein创建新工程:

$ lein new lein-reitit default
$ cd lein-reitit

补全工程结构:

lein-reitit
  ├─env
  │  ├─dev
  │  │  ├─clj
  │  │  └─resources
  │  └─prod
  │      └─resources
  ├─src
  │  └─lein_reitit
  │      ├─routes
  │      └─services
  └─test
     └─lein_reitit

用你心爱的IDE打开工程,添加reitit的依赖(project.clj)配置项目,依赖使用最新的版本,目前是0.4.2(目前遇到不少新版本有bug的项目,报莫名奇怪错误时,试试换用低版本):

(require 'cemerick.pomegranate.aether)
(cemerick.pomegranate.aether/register-wagon-factory!
 "http" #(org.apache.maven.wagon.providers.http.HttpWagon.))

(defproject lein-reitit "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [aero "1.1.6"] #_"read config"
                 [javax.servlet/javax.servlet-api "4.0.1"]
                 [ring/ring-jetty-adapter "1.8.0"]
                 [metosin/reitit "0.4.2"] #_"routes"]
  :repl-options {:init-ns lein-reitit.core}
  :profiles {:dev {:source-paths   ["env/dev/clj"]
                   :resource-paths ["env/dev/resources"]}
             :prod {:resource-paths ["env/prod/resources"]}}
  :main lein-reitit.core/start
  :aliases {"reitit"  ["do" "clean" ["with-profile" "prod" "uberjar"]]}
  :repositories [["aliyun" "http://maven.aliyun.com/nexus/content/groups/public"]
                 ["clojars" "https://mirrors.tuna.tsinghua.edu.cn/clojars/"]])

编写core:

(ns lein-reitit.core
  (:require [reitit.ring :as ring]
            [reitit.coercion.spec]
            [reitit.swagger :as swagger]
            [reitit.swagger-ui :as swagger-ui]
            [reitit.ring.coercion :as coercion]
            [reitit.ring.middleware.muuntaja :as muuntaja]
            [reitit.ring.middleware.exception :as exception]
            [reitit.ring.middleware.multipart :as multipart]
            [reitit.ring.middleware.parameters :as parameters]
            [ring.adapter.jetty :as jetty]
            [muuntaja.core :as m]
            [clojure.java.io :as io])
  (:use [lein-reitit.routes
         [login :only [login]]])
  (:gen-class))

(def app
  (ring/ring-handler
   (ring/router
    [["/swagger.json"
      {:get {:no-doc true
             :swagger {:info {:title "lein-reitit"
                              :description "with reitit-ring"}}
             :handler (swagger/create-swagger-handler)}}]
     login
     ]
    {:data {:coercion reitit.coercion.spec/coercion
            :muuntaja m/instance
            :middleware [;; swagger feature
                         swagger/swagger-feature
                           ;; query-params & form-params
                         parameters/parameters-middleware
                           ;; content-negotiation
                         muuntaja/format-negotiate-middleware
                           ;; encoding response body
                         muuntaja/format-response-middleware
                           ;; exception handling
                         exception/exception-middleware
                           ;; decoding request body
                         muuntaja/format-request-middleware
                           ;; coercing response bodys
                         coercion/coerce-response-middleware
                           ;; coercing request parameters
                         coercion/coerce-request-middleware
                           ;; multipart
                         multipart/multipart-middleware]}})
   (ring/routes
    (swagger-ui/create-swagger-ui-handler
     {:path "/"
      :config {:validatorUrl nil
               :operationsSorter "alpha"}})
    (ring/create-default-handler))))

(defn start []
  (println "server starting...")
  (jetty/run-jetty #'app {:port 3000, :join? false})
  (println "server running in port 3000"))

创建路由(参考工程ring-swagger),现在没做路由封装,使用reitit原生方式:

(ns lein-reitit.routes.login
  (:require [lein-reitit.services.login :as login]))

(def login
  ["/login"
   {:swagger {:tags ["login api"]}}
   ["/auth"
    {:post {:summary "verify user's password"
            :parameters {:body {:username string?, :password string?}}
            :responses {200 {:body {:success boolean?}}}
            :handler #(login/auth (get-in % [:parameters :body]))}}]])

创建handler:

(ns lein-reitit.services.login)

(defn auth
  [{:keys [username password] :as params}]
  (println "params is =" params)
  {:status 200
   :body {:success (and (= username "test") (= password "123456"))}})

启动并测试:

$ lein run

browser> http://localhost:3000/index.html#!/login32api/post_login_auth

tips:reitit支持动态路由,但是解析速度会下降,开发阶段可以改造成动态路由,部署时采用静态路由。

个人感觉,至于reitit这么快,应该归咎于采用map形式,并且所有路由以高效的数据结构vector,详细改造在下一篇介绍

访问我查看源码传送Git

QQ群:667494487

 

你可能感兴趣的:(Clojure,Leiningen,clojure)