C помощью Snap я создал небольшой демонстрационный проект, который я представляю по ходу текста. Местами в тексте будет встречаться дословный перевод документации.
Официальный сайт
Погружение в Snap |
Установка snap через cabal
#: sudo cabal update#: sudo cabal install snap
Настройки параметров системы Ubuntu
Snap хранит свои исполняемые бинарные файлы в папке ~/.cabal/bin (snap к примеру), по этому для удобства их использования в файл ~/.bashrc следует добавить строчку:PATH=$HOME/.cabal/bin:$PATH
Создание каркаса типового Snap проекта
#: mkdir myproject#: cd myproject
#: snap init
команда snap init создает шаблон типового проекта в текущей директории.
Сборка проекта:
$: sudo cabal install
Запуск:
#: myproject -p 8000
Теперь по адресу http://localhost:8000/ должен откликаться созданый сайт.
Файловая структура созданного проекта
dist/log/
resources/
static/
templates/
src/
Site.hs
Main.hs
Application.hs
Попробую объяснить назначение файлов в папке src
Файл main.hs - это скелет проекта. В файле Application.hs определяется модуль Application, который связан с обработкой ответов сервера и который используется в файле Site.hs. Application.hs используется для расширения стандартного Snap обработчика HTTP запросов. Site.hs - это основной исходный код проекта, роутинг, контроллеры и т.п.
Обработка url адресов в файле Site.hs задается следующим образом:
site :: Application ()
site = route [ ("/", index)
, ("/echo/:stuff", echo)
]
<|> serveDirectory "resources/static"
Url адресс "/" относится к функции-обработчику index, "/echo/:stuff" к функции-обработчику echo. Обе эти функции выполняют роли контроллеров.
Фрагмент url адреса отмеченный двоеточием (":") - захватываемое значение параметра stuff. Значение этого параметра можно получить в дальнейшем с помощью rqParams или getParam (как и параметры передаваемые через POST и GET методы).
Вторая половина отделенная от основной части "<|>" будет переправлять на содержимое папки resources/static/.
Дословно оператор "<|>" в монаде Snap означает "try a, and if it fails, try b".
К примеру файл style.css будет искаться в resources/static/. Если он там не найдется метод serveDirectory вынудит Snap выдать ответ "404 Not Found".
Функция/метод/обработчик echo выглядит следующим образом
echo :: Handler App App ()
echo = do
message <- decodedParam "stuff"
heistLocal (bindString "message" (T.decodeUtf8 message)) $ render "echo"
where
decodedParam p = fromMaybe "" <$> getParam p
Здесь функция decodedParam выступает в качестве обёртки над методом getParam. В качестве аргумента передается ей имя параметра заданного в роутинге ("stuff"), но можно и передать и имя параметра post при необходимости.
С помощью метода heistLocal используем полученное значение для построения страницы с помощью шаблона "echo" (render "echo").
А при помощи метода bindString подменяем параметр в шаблоне <message/> на значение (T.decodeUtf8 message).
Snap использует систему шаблонизации Heist. Довольно гибкая и на оф. сайте представлено достаточно документации.
В предыдущем примере указанный шаблон echo располагается в файле resources/templates/echo.tpl, который представляет из себя html файл с расставленными полями подстановки/параметрами.
Поля подстановки имеют вид ${key} или <key/>
Вот так выглядит шаблон echo:
<html> <body> <div id="content"> <h1>Is there an echo in here?</h1> </div> <p>You wanted me to say this?</p> <p>"<message/>"</p> <p><a href="/">Return</a></p> </body> </html>Усложним типовой проект.
Добавим на главную страницу ("/") форму, которая при отправке данных будет:
- сохранять данные в файле -> Вызов монады IO в монаде Snap
- выдавать страницу ответа -> Передача на страницу данных методом POST
import System.IO import qualified Data.ByteString as BS ... -- пример на обработку post параметров ($_POST[]) и вызова монады IO из монады Snap (Понадобится чтобы сохранить данные в файл) command3post :: Handler App App () command3post = do input_name <- decodedPost "firstname" -- ByteString second_name <- decodedPost "secondname" liftIO $ appendFile "output.txt" (((T.unpack . T.decodeUtf8. BS.concat ) [input_name, " : " ,second_name])++"\n") -- Пояснение справа на лево: -- BS.concat - слияние списка элементов ByteString -- T.unpack . T.decodeUtf8 - преобразуем ByteString в String -- appendFile - добавляет строку в файл -- liftIO - преобразует монаду IO в монаду Snap heistLocal (bindString "firstname" (T.decodeUtf8 input_name)) $ render "formrezult" where decodedPost p = fromMaybe "" <$> getParam pА список маршрутов приведем к следующему виду:
routes :: [(ByteString, Handler App App ())] routes = [ ("/", index) , ("formaction", command3post) , ("/echo/:stuff", echo) , ("", with heist heistServe) , ("", serveDirectory "resources/static") ]В файл resources/templates/index.tpl добавить
<form method="post" action="formaction"> <p>First name: <input type="text" name="firstname"/></p> <p>Second name: <input type="text" name="secondname"/></p> <input type="submit" value="send"/> </form>Создать файл resources/templates/formrezult.tpl
<!DOCTYPE HTML> <html> <head> <title>Form request Page</title> </head> <body> <div id="content"> <h1>Form Rezult</h1> </div> <p>Thank you <firstname/></p> <p><a href="/">Return on main page</a></p> </body> </html>Вот и все. Проект можно собирать и запускать.
Скачать проект целеком.
Комментариев нет:
Отправить комментарий