Разработка простого веб сервиса
| |
Ingvord | Date: Wednesday, 17.02.2010, 18:42 | Message # 1 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Итак, дорогие друзья, предположим вы, а точнее мы, решили забацать новый интернет сервис... С чего начать? Ну, во-первых, стоит оценить перспективность проекта... положим проект весьма перспективен. Во-вторых, необходимо прикинуть инфраструктуру... В-третьих, выбрать техническую базу (программную, равно как и аппаратную) Далее увидим по ходу дела, подозреваю, что потребуется реализовать хотя бы beta версию, и с этим идти по Миру искать инвестора.... но до этого ещё далеко. Здесь рассмотрим техническую сторону вопроса, т.е. предполагается, что проект действительно перспективный. На остальном попытаемся отсановиться по подробнее.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Wednesday, 24.02.2010, 13:30 | Message # 2 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Так как в итоге планируется разработать простенький веб-сервис (даже без регистрации). Точнее страничку, на которой пользователь по запросу сможет получить интересующую его информацию. Вся бизнес логика данного сервиса уместиться в паре сервлетов Поразмыслив немного, пришли к выводу, что лучшим вариантом инфраструктуры будет следующая связка: javascriptMVC + tomcat + MySQL. JavaScriptMVC - навороченный фреймворк для разработки сайтов (точнее тонких клиентов) на javascript. Подробнее тут. Мы остановились на версии 1.5.5, так как на мой взгляд она наиболее оптимальна. Tomcat довольно легковесный servlet контейнер, что нам и требуется. Мы взяли версию 6.20 В качестве транспортного протокола между сервером и клиентом решили взять JSONP. Опять же на мой взгляд с ним гораздо приятнее работать чем с XML, как на серверной стороне так и на клиентской (JQuery forever ) тут отличная статья для начинающих. MySQL - что тут сказать? Всё очевидно. Даже бесплатных хостов с поддержкой MySQL море. Собственно этот факт и стал решающим. Итак, с инфраструктурой и программной реализацией определились. По поводу аппаратной: на данный момент особо сказать нечего, ясно что это будет некий хост с tomcat и MySQL.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Thursday, 25.02.2010, 17:20 | Message # 3 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Итак мы подошли к самому главному - непосредственно разработке. С чего начать? Ну видимо начать придёться с пустого листа. Заходим в свою любимую IDE (jIDEA в частности) и создаём пустой maven2 проект. Так как мы разрабатываем веб сервис, фактически web приложение, необходимо указать maven'у сей факт: в pom.xml добавляем строчку "<packaging>war</packaging>" в описание проекта. Подробнее про maven war plugin можно почитать тут. Структура проект при этом должна быть следующая: / |--src |--main | |--java | |--javascript | |--webapp | |--WEB-INF | |--web.xml |--test В папку javascript распаковываем содержимое архива javascriptMVC. Далее настраиваем tomcat в IDE. В jIDEA Run->Edit Configuration->'+'->tomcat->local. На вкладке server указываем путь к установке tomcat (желательно чтобы в пути не было пробелов). На вкладке Deployment указываем наш war'ник. Итак рабочее место в целом готово. Мы пока не подключили Data Sources, сделаем это позже. Важно что теперь можно запустить tomcat из под IDE. Следующим шагом необходимо правильно организовать сборку проекта. Так как щас кроме WEB-INF/web.xml в нашем war ничего нет. Самым простым решением является просто копирование содержимого из javascript в webapp. Однако - это не совсем правильно, так как таким образом в наш war попадёт много лишнего и весить это чудо будет порядка 9 метров. Оптимальное решение - перед тем как архивировать проект в war из под maven. Необходимо запускать поставляемый вместе с javascriptMVC компрессор кода и копировать в webapp только то, что действительно нужно для работы сайта. Как это сделать? Ответ - с помощью ant: Создаем build.xml в root проекта рядом с pom.xml. Ниже приведены примеры запуска разных команд. Пример запуска компрессора [утилита, поставляемая вместе с javascriptmvc для сжатия приложения. Подробнее тут](под Windows): Code <target name="compile-javascript"> <echo>Compressing javascript...</echo> <echo>Executing: js.bat apps/app/compress.js</echo> <exec dir="${src}" executable="cmd.exe"> <arg value="/c"/> <arg value="js.bat"/> <arg line="apps\\app\\compress.js"/> </exec> </target> и копируем только то, что необходимо: Code <echo>Copying source files...</echo> <copy todir="${build}/jmvc" overwrite="true"> <fileset dir="${src}/jmvc"> <include name="include.js"/> </fileset> </copy> <copy todir="${build}/apps" overwrite="true"> <fileset dir="${src}/apps"> <exclude name="**/compress.js"/> <exclude name="**/test.js"/> <exclude name="**/app_production.html"/> </fileset> </copy> <copy file="${src}/apps/app/app_production.html" tofile="${build}/index.html"/> Если всё сделано правильно, то теперь, при запуске tomcat, http://localhost:8080 должен показывать стартовую страничку javascriptMVC. И наш war весить порядка 25 Kb. Однако работать с клиентской стороной удобнее локально, просто запуская javascript/index.html в браузерею Обратите внимание, что мы копируем app_production.html в webapp/index.html, это сделано для того чтобы не забывать деплоить war на сервер с javascript в продакшн моде (<script language="javascript" type="text/javascript" src="../../jmvc/include.js?app,production"></script>).
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Friday, 26.02.2010, 14:25 | Message # 4 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Ура! Теперь можно набросать примерчки 'Hello World!' для освоения процесса разработки под javascriptMVC. Итак шаг 1. Создаём папочку hello_world в /src/main/javascript/apps. Добавляем hello_world.js в /src/main/javascript/apps с примерно следующим содержимым: Code include.resources(); include.plugins('controller','view');
include(function(){ include.models(); include.controllers(); include.views(); }); В папку hello_world добавляем hello_world_production.html: Code <html> <head> <title>Hello World</title> </head> <body> <div id="content"></div> <script language="javascript" type="text/javascript" src="jmvc/include.js?hello_world,production"></script> </body> </html> Копируем содержимое этого файла с заменой production -> development в /src/main/javascript/index.html Далее создаём файл /hello_world/compress.js: Code MVCOptions = { onload: false, compress_callback: function(total){ var compressed = MVCOptions.collect_and_compress(total); MVCOptions.save('apps/hello_world/production.js', compressed); print("Compressed to 'apps/hello_world/production.js'."); var app = new MVCObject.DApplication(total, "hello_world"); app.generate(); print("Generated docs."); }, env : "compress" }
load('jmvc/rhino/compression/htmlparser.js'); load('jmvc/rhino/compression/env.js'); load('jmvc/rhino/compression/helpers.js');
window.location = 'index.html'; Проверить что всё сделано правильно можно собрав проект с нуля (ant+maven[package]) и задеплоив его на сервер. Должна открыться пустая страница с title'ом Hello World
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Friday, 26.02.2010, 14:55 | Message # 5 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Продолжаем работу над Hello World. Шаг 2. Мы хотим получить простенькое web приложение, из двух страничек. На первой - пользователю предлагается в вести имя. После нажатия кнопки пользователю выдаётся привестсвие: Hello, <имя>!!! Итак. Создаём контроллер hello_world_controller.js (/src/main/javascript/controllers): Code HelloWorldController = MVC.Controller.extend('main',{ load: function(params){ document.getElementById('content').innerHTML = new View({url:'views/hello_world_main.ejs'}).render(); } }); Незабываем зарегистрировать его в hello_world.js [include.controllers('hello_world');] Далее создаём views/hello_world_main.ejs: Code <input type="text" id="txtName" size="7" value="Enter your name"/> <input type="button" id="btnOk" value=" OK "/> View также необходимо зарегистрировать в hello_world.js [include.views('views/hello_world_main');]. Это необходимо для того, чтобы при компиляции javascript (когда мы вызываем компрессор) все наши view добавились в production.js, что существенно ускоряет их загрузку непосредственно на сайте. Итак если теперь мы запустим наше приложение, то на страницу должны будут добавиться два input поля: текст и кнопка. Напомню, что такие вещи можно проверять локально, просто открыв index.html в браузере. Продолжаем. Теперь нам необходимо добавить реакцию на нажатие кнопки. Создаём контроллер button_controller.js: Code BtnController = MVC.Controller.extend('btnOk',{ click: function(params){ var txtName = document.getElementById('txtName'); var userName = txtName.value;
document.getElementById('content').innerHTML = new View({url:'views/hello_world_response.ejs'}).render({data:userName}); } }); И views/hello_world_response.ejs: Code <h1>Hello, <%= data%>!!!</h1> Собираем, проверяем что всё работает как ожидалось, радуемся. Итак мы получили готовое к бою приложение Про .ejs можно почитать тут. Про привязку контроллеров к элементам на странице тут. Домашнее задание - написать функциональный тест нашего приложения.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Friday, 26.02.2010, 15:38 | Message # 6 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Прикрепляю архив с исходниками проекта.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Monday, 01.03.2010, 15:17 | Message # 7 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Итак продолжим разработку нашего сервиса. Сегодня мы хотим расширить наше приложение, подключив к обработке запроса серверную сторону. В терминах нашего приложения Hello World это означает, что мы хотим отправлять имя пользователя на сервер, изменять его там (например, дописывать слово 'glorious' перед именем) и возвращать обратно. Напоминаю, в качестве транспортного протокола было решено использовать JSONP. Бизнес логику на сервере реализовывать с помощью servlet технологии. Шаг 1. На клиентской стороне разрабатываем модель. Про модели в javascriptmvc можно почитать тут. Создаём hello_world_model.js: Code Task = MVC.Model.extend('task', { processName: function(name,callback){ jQuery.getJSON("http://localhost:8888/hello_world_servlet?name=" + name + "&callback=?", callback); }},{}) Не забываем про регистрацию новых сущностей в hello_world.js Code include.resources(); include.plugins('controller','view','model');
include(function(){ include.models('hello_world_model'); include.controllers('hello_world','button'); include.views('views/hello_world_main','views/hello_world_response'); }); Всё бы хорошо, да только нашу модель пока нельзя никак использовать. jQuery не определён. А теперь внимание - важный момент: подключение плагина в javascriptmvc. Почему это важно? Так как в терминах javascriptmvc любая функциональность, должна быть оформлена в виде плагина. Это не прихоть разработчиков, так на много одобнее поддерживать и развивать ваш код. Что можно назвать плагином? - Например, это может быть коннектор к базе данных (если вы разрабатываете .hta приложение) итд итп Поехали в /src/main/javascript/jmvc/plugins создаём папочку jquery, куда помещаем необходимую библиотеку (в нашем случае jquery-1.4.2.min.js). Далее создаём файл setup.js: Code include('jquery-1.4.2.min'); Регистрируем плагин в hello_world.js [include.plugins('controller','view','model','jquery');]
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Thursday, 11.03.2010, 16:34 | Message # 8 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Итак продолжим расширять наше риложение за счёт подключения серверной логики. Создаём сервлет. В IDEE на вкладке web тыкаем правой кнопкой мыши и выбираем New -> Servlet. Далее в диалоге вписываем имя сервлета (MyServlet), package какой понравиться, в нашем случае - test. Помещаем его в src/main/java. В параметрах сервлета указываем Display Name - JsonServlet. После этого назначаем servlet-mapping в web.xml: Code <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>MyServlet</servlet-name> <display-name>JsonServlet</display-name> <servlet-class>test.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/json</url-pattern> </servlet-mapping> </web-app> Добавляем servlet-api:2.3 dependency в pom.xml: Code dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.3</version> </dependency> Реализуем наш сервлет: Code protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { String jsonData = getDataAsJson(request.getParameter("name")); String output = request.getParameter("callback") + "(" + jsonData + ");";
response.setContentType("text/javascript");
PrintWriter out = response.getWriter(); out.println(output); } Code private String getDataAsJson(String name) { JSONObject o = new JSONObject();
try { o.put("name", "Glorious " + name); } catch (JSONException e) { return "request failed"; }
return o.toString(); } Для того чтобы всё скомпилировалось нам также потребуется добавить новую maven dependency - json:20090211 Итак серверную часть завершили. Теперь необходимо реализовать вызов нашего сервлета с клиента. Для этого правим button_controller#click: Code click: function(params){ var txtName = document.getElementById('txtName'); var userName = txtName.value;
Task.process(userName,function(response){ var changedUserName = response.name;
document.getElementById('content').innerHTML = new View({url:'views/hello_world_response.ejs'}).render({data:changedUserName}); }); } Итак, если теперь пересобрать проект и запустить tomcat после ввода имени мы получим следующий ответ: Hello, Glorious Ingvord!!! Pretty good, isn't it?
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Friday, 19.03.2010, 15:13 | Message # 9 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Прикрепляю исходники.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Friday, 19.03.2010, 15:25 | Message # 10 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Существенной частью любой программы является обработка ошибок. © Однако количество повторяющихся ошибок можно снизить, если старательно покрывать разрабатываемую функциональность тестами. Попробуем проделать сие полезное дело применительно к нашему веб сервису. Начнём с клиентской части. Подробнее про тестирование в javascriptMVC можно почитать тут. В качестве демонстрации мы разработаем два простых теста: unit и функциональный. Начнём с функционального теста: В src/main/javascript/test/functional создаём файл btnOk_controller_test.js: Code new Test.Controller('btn',{ test_click: function(){ var inpTxt = document.getElementById('txtName'); inpTxt.value = 'Ingvord';
var action = this.Click('#btnOk');
this.assert("Hello, Glorious Ingvord!!!",document.getElementById('content').innerText) } },'functional'); Обратим внимание, что имя файла нашего теста ("btnOk_") совпадает с именем контроллера, описанного в файле button_controller.js:1 [BtnController = MVC.Controller.extend('btnOk',{]. А имя самого теста ("btn") совпадает с префиксом имени инстанса контроллера ("BtnController"). Эти манипуляции с именами позволяют javascriptMVC подгружать наши тесты, даже если мы не описали файл test.js в src/main/javascript/apps/hello_world. Чего мы действительно не сделали Итак запускаем наше приложение в тестовом режиме. Для этого необходимо: 1) заменить 'development' на 'test' в index.html; 2) запустить серверную часть (собрать war и запустить tomcat). Далее открываем index.html в любимом браузере, соглашаемся разрешить поп-апы. После чего откроется консоль тестирования javascriptMVC, с примерно следующим содержанием: Quote You are running "hello_world" in the test environment. Test Controller not found at "test/functional/main_controller_test.js" Loading: "test/functional/btnOk_controller_test.js" There is no application test file at: "apps/hello_world/test.js" Use it to include your test files. Test includes: include.unit_tests('product') include.functional_tests('widget') Переходим на вкладку "Functional" и прогоняем тесты. Радостно радуемся тому что все тесты прошли.
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
Ingvord | Date: Monday, 03.01.2011, 18:13 | Message # 11 |
TLA Leader
Group: Администраторы
Messages: 189
Status: Offline
| Пример простой интеграции JavaScriptMVC 3.0.4 с maven. Для сборки (очистки) JavaScriptMVC приложения используется ant скрипт из build.xml. В pom.xml на package и clean вызываются соответствующие команды ant. Примечание: в архиве отсутствует сам JavaScriptMVC фреймворк, так что для корректной работы примера потребуется распаковать javascriptmvc-3.0.4 в <root>/src/main/javascriptmvc
"Я интересуюсь будущим потому, что собираюсь провести там всю свою жизнь" Чарльз Кеттеринг Коммунизм и Ислам — такие разные идеологии, а методы и результаты одни и те же
|
|
| |
|