从 Android 应用访问基于 REST 的数据库后端





0/5 (0投票)
本文的目的是展示一种使用 MongoDB* 和 Spring IO* 从 Android* 应用访问基于 REST 的数据库后端的方法。
英特尔® 开发人员专区提供用于跨平台应用开发的工具和操作指南、平台和技术信息、代码示例以及同行专业知识,以帮助开发人员创新并取得成功。加入我们的Android、物联网、英特尔® 实感™ 技术和Windows社区,下载工具、访问开发套件、与志同道合的开发人员分享想法,并参与黑客马拉松、比赛、路演和本地活动。
目录
介绍
随着智能手机和平板设备的性能和普及度不断增长,它们正成为我们日常随身携带、熟练使用和依赖的计算设备中的一部分。这为开发人员提供了持续的创新机会,可以利用移动设备提供的独特便携平台进行软件开发。企业正在其场所部署平板设备,以增强客户体验并提供更大的收入机会。这些设备具有能够与后端服务器通信的无线连接。餐厅是一个有趣的例子,平板设备被部署到每张桌子上,允许客户浏览菜单、准备好后点餐,并在用餐结束后支付账单。拥有一个每个平板电脑都可以与之通信的集中式后端服务器,为餐厅管理、分析、动态菜单和改进服务带来了新的机会。本文讨论了从 Android 应用程序访问基于 REST 的数据库后端的方法。特别是,文章的第一部分将讨论所使用的工具、环境设置以及如何创建餐厅数据库。该
使用的工具
在创建概念验证时,拥有一种灵活的解决方案,能够快速启动并运行服务器,这是非常理想的。Spring IO 平台是一个开源解决方案,它使用 Apache* Tomcat 服务器并与各种数据库配合使用。Spring 提供了一个框架,可以轻松实现 Android 客户端和 Linux* 服务器通过 REST 接口进行通信。服务器端使用的组件包括 Ubuntu* Linux 14 作为操作系统,MongoDB 作为数据库,以及 Spring IO 平台作为 REST 服务。客户端使用的组件包括 Android Studio 作为开发 IDE,Spring REST Template API 用于与服务器通信,Jackson 库用于解析 JSON 响应,以及 AVD 用于 Android 设备模拟。请参阅下面的链接,了解有关这些组件的更多信息。
https://springframework.org.cn/
https://springframework.org.cn/understanding/REST
https://developer.android.com.cn/sdk/installing/studio.html
http://wiki.fasterxml.com/JacksonHome
环境设置
要设置服务器和客户端环境,请按照以下步骤安装 Linux、软件包和 Android Studio。
安装 Ubuntu Linux 14 并连接到本地网络。
http://www.ubuntu.com/download
从终端安装软件包。
MongoDB
sudo apt-get update
sudo apt-get install –y mongodb-org
git
sudo apt-get install git
gradle
sudo apt-get install gradle
curl
sudo apt-get install curl
java
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
安装 Android Studio
https://developer.android.com.cn/sdk/index.html
创建数据库
Spring 启动项目为使用 MongoDB 创建持久性后端提供了一个很好的起点,该后端使用 HTTP JSON 接口访问数据库。创建包含菜单项和价格的餐厅数据库非常容易。此外,可以在几行代码中定义查询。请参阅下面的步骤来创建数据库、创建查询和运行服务。
获取 Spring 启动项目。
git clone https://github.com/spring-guides/gs-accessing-mongodb-data-rest.git
进入初始源代码目录。
cd gs-accessing-mongodb-data-rest/initial/src/main/java/hello
创建 Restaurant 对象 (Restaurant.java)。
import org.springframework.data.annotation.Id;
public class Restaurant {
@Id private String id;
private String menuCategoryName;
private String menuItemName;
private String menuItemPrice;
private Boolean isSpecial;
private String specialmenuItemPrice;
public String getmenuCategoryName() {
return menuCategoryName;
}
public void setmenuCategoryName(String menuCategoryName) {
this.menuCategoryName = menuCategoryName;
}
public String getmenuItemName() {
return menuItemName;
}
public void setmenuItemName(String menuItemName) {
this.menuItemName = menuItemName;
}
public String getmenuItemPrice() {
return menuItemPrice;
}
public void setmenuItemPrice(String menuItemPrice) {
this.menuItemPrice = menuItemPrice;
}
public Boolean getisSpecial(){
return isSpecial;
}
public void setisSpecial(Boolean isSpecial){
this.isSpecial = isSpecial;
}
public String getspecialmenuItemPrice(){
return specialmenuItemPrice;
}
public void setspecialmenuItemPrice(String specialmenuItemPrice){
this.specialmenuItemPrice = specialmenuItemPrice;
}
}
使用查询创建 Restaurant 数据库存储库 (RestaurantRepository.java)。
服务器上数据库根的路径将是 https://:8080/menu。下面定义的接口中有两个查询。findByMenuItemName
允许按 menuItemName
搜索。findByMenuCategoryName
允许按 menuCategoryName
搜索。
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource(collectionResourceRel = "menu", path = "menu")
public interface RestaurantRepository extends MongoRepository {
List findByMenuItemName(@Param("name") String name);
List findByMenuCategoryName(@Param("name") String name);
}
创建 Application 类 (Application.java)。
下面显示的应用程序类是服务的主要入口点,并包含在服务中使用 Spring IO 和 MongoDB 的配置。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
@Configuration
@EnableMongoRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
进入初始目录。
cd gs-accessing-data-mongodb/initial/
使用 Gradle 构建。
./gradlew build
运行服务器。
java –jar build/libs/<project_name>.jar
访问数据库。
curl https://:8080/menu
查看 JSON 响应。
在此示例中,数据库包含一个 Tacos 菜单项
{
"_links" : {
"self" : {
"href" : "https://:8080/menu{?page,size,sort}",
"templated" : true
},
"search" : {
"href" : "https://:8080/menu/search"
}
},
"_embedded" : {
"menu" : [ {
"menuCategoryName" : "Mexican",
"menuItemName" : "Tacos",
"menuItemPrice" : "$15",
"isSpecial" : false,
"specialmenuItemPrice" : "$7.50",
"_links" : {
"self" : {
"href" : "https://:8080/menu/5488c2ee44ae7e3fab758edd"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
访问数据库
启动 Android Studio 并创建一个新项目。创建新项目后,需要将互联网权限添加到清单、Spring Rest Template 依赖项和 Jackson JSON 解析依赖项中,如下所示。
将互联网权限添加到清单 (AndroidManifest.xml)。
<uses-permission android:name="android.permission.INTERNET">
添加 RestTemplate 和 Jackson 库依赖项 (build.gradle)。
apply plugin: 'com.android.application'.
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "com.example.test.myapplication"
minSdkVersion 7
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/ASL2.0'
exclude 'META-INF/LICENSE'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/notice.txt'
}
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
compile 'com.fasterxml.jackson.core:jackson-databind:2.3.2'
}
该应用需要一种方法来理解 JSON 响应并能够解析它。一种方法是创建表示响应的 Java 对象。Jackson 库是一个方便的库,可用于解析 JSON 响应并使用 Java 对象。要使用此库,Jackson 注解会添加到 Java 对象中。Java 对象可以手动创建,但有一个方便的工具可以帮助为给定 JSON 响应创建它们,网址为 http://www.jsonschema2pojo.org/。此示例的 Menu Class 如下所示,带有 Jackson 注解。
package com.example.test.myapplication;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.HashMap;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"menuCategoryName",
"menuItemName",
"menuItemPrice",
"isSpecial",
"specialmenuItemPrice",
"_links"
})
public class Menu {
@JsonProperty("menuCategoryName")
private String menuCategoryName;
@JsonProperty("menuItemName")
private String menuItemName;
@JsonProperty("menuItemPrice")
private String menuItemPrice;
@JsonProperty("isSpecial")
private Boolean isSpecial;
@JsonProperty("specialmenuItemPrice")
private String specialmenuItemPrice;
@JsonProperty("_links")
private Links_ Links;
@JsonIgnore
private Map additionalProperties = new HashMap();
@JsonProperty("menuCategoryName")
public String getMenuCategoryName() {
return menuCategoryName;
}
@JsonProperty("menuCategoryName")
public void setMenuCategoryName(String menuCategoryName) { this.menuCategoryName = menuCategoryName; }
@JsonProperty("menuItemName")
public String getMenuItemName() {
return menuItemName;
}
@JsonProperty("menuItemName")
public void setMenuItemName(String menuItemName) {
this.menuItemName = menuItemName;
}
@JsonProperty("menuItemPrice")
public String getMenuItemPrice() {
return menuItemPrice;
}
@JsonProperty("menuItemPrice")
public void setMenuItemPrice(String menuItemPrice) {
this.menuItemPrice = menuItemPrice;
}
@JsonProperty("isSpecial")
public Boolean getIsSpecial() {
return isSpecial;
}
@JsonProperty("isSpecial")
public void setIsSpecial(Boolean isSpecial) {
this.isSpecial = isSpecial;
}
@JsonProperty("specialmenuItemPrice")
public String getSpecialmenuItemPrice() {
return specialmenuItemPrice;
}
@JsonProperty("specialmenuItemPrice")
public void setSpecialmenuItemPrice(String specialmenuItemPrice) { this.specialmenuItemPrice = specialmenuItemPrice; }
@JsonProperty("_links")
public Links_ getLinks() {
return Links;
}
@JsonProperty("_links")
public void setLinks(Links_ Links) {
this.Links = Links;
}
@JsonAnyGetter
public Map getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); }
}
数据库通过基于 REST 的简单 HTTP 接口进行访问,以执行 POST、PUT、GET 和 DELETE 等基本操作。RestTemplate 提供了一个很好的 API,可以在 AsyncTask 中执行这些操作,从而使应用程序保持响应。下面的代码片段显示了如何访问和操作餐厅数据库的示例。
创建 RestTemplate 实例和服务器路径。
private RestTemplate rest = new RestTemplate(); private String url = "http://192.168.1.110:8080/menu/";
启用 Jackson 库 JSON 解析。
RestTemplate rest = new RestTemplate();
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
创建菜单项实例
Menu myMenuItem = new Menu();
myMenuItem.setMenuCategoryName("Mexican");
myMenuItem.setMenuItemName("Tacos");
myMenuItem.setMenuItemPrice("$15");
myMenuItem.setIsSpecial(false);
myMenuItem.setSpecialmenuItemPrice("$7.50");
向数据库添加新的菜单项 (POST)
添加新的菜单项是一个 POST 操作,它将新的菜单项传递给任务。
new Http_POST_Task().execute(myMenuItem);
private class Http_POST_Task extends AsyncTask {
@Override
protected Void doInBackground(Menu... menuItem) {
try{
rest.postForObject(url,menuItem[0],Restaurant.class);
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return null;
}
}
从数据库中删除菜单项 (DELETE)。
删除菜单项是一个 DELETE 操作,它将菜单项传递给任务以进行删除。
new Http_DELETE_Task().execute(myMenuItem);
private class Http_DELETE_Task extends AsyncTask {
@Override
protected Void doInBackground(Menu... menuItem) {
try {
//DELETE
String urlStr = menuItem[0].getLinks().getSelf().getHref();
rest.delete(new URI(urlStr));
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return null;
}
}
在数据库中搜索菜单项 (GET) 搜索菜单项执行 findByMenuItemName
查询以获取指定的菜单项
try {
myMenuItem = new Http_findByMenuItemName_Task().execute("Tacos").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
private class Http_findByMenuItemName_Task extends AsyncTask {
@Override
protected Menu doInBackground(String... menuItemName) {
try {
String queryURL = url+"search/findByMenuItemName?name="+menuItemName[0];
Restaurant restaurant = rest.getForObject(queryURL, Restaurant.class);
return restaurant.getEmbedded().getMenu().get(0);
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return null;
}
}
更新数据库中现有菜单项 (GET) (PUT)。
更新现有菜单项执行 GET 查询操作以获取现有菜单项
try {
myMenuItem = new Http_findByMenuItemName_Task().execute("Tacos").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
修改现有菜单项,然后执行 PUT 操作。
myMenuItem.setMenuCategoryName("Chinese");
myMenuItem.setMenuItemName("Crab Puffs");
myMenuItem.setMenuItemPrice("$7");
myMenuItem.setIsSpecial(true);
myMenuItem.setSpecialmenuItemPrice("$5");
new Http_PUT_Task().execute(myMenuItem);
private class Http_PUT_Task extends AsyncTask<Menu,Void,Void> {
@Override
protected Void doInBackground(Menu... menuItem) {
try {
String urlStr = menuItem[0].getLinks().getSelf().getHref();
rest.put(new URI(urlStr),menuItem[0]);
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return null;
}
}
总结
本文展示了一种从 Android 应用程序访问基于 REST 的数据库后端的方法。首先讨论了使用的工具和环境设置。演示了使用 MongoDB 和 Spring IO 创建示例餐厅数据库以及查询。文章最后展示了如何在 Android 应用程序中使用 Spring IO 框架来解析 JSON 响应和操作数据库。
++此示例源代码根据英特尔示例源代码许可发布。
关于作者
Mike Rylee 是英特尔公司的软件工程师。他目前从事 Android 应用启用工作。