03 配置 Clojurescript 支持環(huán)境屈藐,并完成登錄功能

03 配置 Clojurescript 支持環(huán)境锄奢,并完成登錄功能.png

配置 project.clj

添加相關(guān)依賴

文件:project.clj

;; ClojureScript 庫
[org.clojure/clojurescript "1.10.439"]

配置前端編譯器和 Figwheel

文件:project.clj

(defproject soul-talk "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}


  :dependencies [
            ;; Clojure 主運(yùn)行時庫
            [org.clojure/clojure "1.9.0"]

            ;; Ring 庫
            [ring "1.7.1"]

            ;; 基于 Ring 的 Response 簡化工具庫
            [metosin/ring-http-response "0.9.1"]

            ;; 常用中間件集合
            [ring/ring-defaults "0.3.2"]

            ;; 路由庫
            [compojure "1.6.1"]

            ;; Selmer 模板庫
            [selmer "1.12.0"]

            ;; ring 前端庫中間件
            [ring-webjars "0.2.0"]

            ;; JQuery 依賴,Bootstrap 需要
            [org.webjars/jquery "3.3.1-1"]

            ;; Bootstrap 
            [org.webjars/bootstrap "4.0.0-2"]

            ;; Popper 
            [org.webjars/popper.js "1.14.1"]

            ;; 字體庫
            [org.webjars/font-awesome "5.5.0"]

            ;; ClojureScript 庫
            [org.clojure/clojurescript "1.10.439"]]


  :plugins [
      ;; 基于 Lein 的 Ring 插件
      [lein-ring "0.12.4"]
      ;; Cljsbuild 編譯器插件
      [lein-cljsbuild "1.1.7" :excludes [[org.clojure/clojure]]]
      ;; figwheel 環(huán)境插件
      [lein-figwheel "0.5.17-SNAPSHOT"]]

  
  ;; Ring 插件不通過 main 函數(shù)啟動挂疆,只需要指定一個入口 Handler
  :ring {:handler soul-talk.core/app}
  
  
  ;; 不使用插件的時候州丹,程序仍然從 main 函數(shù)啟動
  ;; 啟用 ClojureScript 之后给梅,要關(guān)閉預(yù)編譯 AOT
  :main ^:skip-aot soul-talk.core
  
  
  ;; 指定源文件和資源文件路徑
  :source-paths ["src"]
  :resource-paths ["resources"]

  ;; 為 figwheel 指定 CSS 路徑
  :figwheel {:css-dirs ["resources/public/css"]}

  ;; 設(shè)置自動清理路徑
  :clean-targets ^{:protect false} [
    :target-path 
      ;; 下面的路徑根據(jù) cljsbuild 配置查找
      [:cljsbuild :builds :dev :compiler :output-dir]
      [:cljsbuild :builds :dev :compiler :output-to]]


  ;; 設(shè)置 cljsbuild 編譯器參數(shù)
  :cljsbuild {
    :builds {
      ;; 開發(fā)環(huán)境
      :dev {
        ;; 源代碼目錄
        :source-paths ["src-cljs"] 
        ;; 開啟 figwheel                    
        :figwheel     true                             
        :compiler {
          ;; 主命名空間
          :main                   soul-talk.core  
          ;; 依賴文件路徑
          :asset-path             "js/out"    
          ;; 最終輸出的文件        
          :output-to              "resources/public/js/main.js"   
          ;; 臨時文件輸出路徑
          :output-dir             "resources/public/js/out"
          ;; 不優(yōu)化    
          :optimizations          :none
          ;; 源代碼
          :source-map-timestamp   true  
          ;; 打印格式               
          :pretty-print           true}}}}      


  :profiles {
        :user {
            :dependencies []
            :plugins [[lein-ancient "0.6.15"]]}}
            
)

配置中間件

默認(rèn)的 default 中間件會啟用“防止跨域攻擊”中間件,先關(guān)閉他

文件:src/soul_talk/core.clj

;; 組合中間件
(def app
  (-> app-routes
      (wrap-nocache)
      (wrap-reload)
      (wrap-webjars) 
      
      ;; 常用中間件珍昨,關(guān)閉跨域攻擊功能
      (wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))))

靜態(tài)資源

創(chuàng)建 base.html 靜態(tài)頁面父模板

注意:要引入 js/main.js 自定義腳本

文件:resources/base.html

<!DOCTYPE html>

<html lang="zh-cmn-Hans">

<head>
    <!-- 必須的標(biāo)簽 -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <title>使用 Clojure 建立個人網(wǎng)站</title>

    <!-- 樣式表 -->
    {% style "/assets/bootstrap/css/bootstrap.min.css" %}
    {% style "/assets/font-awesome/css/all.css" %}
    <link rel="stylesheet" href="/css/site.css">

    <!-- 可擴(kuò)展的樣式表 -->
    {% block page-css %}
    {% endblock %}
</head>

<body>

<div class="container-fluid">
    <!-- 可擴(kuò)展的區(qū)域 -->
    {% block content %}

    {% endblock %}
</div>

<!-- scripts -->
{% script "/assets/jquery/jquery.min.js" %}
{% script "/assets/font-awesome/js/all.js" %}
{% script "/assets/bootstrap/js/bootstrap.min.js" %}


<!-- 引入自定義腳本-->
<script src="/js/main.js" type="text/javascript"></script>


<!-- 可擴(kuò)展腳本-->
{% block page-script %}

{% endblock %}
</body>
</html>

修改 index.html

注意:頁面接收 Handler 傳來的一個變量县耽,用于顯示登錄狀態(tài)订咸,但不是真正的 Session

文件:resources/index.html

<!-- 擴(kuò)展 base.html -->
{% extends "base.html" %} 


<!-- 擴(kuò)展 content 部分的內(nèi)容 -->
{% block content %}
<div class="container">

    <header class="blog-header py-3">
        <div class="row flex-nowrap justify-content-between align-items-center">
            <div class="col-4 pt-1">
                <a class="text-muted" href="#">訂閱</a>
            </div>
            <div class="col-4 text-center">
                <a class="blog-header-logo text-dark" href="#">Soul Talk</a>
            </div>
            
            <!-- 根據(jù)登錄狀態(tài)顯示不同內(nèi)容 -->
            <div class="col-4 d-flex justify-content-end align-items-center">
                {% if session.identity %}
                <span class="navbar-text">歡迎你 {{session.identity}} </span>
                <a class="btn btn-sm btn-outline-secondary" href="/logout">退出</a>
                {% else %}
                <a class="btn btn-sm btn-outline-secondary" href="/login">登錄</a>
                {% endif %}
            </div>

        </div>
    </header>

    <div class="nav-scroller py-1 mb-2">
        <nav class="nav d-flex justify-content-between">
            <a class="p-2 text-muted" href="#">World</a>
            <a class="p-2 text-muted" href="#">U.S.</a>
            <a class="p-2 text-muted" href="#">Technology</a>
            <a class="p-2 text-muted" href="#">Design</a>
            <a class="p-2 text-muted" href="#">Culture</a>
            <a class="p-2 text-muted" href="#">Business</a>
            <a class="p-2 text-muted" href="#">Politics</a>
            <a class="p-2 text-muted" href="#">Opinion</a>
            <a class="p-2 text-muted" href="#">Science</a>
            <a class="p-2 text-muted" href="#">Health</a>
            <a class="p-2 text-muted" href="#">Style</a>
            <a class="p-2 text-muted" href="#">Travel</a>
        </nav>
    </div>

    <div class="jumbotron p-3 p-md-5 text-white rounded bg-dark">
        <div class="col-md-6 px-0">
            <h1 class="display-4 font-italic">Title of a longer featured blog post</h1>
            <p class="lead mb-0"><a href="#" class="text-white font-weight-bold">Continue reading...</a></p>
        </div>
    </div>
</div>

<main role="main" class="container">
    <div class="row">
        <div class="col-md-8 blog-main">
            <h3 class="pb-3 mb-4 font-italic border-bottom">
                From the Firehose
            </h3>

            <div class="blog-post">
                <h2 class="blog-post-title">Sample blog post</h2>
                <p class="blog-post-meta">January 1, 2014 by <a href="#">Mark</a></p>
                <ol>
                    <li>Vestibulum id ligula porta felis euismod semper.</li>
                    <li>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</li>
                    <li>Maecenas sed diam eget risus varius blandit sit amet non magna.</li>
                </ol>
                <p>Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis.</p>
            </div><!-- /.blog-post -->

            <div class="blog-post">
                <h2 class="blog-post-title">Another blog post</h2>
                <p class="blog-post-meta">December 23, 2013 by <a href="#">Jacob</a></p>

                <p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, </p>

            </div><!-- /.blog-post -->

            <div class="blog-post">
                <h2 class="blog-post-title">New feature</h2>
                <p class="blog-post-meta">December 14, 2013 by <a href="#">Chris</a></p>

                <p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p>
            </div><!-- /.blog-post -->

            <nav class="blog-pagination">
                <a class="btn btn-outline-primary" href="#">Older</a>
                <a class="btn btn-outline-secondary disabled" href="#">Newer</a>
            </nav>

        </div><!-- /.blog-main -->

        <aside class="col-md-4 blog-sidebar">
            <div class="p-3 mb-3 bg-light rounded">
                <h4 class="font-italic">About</h4>
                <p class="mb-0">Etiam porta <em>sem malesuada magna</em> mollis euismod. </p>
            </div>

            <div class="p-3">
                <h4 class="font-italic">Archives</h4>
                <ol class="list-unstyled mb-0">
                    <li><a href="#">March 2014</a></li>
                    <li><a href="#">February 2014</a></li>
                    <li><a href="#">January 2014</a></li>
                    <li><a href="#">December 2013</a></li>
                    <li><a href="#">November 2013</a></li>
                    <li><a href="#">October 2013</a></li>
                    <li><a href="#">September 2013</a></li>
                    <li><a href="#">August 2013</a></li>
                    <li><a href="#">July 2013</a></li>
                    <li><a href="#">June 2013</a></li>
                    <li><a href="#">May 2013</a></li>
                    <li><a href="#">April 2013</a></li>
                </ol>
            </div>

            <div class="p-3">
                <h4 class="font-italic">Elsewhere</h4>
                <ol class="list-unstyled">
                    <li><a href="#">GitHub</a></li>
                    <li><a href="#">Twitter</a></li>
                    <li><a href="#">Facebook</a></li>
                </ol>
            </div>
        </aside><!-- /.blog-sidebar -->

    </div><!-- /.row -->

</main><!-- /.container -->

<footer class="blog-footer">
    <p>Blog template built for <a >Bootstrap</a> by <a >@mdo</a>.</p>
    <p>
        <a href="#">Back to top</a>
    </p>
</footer>


<!-- 這里擴(kuò)展 content 結(jié)束 -->
{% endblock %}

創(chuàng)建 login.html

文件:resources/login.html

{% extends "base.html" %}
{% block page-title %}Soul Talk Login {% endblock %}
{% block page-css %}
<link rel="stylesheet" href="/css/login.css">
{% endblock %}
{% block content %}
<div class="container text-center">
    <form class="form-signin" action="/login" method="post" id="loginForm">
        <img src="" alt="" class="mb-4">
        <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
        <label for="email" class="sr-only">Email Address</label>
        <input type="text" id="email" name="email" class="form-control" placeholder="Email Address" required autofocus/>
        <label for="password" class="sr-only">Password</label>
        <input type="password" id="password" name="password" class="form-control" placeholder="Password" required />
        <div class="check-box mb-3">
            <label>
                <input type="checkbox" value="Remember me">記住我
            </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">登錄</button>
        <p class="mt-5 mb-3 text-muted">&copy: 2018</p>
    </form>
</div>
{% endblock %}

ClojureScript

新建 src-cljs 目錄,在這個目錄下新建 soul_talk/core.cljs 文件

(ns soul-talk.core)

(defn main []
  (enable-console-print!)
  (prn "Hello, Clojurescript"))

(main)

Clojure

添加登錄相關(guān)處理器

修改 src/soul_talk/core.clj酬诀,添加處理登錄請求的處理器

;; 渲染 index.html 頁面
(defn home-handle [request]
  (parser/render-file "index.html"  request))
  
  
;; Get 登錄頁面
(defn login-page [request]
  (parser/render-file "login.html" {}))


;; Post 登錄數(shù)據(jù)
(defn handle-login [email password request]
  (if (and (= email "jiesoul@gmail.com") (= password "12345678"))
    ;; 如果登錄成功脏嚷,則在 Session 中添加信息
    (home-handle (assoc-in request [:session :identity] email))
    ;; 如果失敗,則返回登陸頁面瞒御,并向頁面中傳送錯誤信息
    (login-page (assoc request :error "用戶名密碼不對"))))

注意一:這里的 session 不是系統(tǒng) session父叙,而只是一個傳給模板的變量,僅僅對渲染頁面起作用肴裙,其他頁面就看不到這個 session 了趾唱。如果要使用系統(tǒng) session,必須在返回的鍵值對中加入 :session 鍵:

(-> (redirect "/") (assoc :session {:identity email}))

注意二:這里 Post 完畢后直接返回了 Index.html 的 HTML 蜻懦,因此 URL 還是 http://localhost:3000/login 甜癞,這是不正確的做法,應(yīng)該重定向到 /index.html

添加退出登錄處理器

退出流程:清空 Session 信息宛乃,跳轉(zhuǎn)到首頁即可

(ns soul-talk.core
  (:require ......
    ;; 引入重定向函數(shù)
    [ring.util.response :refer [redirect]]))
    
    
;; 退出登錄悠咱,清空 Session ,調(diào)整到首頁
(defn handle-logout [request]
  (do
    (assoc request :session {})
    (redirect "/")))

注意:這里清除的同樣也只是一個模板變量征炼,而不是系統(tǒng) session 析既。如果要清楚系統(tǒng) session ,需要將返回鍵值對中的 :session 鍵設(shè)置為空:

(-> (redirect "/") (assoc :session {}))

配置路由

將登錄和退出處理器添加到路由規(guī)則中

文件:src/soul_talk/core.clj

(ns soul-talk.core
  (:require ......
    ;; 引入相關(guān)函數(shù)
    [compojure.core :refer [routes GET defroutes POST]]))
    
    
(def app-routes
  (routes
    (GET "/" request (home-handle request))
    (GET "/about" [] (str "這是關(guān)于我的頁面"))
    
    
    ;; 登錄路由谆奥,Get 和 POST
    (GET "/login" request (login-page request))
    (POST "/login" [email password :as req] (handle-login email password req))
    
    ;; 退出登錄路由==========
    (GET "/logout" request (handle-logout request))

    (route/not-found error-page)))

啟動程序

啟動服務(wù)

lein ring server-headless

編譯 ClojureScript

lein figwheel

設(shè)置 Git 忽略文件

因?yàn)?ClojureScript 會下載很多依賴文件眼坏,同時產(chǎn)生很多編譯輸出文件,包括最終的輸出文件 main.js 酸些,都設(shè)置在了 /resources/public/js 中宰译。這些都是動態(tài)的,不需要 Git 跟蹤魄懂。

另外 FigWheel 的日志文件 figwheel_server.log 也不需要發(fā)布沿侈,因此都可以放到忽略文件中

figwheel_server.log
/resources/public/js
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逢渔,隨后出現(xiàn)的幾起案子肋坚,更是在濱河造成了極大的恐慌乡括,老刑警劉巖肃廓,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诲泌,居然都是意外死亡盲赊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進(jìn)店門敷扫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哀蘑,“玉大人诚卸,你說我怎么就攤上這事』媲ǎ” “怎么了合溺?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缀台。 經(jīng)常有香客問我棠赛,道長,這世上最難降的妖魔是什么膛腐? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任睛约,我火速辦了婚禮,結(jié)果婚禮上哲身,老公的妹妹穿的比我還像新娘辩涝。我一直安慰自己,他們只是感情好勘天,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布怔揩。 她就那樣靜靜地躺著,像睡著了一般脯丝。 火紅的嫁衣襯著肌膚如雪沧踏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天巾钉,我揣著相機(jī)與錄音翘狱,去河邊找鬼。 笑死砰苍,一個胖子當(dāng)著我的面吹牛潦匈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赚导,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼茬缩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吼旧?” 一聲冷哼從身側(cè)響起凰锡,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎圈暗,沒想到半個月后掂为,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡员串,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年勇哗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寸齐。...
    茶點(diǎn)故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡欲诺,死狀恐怖抄谐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扰法,我是刑警寧澤蛹含,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站塞颁,受9級特大地震影響挣惰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜殴边,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一憎茂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锤岸,春花似錦竖幔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛋铆,卻和暖如春馋评,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刺啦。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工留特, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玛瘸。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓蜕青,卻偏偏與公主長得像,于是被迫代替她去往敵國和親糊渊。 傳聞我的和親對象是個殘疾皇子右核,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,606評論 2 350

推薦閱讀更多精彩內(nèi)容