从 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 应用启用工作。

