Groovy + JSON + Prototype in Action
Рубрика: Development, Groovy, Java, JavaScript/Ajax, MySQL | 6 April 2007, 18:53 |
Vadim Voituk
Дабы у читателя не возникало мысли, что Groovy подходит только для написания простеньких утилит и prebuild-скриптов предлагаю рассмотреть пример создания серверного приложения на Groovy с использованием коктейля Web2.0-ппопулярных технологий.
Предположим что нужно разработать сервис для получения информации о пользователе из некой базы данных.
Причем информацию необходмо получать в формате JSON – как-никак Web 2.0 на дворе.
План действий:
- Описываем необходимые требования
- Создаем базу данных и заполняем её тестовыми данными
- Создаем пул соединений к базе данных
- Описываем сущность User
- Создаем сервлет “Информация о пользователе” (ответ формате JSON)
- Создаем сервлет “Список пользователей”
- Создаем “клиентскую” часть, получающую данные от сервлета “Информация о пользователе”
Итак, для разработки нам необходимо:
- Сервлет-контейнер (я буду использовать Tomcat)
- Файл groovy-all-1.0.jar из дистрибутива Groovy
- Библиотека Json-lib от Andres Alminary …
- … для какой необходимы ezmorph-1.0.1.jar и commons-beanutils-core.jar из пакета commons-beanutils.
- JavaScript библиотека prototype.js
- СУБД MySQL и JDBC-драйвер к нему
Перед началом необходимо скопировать файлы groovy-all-1.0.jar и mysql-connector-java-5.0.4-bin.jar в директорию $TOMCAT_HOME/common/lib/.
По идее дожно быть достаточно положить его в WEB-INF/lib директорию своего web-приложения, но в таком случае у меня он не заработал, а желания искать причину у меня небыло.
Также копируем в WEB-INF/lib приложения commons-beanutils-core.jar, ezmorph-1.0.1.jar и json-lib-1.1-jdk15.jar
Создаем базу данных:
[sql] CREATE DATABASE jwap;[/sql]
и таблицу для хранения пользователей:
[sql]
CREATE TABLE `users` ( `id` int(10) unsigned NOT NULL auto_increment, `name` char(255) NOT NULL default '', `email` char(50) NOT NULL default '', `b_date` date NOT NULL default '0000-00-00', `icq` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`id`), UNIQUE KEY `u_name` (`name`) ) ENGINE=MyISAM
[/sql]
добавляем тестовые данные:
[sql]INSERT INTO users (name, email, b_date,icq) VALUES
(‘Vadim Voituk’, ‘vadim@microsoft.com’, ’1980-11-22′, 944328),
(‘Bill Gates’, ‘bill@microsoft.com’, ’1954-01-04′, 123456789)[/sql]
Создаем пул соединений к базе данных
Назовем его jdbc/MYSQLDB.
Для этого в META-INF/context.xml пишем следующее:
[xml]<?xml version=’1.0′ encoding=’utf-8′?>
<Context>
<Resource
name=”jdbc/MYSQLDB”
auth=”Container”
type=”javax.sql.DataSource”
username=”mysql_user”
password=”my-mysql-password”
driverClassName=”org.gjt.mm.mysql.Driver”
url=”jdbc:mysql://localhost/jwap”
validationQuery=”SELECT 1″
maxActive=”150″
maxIdle=”15″
/>
</Context>[/xml]
Создавать пул соединений не обязательно, но мне кажется что так будет удобнее.
Описываем сущность User:
[java]
class User {
int id;
String name;
String email;
int icq;
}
[/java]
На этом этапе хочется заметить что создавать сервлеты с помощью Groovy можно двумя способами: создавая подкласс javax.servlet.http.HttpServlet и с помощью GroovyServlet. Здесь мы рассмотрим оба варианта.
Создаем сервлет “Информация о пользователе”
[java]
import javax.servlet.http.*;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import groovy.sql.Sql;
import net.sf.json.JSONSerializer;
class UserInfo extends HttpServlet {
/**
* @see
*/
public void service(HttpServletRequest request, HttpServletResponse response) {
String id = request.getPathInfo();
if (!id?.startsWith("/") || id?.length()<=1) return;
id = id[1..id.length()-1];
def numId;
try { numId = id.toInteger(); } catch (NumberFormatException e) { return; }
PrintWriter out = response.getWriter();
InitialContext initCont = new InitialContext();
DataSource dataSource = (DataSource)initCont.lookup("java:comp/env/jdbc/MYSQLDB");
def db = Sql.newInstance(dataSource);
try {
db.eachRow("SELECT * FROM users WHERE id='${numId}'") {
def user = new User(id:it.id, name:it.name, email:it.email, icq:it.icq);
out.println JSONSerializer.toJSON(user, ["metaClass"] as String[])
}
} catch (Exception e) {
out.println("Error: " + e.message);
} finally {
db.close();
out.close();
}
}
}
[/java]
в web.xml дописываем:
[xml]
<servlet>
<servlet-description>Return user info</servlet-description>
<servlet-name>UserInfo</servlet-name>
<servlet-class>com.point.heartbeat.UserInfo</servlet-class>
</servlet>
<servlet-maping>
<servlet-name>UserInfo</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-maping>
[/xml]
переходим по адресу http://myserver.com:8080/groovy/user/1 и вуаля!:
{"email":"vadim@microsoft.com","name":"Vadim Voituk","id":1,"icq":944328}
Мы получили JSON представление обьекта User с id=1.
Тут был показан классический метод создания сервлетов, применимый в Java.
Теперь на примере сервлета “Список пользователей” покажу как легко создавать сервлеты используя для этого возможности Groovy.
Для этого дописываем в web.xml такие строки:
[xml]
<servlet>
<servlet-description>Groovy servlet</servlet-description>
<servlet-name>GroovyServlet</servlet-name>
<servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GroovyServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
[/xml]
Далее создаем в WebContent-директории (!!!) скрипт:
[java]
import javax.naming.InitialContext;
import javax.sql.DataSource;
import groovy.sql.Sql;
response.setContentType("text/html;charset=utf-8");
InitialContext initCont = new InitialContext();
DataSource dataSource = (DataSource)initCont.lookup("java:comp/env/jdbc/MYSQLDB");
def db = Sql.newInstance(dataSource);
try {
db.eachRow("SELECT * FROM users ORDER BY id") {
out.println "
$it.name
"
}
out.println '''
.user_item {Cursor: pointer;}
''';
} catch (Exception e) {
out.println("Error: " + e.message);
} finally {
db.close();
out.close();
}
[/java]
Теперь переходим по адресу http://mserver.com:8080/groovy/UsersList.groovy и видим список пользователей
И напоследок добавим возможность при клике на имя пользователя смотреть подробную информацию о нем.
Тут нам понадобится JavaScript библиотека Prototype. Можно конечно написать все на чистом JavaScript но после 4-х месяцев использования Prototype я стал ленивым и предпочитаю не изобретать велосипед.
Всю логику на JavaScript я перенес в файл my.js.
А результат всех мытарств выглядит вот так невзрачно:
Полные исходные коды примеров.
Вышло все немного сумбурно, но я готов отвечать на вопросы и вносить коррективы :)
Tweet
Ты знаешь ДР Билла Гейтса!
Нет, не знаю. Просто ввел случайную дату.
На самом деле Бил Гейтс родился 25 октября 1955 г.
Случайно не задавался вопросом об UTF-8 в Groovy сервлете?
Я просто кучу интернета уже извел, а воз и ныне там… Проблема в том, что исходный текст .groovy файла в UTF8 подвергается доп. перекодировке при выводе…
schleicher: Очень даже задавался :) У меня была та же проблема.
Для по умолчанию response output stream идет в кодировке отличной от UTF-8 (сразу и не вспомню какой именно), пототому его нужно перевести с UTF-8.
Делается это приблизительно так:
[java]OutputStream os = response.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os , “UTF-8″);
PrintWriter o = new PrintWriter(osw);
[/java]
и далее везде вместо println “Hello world!” писать o.println “Hello world!”.
Как это работает можно посмотреть в исходных кодах примера.
В кодировке дефолтной системной. В этой кодировке груви считывает файл, отчего собсно и все проблемы. При запуске или компиляции из консоли вроде как можно указывать кодировку, а вот в сервлете непонятно как это сделать…
я так понял, что устанавливая response.content-type мы перекодируем из системной кодировки в ту, что указали.
то есть корень зла – в считывании файла скрипта!
Я, балуясь с Jruby сервлетами, ходил по тем же граблям, пока не переписал org.jruby.RubyServlet считывание файла скрипта. А в Groovy это спрятано далеко в недра jar’a… вчера пытался добраться да спать сильно хотелось :-)
Твой способ тоже не совсем корректен. Данные из MySQL ты принимаешь в cp1251. А потом они автоконвертируются в UTF-8. А попробуй базу в UTF! А попробуй просто
o.print(“труляля”)
у меня во всяком случае выводит порушенный конвертацией текст.
Можешь привести ссылку на этот вопрос в groovy-user? и вообще, где этот groovy-user, может есть смысл читать? :-)
В принципе без разницы в какой кодировке у меня данные – на выходе из JDBC-дравера я их получаю в юникоде.
А вот насчет системной кодировке – тут ты прав.
Провел несколько тестов и убедился.
А читать рассылки groovy-user можно тут
http://www.nabble.com/codehaus—Groovy-f11866.html
Там же можно и задавать вопросы.
Если удасться что-то узнать по этому поводу – буду благодарен если сообщишь.
awesome article.
where can i get the english version
Why awesome?
There is no English version avaible.
You can ask your questions here.
В общем так. Все что касаемо UTF-8 решилось только написнием своего сервлета. Там же мне было нжуно маппить все запросы на один скрипт, чего нет в стандартном GroovyServlet. Буду рад, если проявишь внимание к моей статье:
http://schleicher.ru/blog/240.html
А что случилось с кодом? У меня почему-то он весь в одну строку.
Браузер: Firefox 3
Alno: вроде исправлено :)