(:html

(:head

(:title 'Random numbers'))

(:body

(:h1 'Random numbers')

(:p (loop repeat 10 do (html (:print (random 1000)) ' '))))))

The macro version will be quite a bit more efficient than the emit-html version. Not only do you never have to generate an s-expression representing the whole page, also much of the work that emit-html does at runtime to interpret the s-expression will be done once, when the macro is expanded, rather than every time the code is run.

You can control where the output generated by both html and emit-html is sent with the macro with-html-output, which is part of the FOO library. Thus, you can use the with-html-output and html macros from FOO to rewrite random- number like this:

(defun random-number (request entity)

(with-http-response (request entity :content-type 'text/html')

(with-http-body (request entity)

(with-html-output ((request-reply-stream request))

(html

(:html

(:head (:title 'Random'))

(:body

(:p 'Random number: ' (:print (random 1000))))))))))

HTML Macros

Another feature of FOO is that it allows you to define HTML 'macros' that can translate arbitrary forms into HTML s-expressions that the html macro understands. For instance, suppose you frequently find yourself writing pages of this form:

(:html

(:head (:title 'Some title'))

(:body

(:h1 'Some title')

... stuff ...))

You could define an HTML macro to capture that pattern like this:

(define-html-macro :standard-page ((&key title) &body body)

`(:html

(:head (:title ,title))

(:body

(:h1 ,title)

,@body)))

Now you can use the 'tag' :standard-page in your s-expression HTML, and it'll be expanded before being interpreted or compiled. For instance, the following:

(html (:standard-page (:title 'Hello') (:p 'Hello, world.')))

generates the following HTML:

<html>

<head>

<title>Hello</title>

</head>

<body>

<h1>Hello</h1>

<p>Hello, world.</p>

</body>

</html>

Query Parameters

Of course, generating HTML output is only half of Web programming. The other thing you need to do is get input from the user. As I discussed in the 'A 30-Second Intro to Server-Side Web Programming' section, when a browser requests a page from a Web server, it can send query parameters in the URL and post data, both of which act as input to the server-side code.

AllegroServe, like most Web programming frameworks, takes care of parsing both these sources of input for you. By the time your published functions are called, all the key/value pairs from the query string and/or post data have been decoded and placed into an alist that you can retrieve from the request object with the function request-query. The following function returns a page showing all the query parameters it receives:

(defun show-query-params (request entity)

(with-http-response (request entity :content-type 'text/html')

(with-http-body (request entity)

(with-html-output ((request-reply-stream request))

(html

(:standard-page

(:title 'Query Parameters')

(if (request-query request)

(html

(:table :border 1

(loop for (k . v) in (request-query request)

do (html (:tr (:td k) (:td v))))))

(html (:p 'No query parameters.')))))))))

(publish :path '/show-query-params' :function 'show-query-params)

If you give your browser a URL with a query string in it like the following:

http://localhost:2001/show-query-params?foo=bar&baz=10

you should get back a page similar to the one shown in Figure 26-4.

Figure 26-4. http://localhost:2001/show-query-params? foo=bar&baz=10

To generate some post data, you need an HTML form. The following function generates a simple form, which submits its data to show-query-params:

(defun simple-form (request entity)

(with-http-response (request entity :content-type 'text/html')

(with-http-body (request entity)

(let ((*html-output* (request-reply-stream request)))

(html

(:html

Вы читаете Practical Common Lisp
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату