代码之家  ›  专栏  ›  技术社区  ›  Vinn

DB中的HTML未注入hunchentoot路由

  •  0
  • Vinn  · 技术社区  · 2 年前

    我的应用程序中有许多从数据库获取信息的路线。在一种特定的情况下,我从数据库中获取HTML内容,以便使用 cl-who

    我不知道为什么数据库中的内容不会呈现。页面的其余部分运行良好。

    当我测试手动将html添加到路由中(硬编码的html标记)时,它工作得很好。在我使用 (second (get-content)) (见下文)DB中的html不会添加到模板中。

    我错过了什么?

    数据库宏

    (defmacro access-db(db &body query)
      `(progn
         (clsql:connect ,db)
         (unwind-protect (progn ,@query)
          (disconnect-db ,db)))) 
    

    页面宏

    (defmacro defpage ((&key title) &body content)
      `(cl-who:with-html-output-to-string 
           (*standard-output* nil :prologue t :indent t)
         (:html
          :xmlns "http://www.w3.org/1999/xhtml"
          :xml\:lang "en"
          :lang "en"
          (:head
           (:meta
        :http-equiv "Content-Type"
        :content "text/html;charset=utf-8")
           (:title
        ,(format nil "~A" title))
           (:link :type "text/css" 
              :rel "stylesheet"
              :href "/styles.css"))
          (:body :class "whole-page" 
             (:div :class "site-articles"
               (:div :class "article-body"
                 (:div :class "on-page-title"
                       (:h1 :class "main-header" ,title))
                 ,@content))))))
    

    Hunchetoot路线

    (define-easy-handler (test-page :uri "/wow") ()
      (let ((content
          (bt:make-thread
           (lambda ()
             (second (get-content))))))
        (defpage (:title "Main One") 
          (bt:join-thread content))))
    

    获取内容使用 access-db 函数,并返回数据库中第一个项目的列表。标题和HTML。html在该列表中排名第二。

    获取内容

    (defun get-content ()
      (let ((blogs
          (access-db *PSQL-CONNECT-INFO*
            (clsql:query
             "select * from content"))))
        (first blogs)))
    
    
    0 回复  |  直到 2 年前
        1
  •  0
  •   ignis volens    2 年前

    [免责声明:我无法让CLSQL工作,而且无论如何都不想与数据库有任何关系,所以这个答案是关于其他事情的问题。]

    我想你可能会对宏感到困惑,但你的 defpage 宏被混淆了。

    CL-WHO的 with-html-output 做的就是 将流绑定到可以打印的变量 ,然后将其主体视为它和所有类似的宏(我认为HTOUT是第一个真正做到这一点的宏)所理解的隐式“html-lisp”语言。这意味着,如果要将输出发送到此流,则需要将其打印到此流。 with-html-output-to-string 只是以显而易见的方式将输出捕获到字符串中。

    以下是该宏的清理版本,名称更好( defpage 闻起来像是“定义页面”(define page),而这根本不是它所做的)。

    (defmacro with-output-to-standard-page ((&key (title "page")
                                                  (stream '*standard-output*)
                                                  (string-form 'nil))
                                            &body content)
      (let ((tv (make-symbol "TITLE")))
        `(let ((,tv ,title))
           (with-html-output-to-string (,var ,string-form :prologue t :indent t)
             (:html
              :xmlns "http://www.w3.org/1999/xhtml"
              :xml\:lang "en"
              :lang "en"
              (:head
               (:meta
                :http-equiv "Content-Type"
                :content "text/html;charset=utf-8")
               (:title (princ ,tv ,var))
               (:link :type "text/css" 
                :rel "stylesheet"
                :href "/styles.css"))
              (:body :class "whole-page" 
               (:div :class "site-articles"
                (:div :class "article-body"
                 (:div :class "on-page-title"
                  (:h1 :class "main-header"
                   (princ ,tv ,var)))
                 ,@content))))))))
    

    这种行为比你的行为更传统:

    (let ((title "foo"))
      (with-output-to-standard-page (:title title)
        ...))
    

    将起作用,并且

    (with-output-to-standard-page (:title (complicated-function-with-state))
      ...)
    

    将呼叫 complicated-function-with-state 只有一次。

    此外,如果您需要,还可以定义流变量和字符串形式:

    (with-output-to-standard-page (:var s)
      (princ "foo" s))
    

    将起作用。

    最后,它将内容放在首字母下面 h1 ,不在里面(和外面 on-page-title div 事实上),并将标题用于 h1

    所有这些都是在一个包中完成的,该包使用 CL-WHO , HUNCHENTOOT BORDEAUX-THREADS 以避免可怕的包前缀everwhere恐怖,并使代码可读。

    那么,如果我们更换 get-content 函数,因为没有SQL:

    (defun get-content ()
      (list 'nothing "my page content"))
    

    然后,将处理程序更正为 打印 流,这是关键问题

    (define-easy-handler (test-page :uri "/wow") ()
      (let ((content-thread
             (make-thread
              (lambda ()
                (second (get-content))))))
        (with-output-to-standard-page (:var p :title "Main One") 
          (princ (join-thread content-thread) p))))
    

    现在一切都会好起来的。


    看着你 access-db 宏观方面,几乎可以肯定,它也存在问题。

    首先,我称之为 with-db-access 因为 with-* 是这样的宏的一个常规名称(另一种可能是 accessing-db )。然后,它至少有一个问题,那就是它将对第一个参数进行乘法运算。它应该是这样的

    (defmacro with-db-access (db &body query)
      (let ((dbv (make-symbol "DB")))
        `(let ((,dbv ,db))
           (connect ,dbv)
           (unwind-protect
               (progn ,@query)
             (disconnect-db ,dbv)))))
    

    以避免该问题。

    请注意,使用Tim Bradshaw的 metatronic macros 。使用它,这将是:

    (defmacro/m with-db-access (db &body query)
      `(let ((<db> ,db))
         (connect <db>)
         (unwind-protect
             (progn ,@query)
           (disconnect-db <db>))))
    

    我的 with-output-to-standard-page 上面的宏将使用metatronic宏进行类似的简化。

    推荐文章