Введение
Для многих разработчиков Java часто является синонимом ужасно занудных корпоративных приложений. Она ассоциируется с многочисленными конфигурационными файлами формата XML, шаблонным кодом и т.д. Поэтому как правило вместо нее разработчики используют динамические языки (такие как Ruby, Python, PHP) для разработки своих проектов, особенно для простых утилит, мэш-апов и т.п.
Однако в среде Java многое изменилось за последние несколько лет. Появилось много фрейморков освобождающих разрабочика от бремени корпоративных («энтерпрайзных») приложений. Grails вероятно — один из лучших. Он основан на Groovy, динамическом языке на платформе Java. Groovy создан специально для Java-программистов и переход на него максимально безболезненый. Grails используе хорошо известные, надежные и эффективные библиотеки Java (Spring, Hibernate и т.п.) для выполнения всей тяжелой работы. Существует также система плагинов и плагины для почти для всех широко используемых библиотек Java.
В этом посте я раскажу, как сделать мэш-ап из Twitter'а и Google Maps в течении всего 20 минут. Конечный результат будет выглядеть примерно следующим образом:
Подготовка среды разработки
Сначала неплохо бы убедится, что установлена правильная версия JDK. Лучше всего просто скачать последнюю версию JDK здесь.
Установите ее и установите переменную среды
JAVA_HOME
так чтоб она указывала на каталог установки.Затем скачайте последний релиз Grails отсюда.
Распакуйте архив в любое место, а затем установите переменную среды
GRAILS_HOME
чтоб она указывала на каталог в который был распакован архив. Также убедитесь что подкаталог bin/
каталога установки Grails упоминается в переменной окружения PATH
.После выполнения вышеупомянутых шагов будет возможно запускать команды Grails в консоли. Можно набрать
grails help
чтоб проверить это. Должен появится список доступных команд.Основные понятия
Grails основан на шаблоне проектирования MVC. Модель представлена в domain-классах, контроллеры классами контроллеров, отображение — GSP страницами. В этом проекте используются только классы контроллеров и GSP, так как модель предоставляется Twitter API.
Не помешает прочитать краткое руководство пользователя для начала. Дополнительную информацию можно получить в руководстве пользователя. В частности, в этом посте пригодится информация о контроллерах и GSP.
Создание каркаса приложения
Одна из возможностей Grails освобождающая разработчика от «энтерпрайзного» бремени Java — возможность автоматически генерировать каркас основного приложения.
Чтобы сделать это просто наберите:
grails create-app geo_twitter
Это создаст приложение
geo_twitter
в текущем рабочем каталоге. Перейдите в этот каталог для всех дальнейших шагов.Приступая к работе с Google Maps
Интеграция Google Maps проста и хорошо поддерживается Google. Однако вам сначала нужно получить ключ API, чтобы получить доступ ко всем услугам. Не бойтесь — это просто, быстро и бесплатно.
Для начала неплохо бы подчистить основной шаблон разметки (layout) — можно удалить логотип Grails и т.д. Откройте
grails-app/views/layout/main.gsp
и исправьте так, чтоб он выглядел следующим образом:<html>
<head>
<title><g:layoutTitle default="Grails" /></title>
<link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
<g:layoutHead />
</head>
<body>
<g:layoutBody />
</body>
</html>
Потом отредактируйте
grails-app/views/index.gsp
чтоб интергрировать Google Maps как то так:<html>
<head>
<title>Welcome to GeoTwitter!</title>
<meta name="layout" content="main" />
<script src="www.google.com/jsapi?key=YOUR_GOOGLE_MAPS_API_KEY" type="text/javascript"></script>
<script type="text/javascript">
google.load("maps", "2.x");
google.load("jquery", "1.3.1");
google.setOnLoadCallback(function() {
$(document).ready(function() {
var map = new GMap2(document.getElementById('map'));
var vinnitsa = new GLatLng(49.2325477, 28.4744695); // Replace this by coordinates of your own city ;)
map.setCenter(vinnitsa, 8);
map.addControl(new GLargeMapControl());
});
});
</script>
</head>
<body>
<div id="map" style="width:800px; height:600px">
</div>
</body>
</html>
Конечный результат будет выглядеть как-то так:
Форма для Twitter'а и верстка
Добавьте простую форму с именем пользователя на страницу
index.gsp
.<div class="form">
<form action="" id="twitter">
<p>
<label>twitter id:</label>
<input type="text" id="name" name="name" value=""/>
</p>
<p class="submit">
<input type="submit" value="Map my friends!">
</p>
</form>
</div>
Затем замените основные стили в
web-app/css/main.css
на что-то вроде этого:body {
font-family: Verdana, Helvetica, sans-serif;
margin: 1em;
}
#map {
position: absolute;
width: 800px;
height: 600px;
left: 19em;
top: 1em;
}
.form {
border: 1px dashed gray;
width: 15em;
padding: 0.5em;
}
.form label {
width: 7em;
display: block;
float: left;
}
.form input {
width: 10em;
}
.form .submit {
padding-left: 7em;
}
Вы получите нечто подобное:
Немного особой Grails-магии серверной логики
Чтобы сделать что-то на самом деле работает, нужно добавить серверную логику. Сначала установим плагин Grails для работы с Twitter.
grails install-plugin twitter
Теперь нам нужно создать контроллер, который будет выдавать список друзей из Twitter с информацией об их местонахождении и т.д.
grails create-controller Twitter
Команда выше сгенерирует файл
grails-app/controllers/TwitterController.groovy
со скелетом контроллера. Его надо заменить реализацией контроллера который будет выдавать информацию о друзьях в формате JSON. Он будет также обращаться к сервису геокодирования, чтобы получать координаты на карте по имени данной местности.import grails.converters.*
class TwitterController {
// Google Maps API key
static def API_KEY = "Insert your Google Maps API key here"
// TwitterService instance will be injected into this variable by Spring
def twitterService
def friendsJson = {
// Get friends of given user
def friends = getFriends(params.name)
// Render friends list as JSON
render(friends as JSON)
}
private def getFriends(String userName) {
def friends = twitterService.getFriends(params.name)
// Return only the needed fields for each user and retrieve coordinates for location
friends.collect { it ->
[
screenName: it.screenName,
name: it.name,
pictureUrl: it.profileImageUrl as String,
bio: it.description,
status: it.status?.text,
coords: getCoordsFromLocation(it.location)
]
}
}
/**
* This method gets coordinates on map for given location string.
*/
private def getCoordsFromLocation(String location) {
if (location) {
if (location.contains("iPhone:")) {
// There can be coords specified in location
// like iPhone: 39.035248,-77.138687
location = location.replace("iPhone: ", "")
def parts = location.split(",")
return [latitude: parts[0], longitude: parts[1]]
} else {
// Encode location as URL
def encodedLocation = URLEncoder.encode(location)
// Call web service by retrieving URL content
def response =
"maps.google.com/maps/geo?q=${encodedLocation}&output=xml&key=${API_KEY}".toURL().getText()
// Parse response XML
def root = new XmlSlurper().parseText(response)
if (root.Response.Placemark.size() == 1) {
def coords = root.Response.Placemark.Point.coordinates.text()
def parts = coords.split(",")
if (parts.size() > 1) {
return [latitude: parts[1] as Double, longitude: parts[0] as Double]
}
}
}
}
// No coordinates are determined
return null
}
}
Использование AJAX для получения данных от сервера
После того как мы написали логику контроллера, нужно написать JS код, который будет получать данные с сервера и отображать их на карте. Этот код можно разместить в обработчике отправки формы, но сначала надо задать правильное действие для формы:
action="${createLink(controller: 'twitter', action: 'friendsJson'}"
Потом добавим обработчик в
index.gsp
, наподобие:google.load("maps", "2.x");
google.load("jquery", "1.3.1");
google.setOnLoadCallback(function() {
$(document).ready(function() {
// Create and configure Google Map control
var map = new GMap2(document.getElementById("map"));
var vinnitsa = new GLatLng(49.2325477, 28.4744695);
map.setCenter(vinnitsa, 4);
map.addControl(new GLargeMapControl());
// Add form submit handler
var form = $("#twitter");
form.submit(function() {
$.getJSON(form.attr("action") + "?" + form.serialize(), function (data) {
// Clear all markers
map.clearOverlays();
// Loop through friends list and add markers to map
$.each(data, function (i, item) {
if (item.coords) {
var marker = new GMarker(new GLatLng(item.coords.latitude, item.coords.longitude));
map.addOverlay(marker);
var popup = '<img style="width: 48px; height:48px;" src="' + item.pictureUrl + '">' +
item.name + ' (' + item.screenName + ') <br>' +
item.bio + '<br>' + item.status;
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(popup);
});
}
});
});
// Indicate that form should not actually be submitted
return false;
});
});
});
Теперь, когда вы введете имя и нажмете кнопку «Map my friends!» получите следующую картину:
Демо и исходники
- Исходники демо-проекта можно взять в репозитории GitHub
- Демо можно посмотреть на нашем демо-сервере (смотрите ссылку в блоге на английском), если он не упадет, а он таки упадет :)