PDF:

Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Hòa trộn công nghệ bên ngoài vào trong một ứng dụng Grails
Scott Davis
Tổng Biên tập
AboutGroovy.com
15 01 2010
Scott Davis cho bạn biết làm cách nào bạn có thể nhúng các bản đồ vào một ứng dụng Grails
sử dụng những dịch vụ Web và APIs sẵn có miễn phí trong bộ cài đặt mới nhất này của Làm chủ
Grails. Ông sử dụng ứng dụng mẫu lập kế hoạch-chuyến đi từ những cài đặt trước và đưa nó tới
mức tiếp theo bằng mã địa lí, Các bản đồ Google, và những dịch vụ Grails.
Xem thêm bài trong loạt bài này
Tôi đã xây dựng một ứng dụng lập kế hoạch-chuyến đi từ bài viết đầu tiên trong loạt bài này. Giờ
khung làm việc Người điều khiển-Khung nhìn-Mô hình (Model-View-Controller (MVC)) cơ bản đó
đang ở đây, ta sẵn sàng để hòa trộn với những kĩ thuật bên ngoài. Cụ thể, ta sẽ thêm một bản đồ.
Tôi có thể nói, "Tôi đang đặt một chuyến đi từ Denver tới Raleigh, với những điểm dừng ở San
Jose và Seattle dọc đường đi," nhưng một bản đồ sẽ giúp mô tả chuyến đi tốt hơn. Bạn có thể biết
rằng Seattle và Raleigh ở những phía đối diện nhau của nước Mỹ, nhưng một bản đồ giúp bạn hình
dung khoảng cách giữa hai thành phố này.
Cho bạn một ý tưởng ban đầu về ứng dụng gì sẽ làm ở phần cuối của bài viết này, hãy vào trang
http://maps.google.com và nhập mã IATA DEN trong hộp tìm kiếm. Bạn nên kết thúc ở Sân bay Quốc
tế Denver, như được biểu diễn trong Hình 1. (Biết thêm về những mã IATA, xem bài viết của tháng
trước.)
© Copyright IBM Corporation 2010
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Nhẫn hiệu đăng ký
Trang 1 của 19
developerWorks®
ibm.com/developerWorks/vn/
Hình 1. Sân bay Denver, nhờ Các bản đồ của Google
Bên cạnh việc hiển thị các sân bay của Mỹ bạn tạo một bảng HTML, lập kế hoạch-chuyến đi cũng
sẽ vẽ được các sân bay trên một bản đồ. Tôi sẽ sử dụng API Các bản đồ Google miễn phí trong bài
viết này. Bạn có thể sử dụng API Các bản đồ Yahoo! miễn phí hoặc bất kỳ cái nào khác (xem Tài
nguyên). Một khi bạn hiểu những điều cơ bản về bản đồ Web trực tuyến, bạn sẽ hiểu rằng các API
khác nhau có thể hoán đổi cho nhau một cách hợp lí. Trước khi bạn có thể ánh xạ một phần của
giải pháp, bạn cần hiểu làm thế nào để một chuỗi ba kí tự đơn giản như DEN biến đổi thành một
điểm trên bản đồ
Mã địa lí
Khi bạn nhập DEN vào Các bản đồ Google, ứng dụng thực hiện một phép biến đổi nhỏ đằng sau.
Bạn có thể nghĩ tới những địa phương về mặt địa chỉ đường phố như Đường 123 Main, nhưng các
bản đồ Google cần một điểm vĩ độ/kinh độ để hiển thị nó trên bản đồ. Hơn nữa bắt buộc bạn cung
cấp điểm vĩ độ/kinh độ của mình, nó dịch các địa chỉ người dùng có thể đọc được vào những vĩ độ/
kinh độ thay cho bạn. Phép biến đổi này được gọi là mã địa lí (geocoding) (xem Tài nguyên).
Về bài viết này
Grails là một khung làm việc phát triển Web hiện đại mà hòa trộn với các kỹ thuật Java™
quen thuộc như Spring và Hibernate với các thực hành đương thời như quy ước qua cấu hình.
Ghi vào Groovy, Grails cho bạn sự tích hợp liền một mạch với mã Java của bạn trong khi việc
thêm một cách mềm dẻo và linh động của một ngôn ngữ tập lệnh. Sau khi bạn học Grails, bạn
sẽ không bao giờ nhìn việc phát triển Web lại theo cách tương tự.
Một phép biến đổi tương tự xảy ra khi bạn lướt Web. Về kỹ thuật, cách duy nhất để liên lạc với một
máy chủ Web từ xa là địa chỉ IP của máy chủ cung cấp. May thay, bạn không cần nhập địa chỉ IP
của mình. Bạn nhập một URL thân thiện vào trình duyệt Web của bạn, và nó thực hiện việc gọi
máy chủ Hệ thống Tên Miền (Domain Name System (DNS)). Máy chủ DNS đổi URL thành địa chỉ
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 2 của 19
ibm.com/developerWorks/vn/
developerWorks®
IP tương ứng, và trình duyệt thực hiện kết nối HTTP tới máy chủ từ xa. Tất cả điều này là trong
suốt với người dùng. DNS thực hiện Web vô cùng dễ dàng để sử dụng. Những trình sinh mã địa lí
(geocoder) thực hiện việc tương tự cho các ứng dụng bản đồ dựa trên Web.
Tìm kiếm Web nhanh trên trình sinh mã địa kí miễn phí mang lại một số khả năng phù hợp với nhu
cầu mã hóa địa lí của những người lập kế hoạch chuyến đi. Cả Google và Yahoo! cung cấp các dịch
vụ mã địa lý như một phần tiêu chuẩn của các API của họ, nhưng với ứng dụng này, tôi sẽ sử dụng
dịch vụ mã địa lý miễn phí được cung cấp trên geonames.org (xem Tài nguyên). RESTful API của
nó cho phép tôi chỉ ra rằng tôi đang cung cấp một mã IATA thay vì một giới hạn tìm kiếm-văn bản
chung chung. Tôi không có gì chống lại các cư dân của Ord, Ned., nhưng tôi quan tâm nhất là Sân
bay Quốc tế Chicago O'Hare.
Nhập URL http://ws.geonames.org/search?name_equals=den&fcode=airp&style=full vào trình
duyệt Web của bạn. Bạn nên xem XML trả về được trình bày trong Ví dụ 1:
Ví dụ 1. XML trả về từ yêu cầu mã địa lý
<geonames style="FULL">
<totalResultsCount>1</totalResultsCount>
<geoname>
<name>Denver International Airport</name>
<lat>39.8583188</lat>
<lng>-104.6674674</lng>
<geonameId>5419401</geonameId>
<countryCode>US</countryCode>
<countryName>United States</countryName>
<fcl>S</fcl>
<fcode>AIRP</fcode>
<fclName>spot, building, farm</fclName>
<fcodeName>airport</fcodeName>
<population/>
<alternateNames>DEN,KDEN</alternateNames>
<elevation>1655</elevation>
<continentCode>NA</continentCode>
<adminCode1>CO</adminCode1>
<adminName1>Colorado</adminName1>
<adminCode2>031</adminCode2>
<adminName2>Denver County</adminName2>
<alternateName lang="iata">DEN</alternateName>
<alternateName lang="icao">KDEN</alternateName>
<timezone dstOffset="-6.0" gmtOffset="-7.0">America/Denver</timezone>
</geoname>
</geonames>
Tham số name_equals trong URL bạn nhập vào là mã IATA cho sân bay. Nó chỉ là một phần của
URL mà cần bị thay đổi cho mỗi truy vấn. fcode=airp chỉ ra rằng mã đặc trưng bạn đang tìm kiếm
là một sân bay. Tham số style—short, medium, long, hoặc full— chỉ rõ tính đầy đủ của câu trả lời
XML.
Giờ đây bạn có một trình sinh mã địa lý, bước tiếp theo là tích hợp nó vào ứng dụng Grails của bạn.
Để làm được như vậy, bạn cần một dịch vụ.
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 3 của 19
developerWorks®
ibm.com/developerWorks/vn/
Những dịch vụ Grails
Bằng điểm này trong loạt bài Làm chủ Grails, bạn có một ý tưởng hay về các phân lớp miền, các
kiểm soát, và các Trang Máy chủ Groovy (GSP) tất cả làm việc với nhau trong một kiểu tổ hợp như
thế nào. Chúng làm cho các thao tác cơ bản Tạo/Truy lục/Cập nhật/Xóa (Create/Retrieve/Update/
Delete (CRUD)) dễ dàng trên một kiểu dữ liệu đơn. Dịch vụ mã địa lý này vượt một chút ra ngoài
phạm vi của các phép biến đổi Ánh xạ Quan hệ Đối tượng Grails (Grails Object Relational Mapping
(GORM)) từ các bản ghi cơ sở dữ liệu quan hệ tới POGOs (các đối tượng Groovy cũ đơn giản).
Ngoài ra, dịch vụ sẽ có thể được sử dụng bởi nhiều hơn một phương thức. Cả save và update sẽ cần
mã địa lý mã IATA, như bạn sẽ thấy ở một thời điểm. Grails cung cấp cho bạn một nơi để lưu trữ
các phương thức được sử dụng phổ biến mà vượt qua bất kỳ lớp miền đơn: các dịch vụ.
Để tạo một dịch vụ Grails, gõ grails create-service Geocoder ở dòng lệnh. Xem grails-app/
services/GeocoderService.groovy, được trình bày ở Ví dụ 2, trong một bộ soạn thảo văn bản:
Ví dụ 2. Một dịch vụ Grails nhiều nhánh-ra
class GeocoderService {
boolean transactional = true
def serviceMethod() {
}
}
Trường transactional được quan tâm nếu bạn đang thực hiện các truy vấn cơ sở dữ liệu phức tạp
trong cùng một phương thức. Nó gói mọi thứ trong một giao dịch cơ sở dữ liệu đơn mà trả về nếu
bất kỳ truy vấn nào lỗi. Bởi vì trong ví dụ này bạn đang thực hiện gọi một dịch vụ Web từ xa, bạn có
thể thiết lập nó một cách an toàn là false.
tên là một trình giữ chỗ mà có thể được thay đổi thành cái gì đó hơn là mô tả.
(Các dịch vụ có thể chứa nhiều phương thức như bạn muốn.) Trong Ví dụ 3, tôi thay đổi tên thành
geocodeAirport:
serviceMethod
Ví dụ 3. Phương thức dịch vụ trình sinh mã địa lý geocodeAirport()
class GeocoderService {
boolean transactional = false
// http://ws.geonames.org/search?name_equals=den&fcode=airp&style=full
def geocodeAirport(String iata) {
def base = "http://ws.geonames.org/search?"
def qs = []
qs << "name_equals=" + URLEncoder.encode(iata)
qs << "fcode=airp"
qs << "style=full"
def url = new URL(base + qs.join("&"))
def connection = url.openConnection()
def result = [:]
if(connection.responseCode == 200){
def xml = connection.content.text
def geonames = new XmlSlurper().parseText(xml)
result.name = geonames.geoname.name as String
result.lat = geonames.geoname.lat as String
result.lng = geonames.geoname.lng as String
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 4 của 19
ibm.com/developerWorks/vn/
developerWorks®
result.state = geonames.geoname.adminCode1 as String
result.country = geonames.geoname.countryCode as String
}
else{
log.error("GeocoderService.geocodeAirport FAILED")
log.error(url)
log.error(connection.responseCode)
log.error(connection.responseMessage)
}
return result
}
}
Phần đầu của phương thức geocodeAirport xây dựng URL và thực hiện kết nối. Những phần tử
chuỗi-truy vấn được tập hợp trong một ArrayList và sau đó nối với nhau bởi dấu "và". Phần cuối
của phương thức phân tích kết quả XML sử dụng một XmlSlurper Groovy và lưu trữ các kết quả
trong một bản đồ băm.
Các dịch vụ Groovy không thể truy cập một cách trực tiếp từ một URL. Nếu bạn muốn kiểm tra
phương thức dịch vụ mới này trong trình duyệt Web của bạn, thêm một bao đóng đơn giản cho
AirportController, như được trình bày trong Ví dụ 4:
Ví dụ 4. Cung cấp một URL cho một dịch vụ trong một bộ điều khiển.
import grails.converters.*
class AirportController {
def geocoderService
def scaffold = Airport
def geocode = {
def result = geocoderService.geocodeAirport(params.iata)
render result as JSON
}
...
}
Spring xen dịch vụ vào bộ điều khiển một cách tự động nếu bạn định nghĩa một biến thành viên với
tên trùng với dịch vụ. (Với bí quyết để làm việc này, bạn phải thay đổi kí tự đầu tiên của tên dịch vụ
từ chữ hoa thành chữ thường theo những quy ước đặt tên biến của Java.)
Để kiểm tra dịch vụ, nhập URL http://localhost:9090/trip/airport/geocode?iata=den trong
trình duyệt Web của bạn. Bạn nên xem kết quả được thể hiện trong Ví dụ 5:
Ví dụ 5. Các kết quả của yêu cầu trình sinh mã địa lý
{"name":"Denver International Airport",
"lat":"39.8583188",
"lng":"-104.6674674",
"state":"CO",
"country":"US"}
Bao đóng geocode trong AirportController là chỉ để cho bạn kiểm tra sự đúng đắn dịch vụ. Bạn có
thể gỡ bỏ nó đi, hoặc bạn có thể để nó lại cho các cuộc gọi Ajax tương lai có thể có. Bước tiếp theo
là hệ số lại cơ sở hạ tầng Airport để tận dụng ưu điểm của dịch vụ mã địa lý mới này.
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 5 của 19
developerWorks®
ibm.com/developerWorks/vn/
Hòa trộn trong dịch vụ
Để bắt đầu, thêm các trường mới lat và lng vào grails-app/domain/Airport.groovy, như được trình
bày trong Ví dụ 6:
Ví dụ 6. Thêm các trường lat và lng vào Airport POGO
class Airport{
static constraints = {
name()
iata(maxSize:3)
city()
state(maxSize:2)
country()
}
String
String
String
String
String
String
String
name
iata
city
state
country = "US"
lat
lng
String toString(){
"${iata} - ${name}"
}
}
Gõ grails generate-views Airport ở dấu nhắc lệnh để tạo các tệp tin GSP. Chúng được
gắn liên kết động ở thời gian chạy tới điểm này, nhờ dòng def scaffold = Airport trong
AirportController.groovy. Vì tôi muốn thực hiện vài thay đổi cho các khung nhìn, tôi cần mã hóa thủ
công.
Khi tạo một Airport mới, tôi sẽ giới hạn các trường người dùng-có thể soạn thảo là iata và city.
Trường iata là cần thiết cho truy vấn mã địa lý làm việc. Tôi để city ở đây bởi vì tôi muốn cung
cấp thông tin đó cho bản thân. DEN thực sự là ở Denver, nhưng ORD (Chicago O'Hare) thì ở
Rosemont, Ill., và CVG (Cincinnati, sân bay Ohio) là ở Florence, Ky. Để hai trường này trong
create.gsp và xóa phần còn lại, do đó bây giờ create.gsp giống như Ví dụ 7:
Ví dụ 7. Thay đổi create.gsp
<g:form action="save" method="post" >
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name"><label for="iata">Iata:</label></td>
<td valign="top"
class="value ${hasErrors(bean:airport,field:'iata','errors')}">
<input type="text"
maxlength="3"
id="iata"
name="iata"
value="${fieldValue(bean:airport,field:'iata')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="city">City:</label></td>
<td valign="top"
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 6 của 19
ibm.com/developerWorks/vn/
developerWorks®
class="value ${hasErrors(bean:airport,field:'city','errors')}">
<input type="text"
id="city"
name="city"
value="${fieldValue(bean:airport,field:'city')}"/>
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><input class="save" type="submit" value="Create" /></span>
</div>
</g:form>
Hình 2 thể hiện biểu mẫu kết quả:
Hình 2. Tạo biểu mẫu Airport
Biểu mẫu này được đưa tới bao đóng save trong AirportController. Thêm đoạn mã trong Ví dụ 8
vào bộ điều khiển để thực hiện gọi tới geocodeAirport trước khi Airport mới được lưu lại:
Ví dụ 8. Thay đổi bao đóng save
def save = {
def results = geocoderService.geocodeAirport(params.iata)
def airport = new Airport(params + results)
if(!airport.hasErrors() && airport.save()) {
flash.message = "Airport ${airport.id} created"
redirect(action:show,id:airport.id)
}
else {
render(view:'create',model:[airport:airport])
}
}
Số lượng lớn phương thức là giống hệt những gì bạn thấy nếu bạn gõ grails generate-controller
Airport ở dấu nhắc lệnh. Sự khác biệt duy nhất với bao đóng được sinh ra mặc định là hai
dòng đầu tiên. Dòng thứ nhất có HashMap từ dịch vụ trình sinh mã địa lý. Dòng thứ hai kết hợp
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 7 của 19
developerWorks®
ibm.com/developerWorks/vn/
với paramsHashMap. (Vâng, việc hòa nhập hai HashMaps trong Groovy đơn giản như
việc thêm chúng với nhau.)
resultsHashMap
Nếu lưu trữ cơ sở dữ liệu hoàn thành, bạn được gửi một lần nữa tới hành động chỉ dẫn, không có
thay đổi nào được yêu cầu cho show.gsp, như được trình bày trong Hình 3:
Hình 3. Thể hiện biểu mẫu Airport
Để hỗ trợ việc soạn thảo một Airport, để lại các trường iata và city trong edit.gsp. Bạn có thể sao
chép và dán phần còn lại của các trường từ show.gsp để thực hiện chúng chỉ đọc. (Hoặc nếu bạn
đã đặt "sao chép và dán là hình thức thấp nhất của lập trình hướng đối tượng" từ bài viết trước đó,
bạn có thể giải nén các trường phổ biến vào một mẫu riêng và hoàn trả nó trên cả show.gsp và
edit.gsp.) Ví dụ 9 trình bày thay đổi edit.gsp:
Ví dụ 9. Thay đổi edit.gsp
<g:form method="post" >
<input type="hidden" name="id" value="${airport?.id}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name"><label for="iata">Iata:</label></td>
<td valign="top"
class="value ${hasErrors(bean:airport,field:'iata','errors')}">
<input type="text"
maxlength="3"
id="iata"
name="iata"
value="${fieldValue(bean:airport,field:'iata')}"/>
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 8 của 19
ibm.com/developerWorks/vn/
developerWorks®
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="city">City:</label></td>
<td valign="top"
class="value ${hasErrors(bean:airport,field:'city','errors')}">
<input type="text"
id="city"
name="city"
value="${fieldValue(bean:airport,field:'city')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Name:</td>
<td valign="top" class="value">${airport.name}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">State:</td>
<td valign="top" class="value">${airport.state}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Country:</td>
<td valign="top" class="value">${airport.country}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Lat:</td>
<td valign="top" class="value">${airport.lat}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Lng:</td>
<td valign="top" class="value">${airport.lng}</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:actionSubmit class="save" value="Update" /></span>
<span class="button">
<g:actionSubmit class="delete"
onclick="return confirm('Are you sure?');"
value="Delete" />
</span>
</div>
</g:form>
Biểu mẫu kết quả được trình bày ở Hình 4:
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 9 của 19
developerWorks®
ibm.com/developerWorks/vn/
Hình 4. Biểu mẫu soạn thảo Airport
Nhấn chuột vào nút Update gửi các giá trị biểu mẫu tới bao đóng update. Thêm dịch vụ gọi và bản
đồ băm trộn vào mã mặc định, như được trình bày trong Ví dụ 10:
Ví dụ 10. Thay đổi bao đóng update
def update = {
def airport = Airport.get( params.id )
if(airport) {
def results = geocoderService.geocodeAirport(params.iata)
airport.properties = params + results
if(!airport.hasErrors() && airport.save()) {
flash.message = "Airport ${params.id} updated"
redirect(action:show,id:airport.id)
}
else {
render(view:'edit',model:[airport:airport])
}
}
else {
flash.message = "Airport not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
Tại thời điểm này, bạn đã tích hợp hoàn toàn mã địa lí vào ứng dụng của bạn cũng giống như Các
bản đồ Google. Mất một chút thời gian để xem xét toàn bộ các vị trí trên ứng dụng của bạn mà bạn
đang thu nhận các địa chỉ — các khách hàng, các nhân viên, các văn phòng từ xa, kho hàng, các
địa phương bán lẻ, v.v.. Bằng việc thêm một cặp các trường để lưu trữ vĩ độ/kinh độ và trộn vào
dịch vụ mã địa lí, bạn đang thiết lập cho bản thân mình những bản đồ dễ dàng để hiển thị các đối
tượng — đó chính là những gì tôi sẽ làm tiếp theo.
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 10 của 19
ibm.com/developerWorks/vn/
developerWorks®
Các bản đồ Google
Hầu hết mọi người đồng ý rằng Các bản đồ Google thiết lập chuẩn giúp dễ sử dụng hơn khi nó
thành bản đồ Web. Một vài người nhận ra rằng việc dễ dùng này mở rộng cho việc nhúng một bản
đồ Google vào trang Web của riêng bạn. Đưa tọa độ vĩ độ/kinh độ cho các điểm dữ liệu là phần bài
tập khó nhất, và chúng ta sẵn sàng giải quyết vấn đề đó.
Để nhúng một Bản đồ Google vào ứng dụng Grails của bạn, điều trước tiên bạn cần làm là có một
khóa API miễn phí. Trang đăng kí chi tiết các điều khoản sử dụng. Về cơ bản, Google cung cấp API
cho bạn miễn phí với điều kiện ứng dụng của bạn cũng là miễn phí. Điều này có nghĩa là bạn không
thể bảo vệ ứng dụng Các bản đồ Google của bạn bằng mật khẩu, tính phí cho việc truy cập vào nó,
hoặc lưu trữ nó đằng sau tường lửa. (Shameless plug: My book GIS for Web Developers cho bạn
tập các hướng dẫn từng bước cho việc xây dựng một ứng dụng giống Bản đồ Google sử dụng dữ
liệu miễn phí và phần mềm nguồn mở; xem Tài nguyên. Điều này giải phóng bạn khỏi những hạn
chế Google đặt trên API của bạn).
Khóa API được gắn với một URL và thư mục cụ thể. Gõ http://localhost:9090/trip trên biểu
mẫu và nhấn nút Generate API Key. Trang xác nhận cho thấy khóa API được sinh ra của bạn, nó
liên quan đến URL, và một trang Web mẫu, như họ nói, "để bạn bắt đầu trên con đường lập bản
đồ"
Để kết hợp trang mẫu này vào ứng dụng Grails của bạn, tạo một tập tin có tên map.gsp trong thư
mục grails-app/views/airport. Sao chép trang mẫu từ Google vào map.gsp. Ví dụ 11 cho thấy các
nội dung của map.gsp:
Ví dụ 11. Một trang Web Bản đồ Google đơn giản
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABCDE"
type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
}
}
//]]>
</script>
</head>
<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 500px; height: 300px"></div>
</body>
</html>
Chú ý rằng khóa API của bạn được nhúng vào tập lệnh URL ở đầu trang. Trong phương thức load,
bạn đang thể hiện một đối tượng GMap2 mới. Đây là bản đồ mà xuất hiện ở <div /> với ID của map
ở cuối của trang. Nếu bạn muốn bản đồ lớn hơn, điều chỉnh độ rộng và chiều cao trong thuộc tính
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 11 của 19
developerWorks®
ibm.com/developerWorks/vn/
của Cascading Style Sheets (CSS). Hiện nay bản đồ được tập trung vào Palo Alto, Calif. ở
mức độ phóng 13 (Mức 0 là mức thu nhỏ tất cả các trường hợp. Khi các số tăng lên, bạn có khung
nhìn các đường phố rõ hơn). Bạn sẽ điều chỉnh các giá trị này chỉ trong một thời điểm. Trong khi
chờ đợi, thêm một bao đóng map rỗng vào AirlineController, như được trình bày ở Ví dụ 12:
style
Ví dụ 12. Thêm bao đóng map
class AirportController {
def map = {}
...
}
Bây giờ vào địa chỉ http://localhost:9090/trip/airport/map trên trình duyệt của bạn. Bạn thấy Bản đồ
Google được nhúng, nó trong giống như Hình 5:
Hình 5. Bản đồ Google đơn giản
Bây giờ quay lại map.gsp và ngắt các giá trị, như được biểu diễn trong Ví dụ 13:
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 12 của 19
ibm.com/developerWorks/vn/
developerWorks®
Ví dụ 13. Điều chỉnh bản đồ cơ bản
<script type="text/javascript">
var usCenterPoint = new GLatLng(39.833333, -98.583333)
var usZoom = 4
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"))
map.setCenter(usCenterPoint, usZoom)
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
}
}
</script>
</head>
<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 800px; height: 400px"></div>
</body>
800 x 400 điểm ảnh là tập kích thước tốt cho việc xem toàn bộ bản đồ nước Mỹ. Ví dụ 13 điều
chỉnh điểm trung tâm và mức độ phóng để bạn có thể xem toàn bộ bản đồ. Bạn có thể thêm một
số các điều khiển bản đồ khác. GLargeMapControl và GMapTypeControl trong Ví dụ 13 cho bạn các
điều khiển thông thường dọc theo góc trái và trên phải của bản đồ. Định kì nhấn nút Refresh của
trình duyệt của bạn để xem những thay đổi của bạn có hiệu lực khi bạn thực hiện xung quanh. Hình
6 phản ánh những điều chỉnh đã thực hiện trong Ví dụ 13:
Hình 6. Bản đồ đã điều chỉnh
Bây giờ bản đồ của bạn là ở đây, bạn đã sẵn sàng để bắt đầu thêm các đánh dấu — push-pin cho
mỗi sân bay của bạn. Trước khi tôi tự động hóa tiến trình, Ví dụ 14 thêm một đánh dấu đơn một
cách thủ công:
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 13 của 19
developerWorks®
ibm.com/developerWorks/vn/
Ví dụ 14. Thêm một đánh dấu vào bản đồ
<script type="text/javascript">
var usCenterPoint = new GLatLng(39.833333, -98.583333)
var usZoom = 4
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"))
map.setCenter(usCenterPoint, usZoom)
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
var marker = new GMarker(new GLatLng(39.8583188, -104.6674674))
marker.bindInfoWindowHtml("DEN<br/>Denver International Airport")
map.addOverlay(marker)
}
}
</script>
Hàm GMarker đưa ra điểm GLatLng. Phương thức bindInfoWindowHtml cung cấp đoạn mã HTML
được hiển thị trên cửa sổ Info khi người dùng nhấn vào đánh dấu. Điều cuối cùng của Ví dụ 14 thực
hiện là thêm đánh dấu vào bản đồ sử dụng phương thức addOverlay.
Hình 7 thể hiện bản đồ với đánh dấu đã thêm vào:
Hình 7. Bản đồ với đánh dấu
Vì bạn biết làm thế nào để thêm một điểm đơn, việc thêm một cách tự động tất cả các điểm
từ cơ sở dữ liệu yêu cầu hai thay đổi nhỏ. Thay đổi thứ nhất để thực hiện bao đóng map trong
AirportController trả về một danh sách các Airport, như được trình bày ở Ví dụ 15:
Ví dụ 15. Trả về một danh sách các Airport
def map = {
[airportList: Airport.list()]
}
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 14 của 19
ibm.com/developerWorks/vn/
developerWorks®
Tiếp theo, bạn cần lặp đi lặp lại danh sách các Airport và tạo các đánh dấu cho mỗi danh sách.
Trong phần trước của loạt bài này, bạn đã thấy thẻ <g:each> được dùng để thêm các dòng vào một
bảng HTML. Ví dụ 16 sử dụng thẻ này để tạo các dòng JavaScript cần thiết để hiển thị các Airport
trên bản đồ:
Ví dụ 16. Thêm các đánh dấu vào bản đồ
<script type="text/javascript">
var usCenterPoint = new GLatLng(39.833333, -98.583333)
var usZoom = 4
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"))
map.setCenter(usCenterPoint, usZoom)
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
<g:each in="${airportList}" status="i" var="airport">
var point${airport.id} = new GLatLng(${airport.lat}, ${airport.lng})
var marker${airport.id} = new GMarker(point${airport.id})
marker${airport.id}.bindInfoWindowHtml("${airport.iata}<br/>${airport.name}")
map.addOverlay(marker${airport.id})
</g:each>
}
}
</script>
Hình 8 cho thấy bản đồ với tất cả các đánh dấu đã thêm vào một cách tự động:
Hình 8. Bản đồ với nhiều đánh dấu
Chuyến đi này của API Bản đồ Google chỉ vừa đủ để bạn thảo luận sơ qua bề ngoài những thứ mà
bạn có thể làm. Bạn có thể quyết định đề cập đến mô hình sự kiện để thực hiện các lời gọi Ajax mà
trả về dữ liệu JavaScript Object Notation (JSON) khi các đánh dấu được nhấn. Bạn có thể sử dụng
các GPolyline để vẽ các chặng riêng của một chuyến đi trên bản đồ. Các khả năng là vô tận. Để
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 15 của 19
developerWorks®
ibm.com/developerWorks/vn/
biết thêm thông tin, tài liệu trực tuyến của Google là tuyệt vời. Bạn cũng có thể có một giới thiệu
nhỏ về API từ cuốn sách PDF của tôi Google Maps API (xem Tài nguyên).
Kết luận
Việc thêm các bản đồ vào ứng dụng Grails của bạn yêu cầu đưa vào ba thành phần.
Phần đầu tiên là mã địa lý dữ liệu của bạn. Ngoài ra có nhiều trình sinh mã địa lí miễn phí mà
chuyển đổi các vị trí người dùng có thể đọc được thành các điểm vĩ độ/kinh độ. Gần như bất kì điều
gì có thể được mã hóa địa lí: các địa chỉ đường phố, các thành phố, các hạt, các bang, các quốc
gia, các mã vùng, các số điện thoại, các địa chỉ IP, và thậm chí các mã IATA cho các sân bay.
Một khi bạn tìm thấy trình sinh mã địa lí đúng cho công việc, tạo một dịch vụ Grails để đóng gói các
dịch vụ Web từ xa gọi đến phương thức sử dụng lại. Những dịch vụ cho các phương thức này mà đi
xa hơn các thao tác CRUD đơn giản trên đối tượng miền đơn. Những dịch vụ không liên quan đến
URL mặc định, nhưng bạn có thể tạo một cách dễ dàng một bao đóng trong một bộ điều khiển để
thực hiện địa chỉ hóa Web chúng.
Cuối cùng, tận dùng ưu điểm của API ánh xạ Web miễn phí chẳng hạn như Bản đồ Google để vẽ
các điểm vĩ độ/kinh độ của bạn trên một bản đồ. Những dịch vụ miễn phí này thường đòi hỏi ứng
dụng của bạn cũng được truy cập miễn phí. Nếu bạn muốn giữ bản đồ cá nhân của riêng bạn, hãy
xem xét API nguồn mở chẳng hạn như OpenLayers, nó cung cấp kinh nghiệm người dùng giống
như Bản đồ Google mà không có sự hạn chế sử dụng tương ứng (xem Tài nguyên). Bạn sẽ cần phải
cung cấp các lớp bản đồ của riêng bạn, nhưng bạn sẽ có thể lưu trữ toàn bộ ứng dụng vào máy chủ
của riêng bạn.
Trong bài viết tiếp theo, tôi sẽ nói về cách để thực hiện ứng dụng Grails của bạn trên mạng di động
một cách thân thiện. Bạn sẽ biết làm thế nào để tối ưu các khung nhìn cho hiển thị iPhone. Tôi
cũng sẽ giải thích việc gửi thông tin từ Grails qua thư điện tử mà xuất hiện như là một tin nhắn SMS
trên điện thoại của bạn. Cho đến lúc đó, hãy vui vẻ với việc nắm vững Grails.
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 16 của 19
ibm.com/developerWorks/vn/
developerWorks®
Các tải về
Mô tả
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Tên
Kích thước
j-grails05208.zip
863KB
Trang 17 của 19
developerWorks®
ibm.com/developerWorks/vn/
Tài nguyên
Học tập
• Làm chủ Grails: Đọc thêm trong loạt bài này để thu được sự hiểu biết hơn về Grails và tất cả
những gì mà bạn có thể làm với nó.
• Grails: Ghé thăm trang Web Grails.
• Grails Framework Reference Documentation (Tài liệu Tham khảo Khung làm việc Grails): Đưa
bạn qua việc bắt đầu với Grails và xây dựng các ứng dụng Web với khung làm việc Grails.
• GeoNames: Dịch vụ mã địa lí GeoNames được dựa trên kiến trúc Representational State
Transfer (REST)
• Google Maps API: Nhúng Các bản đồ Google vào các trang Web của bạn.
• Yahoo! Maps API: Nhúng các bản đồ Yahoo! vào trang Web của bạn và các ứng dụng màn
hình nền.
• Geocoding (Mã địa lí): Nhập mã địa lí trên Wikipedia.
• GIS for Web Developers (GIS dành cho các Nhà phát triển Web) (Scott Davis, Pragmatic
Programmers, 2007): Sách của Scott Davis giới thiệu về Hệ thống Thông tin Địa lí
(Geographic Information Systems (GIS)) theo những từ ngữ đơn giản và thể hiện những
hướng dẫn thực hành.
• The Google Maps API (Scott Davis, Pragmatic Programmers, 2006): Học làm thế nào để vẽ
các bản đồ, thêm các diễn giải và các lộ trình, và mã hóa địa lí dữ liệu của bạn.
• OpenLayers API: OpenLayers là một thư viện JavaScript dành cho việc hiển thị dữ liệu bản
đồ trên hầu hết các trình duyệt Web.
• Groovy Recipes (Scott Davis, Pragmatic Programmers, 2007): Biết thêm về Groovy và Grails
trong cuốn sách mới nhất của Scott Davis.
• Practically Groovy: Chuỗi các developerWorks này được dành để khám phá tác dụng thực tế
của Groovy và dạy cho bạn khi nào và như thế nào để áp dụng chúng một cách thành công.
• Groovy: Biết thêm về Groovy ở trang Web dự án.
• AboutGroovy.com: Keep up with the latest Groovy news and article links.
• Tủ sách kĩ thuật: Duyệt các cuốn sách về các chủ đề kĩ thuật này và khác.
• Khu công nghệ Java developerWorks: Tìm hàng trăm bài viết về mọi khía cạnh của lập trình
Java.
Lấy sản phẩm và công nghệ
• Grails: Tải về các Grails mới nhất.
• OpenLayers: Tải về OpenLayers.
Thảo luận
• Kiểm tra các blog developerWorks và tham gia vào cộng đồng developerWorks.
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 18 của 19
ibm.com/developerWorks/vn/
developerWorks®
Đôi nét về tác giả
Scott Davis
Scott Davis là một tác giả, diễn giả và nhà phát triển phần mềm được cộng đồng quốc
tế thừa nhận, ông có những cuốn sách như Groovy Recipes: Greasing the Wheels
of Java (Các cách thức Groovy: Bôi trơn các bộ máy hoạt động của Java), GIS for
Web Developers: Adding Where to Your Application (GIS cho các nhà phát triển web:
Thêm vào đâu trong ứng dụng của bạn), The Google Maps API (các bản đồ Google
của API) và JBoss At Work (JBoss trong công việc)
© Copyright IBM Corporation 2010
(www.ibm.com/legal/copytrade.shtml)
Nhẫn hiệu đăng ký
(www.ibm.com/developerworks/vn/ibm/trademarks/)
Làm chủ Grails: Các dịch vụ Grails và bản đồ Google
Trang 19 của 19