Android与ReactNative下使用OData进行数据访问
1.OData定义
Open Data Protocol (开放数据协议,OData)是用来查询和更新数据的一种Web协议,其提供了把存在于应用程序中的数据暴露出来的方式。
OData运用且构建于很多 Web技术之上,比如HTTP、Atom Publishing Protocol(AtomPub)和JSON,提供了从各种应用程序、服务和存储库中访问信息的能力。
OData被用来从各种数据源中暴露和访问信息, 这些数据源包括但不限于:关系数据库、文件系统、内容管理系统和传统Web站点。
2.Android下使用OData
1.创建Android应用
2.封装一个OkHttp请求的工具类
封装一个Http请求是每个网络请求必经的一个步骤,在Android4.4版本之后开始谷歌开始普及OkHttp,创建Android应用后,工程自动导入Okhttp的jar包。
代码如下
public class OkHttpUtil {
public final OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build(); //设置各种超时时间
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
/**
* OKHttp get请求
* @param url
* @return
*/
public Response get(String url, Request.Builder builder){
builder.url(url);
final Request request = builder.build();
Response response = null;
try {
response = client.newCall(request).execute();
System.out.println("===="+response.code());
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
/**
* OKHttp post 请求
* @param url
* @param json
* @return
*/
public Response post (String url, String json){
RequestBody requestBody = RequestBody.create(JSON, json);
//创建一个请求对象
Request request = new Request.Builder()
.url(url)
.header("Content-Type","application/json")
.post(requestBody)
.build();
Response response = null;
try {
response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
/**
* OkHttp put请求
* @param uploadUrl
* @return
* @throws IOException
*/
public Response put(Request.Builder builder, String uploadUrl, String json) throws IOException {
builder.url(uploadUrl);
RequestBody body = RequestBody.create(JSON, json);
builder.put(body);
final Request request = builder.build();
Response response = client.newCall(request).execute();
return response;
}
/**
* OkHttp delete请求
* @param url
* @return
* @throws IOException
*/
public Response delete( String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.delete()
.header("Content-Type","application/json")
.build();
Response response = null;
try {
response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
}
3.创建一个请求接口管理类
接口统一管理类本身不难理解,该项目是测试Demo,所用的接口地址是在OData官网上找到的,上面还有一些其他的操作接口,
OData官网测试接口地址:http://www.odata.org/odata-services/
打开后是这样样子
由于是测试地址,那么增删改查操作会对数据产生影响,OData要求每个用户获取测试所用的key,获取key的具体操作如下:
OData语法规则请参考:https://blogs.msdn.microsoft.com/alexj/2009/11/18/tip-44-how-to-navigate-an-odata-compliant-service/
接口管理类代码如下:
public class UrlService {
//查询所有
public String GetAllURL = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People";
//条件查询
public String GetOneByKey = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People?$filter=FirstName eq 'Lewis'";
//查询某一个属性
public String GetOneAtt = "http://services.odata.org/TripPinRESTierService/Airports('KSFO')/Name ";
//添加
public String ADDURL = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People";
//删除
public String DeleteURL = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People('aaa')";
//更新
public String PutURL = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People('aaa')";
}
4.创建一个请求管理类
创建该管理的目的是为了统一处理请求头及响应(本项目并没有用到),因为之前的项目里有一些请求的批处理操作,所以封装了这么一个管理类,就本项目而言可以不用。
代码如下:
public class ApiService {
OkHttpUtil okHttpUtil = new OkHttpUtil();
public Response read(String url) throws IOException {
Request.Builder builder = new Request.Builder();
requestHeaders(builder);
return okHttpUtil.get(url,builder);
}
public Response create(String url, String json) throws IOException {
return okHttpUtil.post(url,json);
}
public Response update(String uploadUrl, String json) throws IOException {
Request.Builder builder = new Request.Builder();
requestHeaders(builder);
return okHttpUtil.put(builder,uploadUrl,json);
}
public Response delete(String url) throws IOException {
return okHttpUtil.delete(url);
}
public String handleResponse(Response response) throws IOException {
if (response.code()==200){
System.out.println("Succeed"+response.body().string());
return response.body().string();
}else {
return "";
}
}
public Request.Builder requestHeaders(Request.Builder builder){
builder.addHeader("Content-Type", "application/json");
return builder;
}
}
5.创建一个MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public Button btnQueryByKey,btnPost,btnPut,btnDelete,btnQueryAll,btnQueryOneAttribute;
public Response response;
public UrlService urlService = new UrlService();
public String url;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
btnPost = (Button) findViewById(R.id.btnPost);
btnPut = (Button) findViewById(R.id.btnPut);
btnDelete = (Button) findViewById(R.id.btnDelete);
btnQueryAll = (Button) findViewById(R.id.btnQueryAll);
btnQueryByKey = (Button) findViewById(R.id.btnQueryByKey);
btnQueryOneAttribute = (Button) findViewById(R.id.btnQueryOneAttribute);
btnQueryOneAttribute.setOnClickListener(this);
btnQueryAll.setOnClickListener(this);
btnQueryByKey.setOnClickListener(this);
btnPost.setOnClickListener(this);
btnPut.setOnClickListener(this);
btnDelete.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btnQueryOneAttribute:
url = urlService.GetOneAtt;
GetRequest getOneAttributeRequest = new GetRequest(MainActivity.this,url);
getOneAttributeRequest.execute();
break;
case R.id.btnQueryAll:
url = urlService.GetAllURL;
GetRequest getAllRequest = new GetRequest(MainActivity.this,url);
getAllRequest.execute();
break;
case R.id.btnQueryByKey :
url = urlService.GetOneByKey;
GetRequest getByKeyRequest = new GetRequest(MainActivity.this,url);
getByKeyRequest.execute();
break;
case R.id.btnPost:
url = urlService.ADDURL;
PostRequest postRequest = new PostRequest(MainActivity.this,url);
postRequest.execute();
break;
case R.id.btnPut:
url = urlService.PutURL;
PutRequest putRequest = new PutRequest(MainActivity.this,url);
putRequest.execute();
break;
case R.id.btnDelete:
url = urlService.DeleteURL;
DeleteRequest deleteRequest = new DeleteRequest(MainActivity.this,url);
deleteRequest.execute();
break;
}
}
}
6.创建展示结果的Activity
public class ResultActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
init();
}
private void init() {
Intent intent = getIntent();
String value = intent.getStringExtra("testIntent");
TextView tvBack = (TextView) findViewById(R.id.tvBack);
tvBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ResultActivity.this.finish();
}
});
TextView tvResult = (TextView) findViewById(R.id.tvResult);
tvResult.setText(value);
}
}
7.结果展示
3.ReactNative下使用OData
1.创建ReactNative应用
2.封装Fetch请求工具类
var HTTPUtil = {};
import {
ToastAndroid
} from 'react-native';
/**
* 基于 fetch 封装的 GET请求
* @param url
* @param params {}
* @param headers
* @returns {Promise}
*/
HTTPUtil.get = function(url) {
return new Promise(
function (resolve, reject) {
fetch(url, {
method: 'GET',
}).then(
(response) => {
return response;
})
.then((response) => {
resolve(response);
})
.catch((err)=> {
reject({status:-1});
})
})
}
/**
* 基于 fetch 封装的 POST请求 FormData 表单数据
* @param url
* @param formData
* @param headers
* @returns {Promise}
*/
HTTPUtil.post = function(url, formData) {
return new Promise(function (resolve, reject) {
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
})
.then((response) => {
return response;
})
.then((response) => {
resolve(response);
})
.catch((err)=> {
reject({status:-1});
})
})
}
/**
* 基于 fetch 封装的 POST请求 Json文件数据
* @param url
* @param data
* @param callback
* @returns {Promise}
*/
HTTPUtil.postJson = function(url, data) {
var fetchOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
fetch(url, fetchOptions)
.then((response) =>{
return response;
}).done();
}
/**
* 基于 fetch 封装的 PUT请求 Json文件数据
* @param url
* @param data
* @param callback
* @returns {Promise}
*/
HTTPUtil.putJson = function(url, data) {
return new Promise(function (resolve, reject) {
fetch(url, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'content-Type': 'application/json'
},
body: JSON.stringify(data)
}) .then((response) => {
return response;
})
.then((response) => {
resolve(response);
})
.catch((err)=> {
reject({status:-1});
})
})
}
/**
* 基于 fetch 封装的 DELETE请求
* @param url
* @param params {}
* @returns {Promise}
*/
HTTPUtil.delete = function(url) {
return new Promise(function (resolve, reject) {
fetch(url, {
method: 'DELETE'
}).then((response) => {
ToastAndroid.show("=1!="+ response.status, ToastAndroid.SHORT);
return response;
})
.then((response) => {
resolve(response);
})
.catch((err)=> {
reject({status:-1});
})
})
}
export default HTTPUtil;
3.创建请求管理类RequestManager
let RequestManager = {};
import {
ToastAndroid,
AsyncStorage
} from 'react-native';
import HttpUtil from './HttpUtil';
import RequsetURL from './RequsetURL';
import AsyncStorageUtil from '../AsyncStorageUtil';
import MainView from '../../View/MainView';
let json = {
"UserName":"fang",
"FirstName":"Lewis",
"LastName":"Black",
"Emails":[
"lewisblack@example.com"
],
"AddressInfo": [
{
"Address": "187 Suffolk Ln.",
"City": {
"Name": "Boise",
"CountryRegion": "United States",
"Region": "ID"
}
}
]
};
let jsonUpdata = {
"FirstName": "Gao",
"LastName": "Xiuyang"
}
RequestManager.state;
RequestManager.getAll = function() {
return HttpUtil.get(RequsetURL.GetAllURL).then(RequestManager.handleResponse);
}
RequestManager.getByKey = function() {
return HttpUtil.get(RequsetURL.GetBuKey).then(RequestManager.handleResponse);
};
RequestManager.postCreat = function() {
return HttpUtil.post(RequsetURL.PostCreat,json).then(RequestManager.handleResponse);
}
RequestManager.putUpdata = function() {
return HttpUtil.putJson(RequsetURL.PutUpdata,jsonUpdata).then(RequestManager.handleResponse);
}
RequestManager.delete = function() {
return HttpUtil.delete(RequsetURL.DeleteURL).then(RequestManager.handleResponse);
}
RequestManager.handleResponse= function(response) {
console.log(response.url, response.statusText);
if (response.ok) {
if(response.status==204){
AsyncStorageUtil.set('Content', "成功!!!!");
}else{
response.text().then(function(text){
AsyncStorageUtil.set('Content', text);
});
}
return response;
}else {
console.error('An error occurred', response);
}
}
export default RequestManager;
4.创建URL管理类
var RequsetURL = {};
RequsetURL.GetAllURL = 'http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People';
RequsetURL.GetBuKey = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People?$filter=FirstName eq 'Lewis'";
RequsetURL.PostCreat = 'http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People';
RequsetURL.PutUpdata = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People('fang')"
RequsetURL.DeleteURL = "http://services.odata.org/TripPinRESTierService/(S(ttgxui24dxjyngne0nkqgyqi))/People('fang')"
export default RequsetURL;
5.创建AsyncStorageUtil进行本地存储
var AsyncStorageUtil = {};
import {
AsyncStorage,
ToastAndroid
} from 'react-native';
AsyncStorageUtil.set = function(key, value){
AsyncStorage.setItem(key, value, () => {
AsyncStorage.mergeItem(key, value, () => {
AsyncStorage.getItem(key, (err, result) => {
if(result!==null){
return true;
}else{
return false;
}
});
});
});
}
AsyncStorageUtil.get = function(key){
Result=''
AsyncStorage.getItem(key, (err, result) => {
return result
});
}
export default AsyncStorageUtil;
6.创建MainView
'use strict';
import React,{Component} from 'react'
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
Alert,
Dimensions,
AsyncStorage,
Platform,
NativeModules,
ToastAndroid,
TouchableOpacity
} from 'react-native';
import AsyncStorageUtil from '../Utils/AsyncStorageUtil';
import RequestManager from '../Utils/RequestApiUtils/RequestManager';
import HttpUtil from '../Utils/RequestApiUtils/HttpUtil';
import RequsetURL from '../Utils/RequestApiUtils/RequsetURL';
import ApiSevice from '../Utils/RequestApiUtils/ApiSevice';
import Result from './ResultView';
export default class page1 extends React.Component {
constructor(props) {
super(props);
this.state = {
content:""
};
}
getByKey(){
let thiz = this;
RequestManager.getByKey().then(x => {
if(x.ok){
thiz.props.navigator.push({
component:Result
});
}else{
ToastAndroid.show('请重试', ToastAndroid.SHORT);
}
});
}
getAll(){
let thiz = this;
RequestManager.getAll().then(x => {
if(x.ok){
thiz.props.navigator.push({
component:Result
});
}else{
ToastAndroid.show('请重试', ToastAndroid.SHORT);
}
});
}
postCreat(){
let thiz = this;
RequestManager.postCreat().then(x => {
if(x.ok){
thiz.props.navigator.push({
component:Result
});
}else{
ToastAndroid.show('请重试', ToastAndroid.SHORT);
}
});
}
putUpdata(){
let thiz = this;
RequestManager.putUpdata().then(x => {
if(x.ok){
thiz.props.navigator.push({
component:Result
});
}else{
ToastAndroid.show('请重试', ToastAndroid.SHORT);
}
});
}
delete(){
let thiz = this;
RequestManager.delete().then(x => {
if(x.ok){
thiz.props.navigator.push({
component:Result
});
}else{
ToastAndroid.show('请重试', ToastAndroid.SHORT);
}
});
}
render() {
return (
<View style = {styles.containers}>
<TouchableOpacity style={styles.btn} onPress={this.postCreat.bind(this)} >
<Text style={styles.btnText}>Post(增加)</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.getAll.bind(this)} >
<Text style={styles.btnText}>Get(查询全部)</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.getByKey.bind(this)} >
<Text style={styles.btnText}>Get(条件查询)</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.putUpdata.bind(this)} >
<Text style={styles.btnText}>Put(修改)</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.delete.bind(this)} >
<Text style={styles.btnText}>Delete(删除)</Text>
</TouchableOpacity>
</View>
)
}
}
let styles = StyleSheet.create({
containers: {
backgroundColor: '#f1f1f1',
height: Dimensions.get('window').height
},
btn: {
backgroundColor: "#0066cc",
height: 40,
borderRadius: 4,
marginLeft: 20,
marginRight: 20,
marginTop: 20,
justifyContent: 'center',
},
btnText: {
textAlign: 'center',
color: '#fff',
fontSize: 16
}
})
7.创建ResultView用于展示结果
'use strict';
import React,{Component} from 'react'
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
Alert,
Dimensions,
AsyncStorage,
Platform,
NativeModules,
ToastAndroid,
ScrollView,
TouchableOpacity
} from 'react-native';
import AsyncStorageUtil from '../Utils/AsyncStorageUtil';
import RequestManager from '../Utils/RequestApiUtils/RequestManager';
export default class page1 extends React.Component {
constructor(props) {
super(props);
AsyncStorage.getItem('Content', (err, result) => {
this.setState({content:result})
AsyncStorage.mergeItem('Content', result);
});
this.state = {
content:""
};
}
onBack(){
const { navigator } = this.props;
if(navigator) {
navigator.pop();
}
}
render() {
return (
<View style = {styles.containers}>
<View style = {styles.titleView}>
<TouchableOpacity onPress={this.onBack.bind(this)} >
<Text style={styles.loginBtn}>返回</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.scrollView}>
<Text style = {styles.textView}>
{this.state.content}
</Text>
</ScrollView>
</View>
)
}
}
let styles = StyleSheet.create({
scrollView: {
height: Dimensions.get('window').height-50,
},
containers: {
backgroundColor: '#f1f1f1',
height: Dimensions.get('window').height-25,
},
titleView: {
backgroundColor: '#4799e5',
height: 45,
flexDirection: 'row',
alignItems: 'center'
},
textView:{
margin: 20,
color: '#666666',
fontSize: 14
},
loginBtn: {
fontSize: 16,
marginLeft: 20,
color: '#fff',
alignSelf: 'flex-end'
},
})
8.结果展示
4.源码地址
1.PostMan(接口测试工具)
http://download.csdn.net/detail/lanye11/9685964
2.Android下使用OData进行数据访问源码
http://download.csdn.net/detail/lanye11/9689924