react-native 实现的移动客户端支持 安卓和苹果手机
NodeJs + Express + MysqL 实现的Restful API后端数据服务接口
需要的组件全部安装完毕后,我们可以看看package.json文件的内容,尤其是版本信息
{
"name": "zigoo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"body-parser": "^1.18.2",
"express": "^4.16.3",
"MysqLi": "^2.2.2",
"react": "^16.3.0-alpha.1",
"react-native": "0.54.3"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"jest": "22.4.3",
"react-test-renderer": "^16.3.0-alpha.1"
},
"jest": {
"preset": "react-native"
}
}
项目文件的层次结构
将MysqL启动服务的目录配置成全局路径:
myths-Mac:~ myth$ pwd
/Users/myth
首先在Mac OS系统中关掉MysqL服务程序 步骤是:System Preferences ---> MysqL ---> Stop MysqL Server
myths-Mac:~ myth$ sudo su
Password: 123 登录 Mac OS系统的密码
你必须要修改数据库的编码 默认是拉丁文编码 我们需要的是utf-8编码,不这个干 你的中文数据肯定存储的是乱码:
sh-3.2# cat > /etc/my.cnf
# Example MysqL config file for small systems.
#
# This is for a system with little memory (<= 64M) where MysqL is only used
# from time to time and it's important that the MysqLd daemon
# doesn't use much resources.
#
# MysqL programs look for option files in a set of
# locations which depend on the deployment platform.
# You can copy this option file to one of those
# locations. For information about these locations,see:
# http://dev.MysqL.com/doc/MysqL/en/option-files.html
#
# In this file,you can use all long options that a program supports.
# If you want to know which options a program supports,run the program
# with the "--help" option.
# The following options will be passed to all MysqL clients
[client]
default-character-set=utf8
#password = your_password
port = 3306
socket = /tmp/MysqL.sock
# Here follows entries for some specific programs
# The MysqL server
[MysqLd]
default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci
port = 3306
socket = /tmp/MysqL.sock
skip-external-locking
key_buffer_size = 16K
max_allowed_packet = 1M
table_open_cache = 4
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 128K
# Don't listen on a TCP/IP port at all. This can be a security enhancement,
# if all processes that need to connect to MysqLd run on the same host.
# All interaction with MysqLd must be made via Unix sockets or named pipes.
# Note that using this option without enabling named pipes on Windows
# (using the "enable-named-pipe" option) will render MysqLd useless!
#
#skip-networking
server-id = 1
# Uncomment the following if you want to log updates
#log-bin=MysqL-bin
# binary logging format - mixed recommended
#binlog_format=mixed
# Causes updates to non-transactional engines using statement format to be
# written directly to binary log. Before using this option make sure that
# there are no dependencies between transactional and non-transactional
# tables such as in the statement INSERT INTO t_myisam SELECT * FROM
# t_innodb; otherwise,slaves may diverge from the master.
#binlog_direct_non_transactional_updates=TRUE
# Uncomment the following if you are using InnoDB tables
#innodb_data_home_dir = /usr/local/MysqL/data
#innodb_data_file_path = ibdata1:10M:autoextend
#innodb_log_group_home_dir = /usr/local/MysqL/data
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
#innodb_buffer_pool_size = 16M
#innodb_additional_mem_pool_size = 2M
# Set .._log_file_size to 25 % of buffer pool size
#innodb_log_file_size = 5M
#innodb_log_buffer_size = 8M
#innodb_flush_log_at_trx_commit = 1
#innodb_lock_wait_timeout = 50
[MysqLdump]
quick
max_allowed_packet = 16M
[MysqL]
no-auto-rehash
# Remove the next comment character if you are not familiar with sql
#safe-updates
[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
[MysqLhotcopy]
interactive-timeout
开始跳过输入密码这步进入MysqL服务器:
sh-3.2# MysqLd_safe --skip-grant-tables --skip-networking &
sh-3.2# MysqL -uroot
MysqL> UPDATE user SET authentication_string=PASSWORD('!8@e21#tw') WHERE user='root';
MysqL> quit
myths-Mac:~ myth$ MysqL -uroot -p
回车输入密码 !8@e21#tw
MysqL> use MysqL --切换数据库失败不要慌张 它强行让你修改上面刚刚设置的密码 你改成裸奔的 123456 作为密码都不成问题
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
MysqL> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
Query OK,0 rows affected (0.00 sec)
你想允许任一IP地址都可以远程去连接你的MysqL数据库服务器,不明白?其中有这样一种情况,你用自己实际的网卡IP去连接数据库是连不上的,我们可以接着执行一条如下的sql语句即可,其中百分号表示任一IP地址均可访问本数据库服务器,像建立数据库同步账户,就需要这么干:
MysqL> GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
MysqL>FLUSH PRIVILEGES;
开始真正步入正题啦 :
创建数据库 MysqL> CREATE DATABASE testdb;
创建users数据表:
MysqL> CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL,
`mobile` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创始化2条记录:
MysqL> insert into users(`id`,`name`,`email`,`mobile`) values(1,'Jack','jack@gmail.com','13570845544');
MysqL> insert into users(`id`,`mobile`) values(2,'Jason','jason@sina.com','1380013800');
MysqL> quit
我的苹果系统网卡地址是:192.168.123.47
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
options=b<RXCSUM,VLAN_HWTAGGING>
ether 00:0c:29:60:24:04
inet6 fe80::e0:bbf8:cc2c:3177%en0 prefixlen 64 secured scopeid 0x4
inet 192.168.123.47 netmask 0xffffff00 broadcast 192.168.123.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
status: active
utun0: flags=8051<UP,POINTOPOINT,MULTICAST> mtu 2000
inet6 fe80::6ea7:d379:ecc3:e2a6%utun0 prefixlen 64 scopeid 0x5
nd6 options=201<PERFORMNUD,DAD>
myths-Mac:~ myth$
我们可以用sqlyog 这样的可视化客户端工具去操作苹果系统中的MysqL服务器了,没这个工具自己在网上随便下载一个
开始使用命令建立一个 react-native 项目:
myths-Mac:~ myth$ react-native init zigoo
myths-Mac:~ myth$ pwd
/Users/myth
myths-Mac:~ myth$ cd zigoo
myths-Mac:~ myth$ yarn add express
myths-Mac:~ myth$ yarn add MysqLi
myths-Mac:~ myth$ yarn add body-parser
使用Android Studio 或者其它你喜欢的开发工具在App.js同一目录中建立一个空的server.js代码文件,你可以用命令查看一下:
myths-Mac:zigoo myth$ ls
App.js app.json ios server.js
__tests__ gen node_modules yarn.lock
android index.js package.json
myths-Mac:zigoo myth$ cat server.js
var express = require('express');
var app = express();
var MysqL = require('MysqL');
var bodyParser = require('body-parser');
app.use(bodyParser.json({type: 'application/json'}));
app.use(bodyParser.urlencoded({extended: true}));
var conn = MysqL.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'testdb'
});
var server = app.listen(9090,function(){
var host = server.address().address
var port = server.address().port
console.log('server start')
});
conn.connect(function(error){
if(!!error) console.log('error');
else console.log('connected');
});
app.get('/users',function(req,res){
conn.query('SELECT * FROM users',function(error,rows,fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.send(rows);
}
})
});
app.post('/users',res){
conn.query('INSERT INTO users SET ?',req.body,fields){
if(!!error) console.log('error');
else {
console.log(req.body)
console.log(rows);
res.send(JSON.stringify(rows));
}
})
})
app.get('/users/:id',res){
conn.query('SELECT * FROM users WHERE id=?',req.params.id,fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.send(JSON.stringify(rows));
}
})
});
app.delete('/users/:id',res){
conn.query('DELETE FROM users WHERE id=?',fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.end('deleted successfully');
}
})
});
app.put('/users',res){
conn.query('UPDATE users SET name=?,email=?,mobile=? WHERE id=?',
[req.body.name,req.body.email,req.body.mobile,req.body.id],fields){
if(!!error) console.log('error');
else {
console.log(req.body)
console.log(rows);
res.send(JSON.stringify(rows));
}
})
})
/*
启动方式
myths-Mac:zigoo myth$ node ./server.js
访问数据接口
http://localhost:9090/users
[{"id":1,"name":"Jack","emial":"jack@gmail.com","mobile":"13570845544"},{"id":2,"name":"Jason","emial":"jason@sina.com","mobile":"1380013800"}]
*/
现在介绍如何用Postman工具来测试上面Restful API 数据操作接口
使用如下命令启动 (MysqL + NodeJs + Express)实现的服务器端服务程序:
$cd /Users/myth/zigoo && node ./server.js
Restful API 测试工具Postman
Method
GET http://192.168.123.47:9090/users
Output Raw
[{"id":1,"email":"jack@gmail.com",
{"id":2,"email":"jason@sina.com","mobile":"13800138000"}]
(二). 新增一个用户
Method
Headers
Accept application/json
Content-Type application/x-www-form-urlencoded
Body x-www-form-urlencoded
key value
name James
email james@126.com
mobile 13800888010
Output Pretty
{"fieldCount":0,"affectedRows":1,"insertId":16,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}
查看刚刚新增的1条用户记录:
myths-Mac:~ myth$ MysqL -uroot -p123456
MysqL: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MysqL monitor. Commands end with ; or \g.
Your MysqL connection id is 516
Server version: 5.7.21 MysqL Community Server (GPL)
Copyright (c) 2000,2018,Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MysqL> use testdb
Database changed
MysqL> select * from users;
+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | Jason | jason@sina.com | 13800138000 |
| 3 | James | james@126.com | 13800888010 |
+----+-------+----------------+-------------+
3 rows in set (0.00 sec)
MysqL>
Method
GET http://192.168.123.47:9090/users/3
Output Raw
[{"id":3,"name":"James","email":"james@126.com","mobile":"13800888010"}]
Method
DELETE http://192.168.123.47:9090/users/3Output Raw
deleted successfully
查看刚刚删除的1条记录(主键 id =3)是否真的不存在,显示它已经被删除:
MysqL> select * from users;+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | Jason | jason@sina.com | 13800138000 |
+----+-------+----------------+-------------+
2 rows in set (0.00 sec)
MysqL>
(五). 根据主键(id = 2)还有其它所有字段的值修改一条已经存在的记录:
Method
PUT http://192.168.123.47:9090/users
Headers
Accept application/json
Content-Type application/x-www-form-urlencoded
Body x-www-form-urlencoded
key value
name James
email james@126.com
mobile 13800888010
id 2
Output Pretty
{"fieldCount":0,"insertId":0,"message":"(Rows matched: 1 Changed: 1 Warnings: 0","changedRows":1}
查看刚刚删修改的1条记录(主键 id =2)是否真的已被更改,显示它已经被修改过了:
MysqL> select * from users;
+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | James | james@126.com | 13800888010 |
+----+-------+----------------+-------------+
2 rows in set (0.00 sec)
现在接下来实现移动端react-native 代码,只用到了一个App.js文件,代码如下:
import React,{ Component } from 'react';
import {
StyleSheet,
Text,
TextInput,
View,
ScrollView,
TouchableHighlight
} from 'react-native';
export default class App extends Component {
constructor(props){
super(props)
this.state = {
apiData: [],
naData: []
}
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}
onGetUsers = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'GET'
}).then((response) => {
return response.json();
}).then((jsonData) => {
this.setState({
apiData: jsonData,
})
console.log(this.state.apiData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}
onPostUser = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: this.name,email: this.email,mobile: this.mobile })
}).then((response) => {
return response.json();
}).then((jsonData) => {
this.setState({
naData: jsonData,
})
console.log(this.state.naData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}
onGetUser = () => {
fetch('http://192.168.123.47:9090/users/'+ this.uid,
})
console.log(this.state.apiData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}
onDeleteUser = () => {
fetch('http://192.168.123.47:9090/users/'+ this.uid,{
method: 'DELETE'
}).then((response) => {
console.log(response.rows);
}).catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}
onPutUser = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'PUT',mobile: this.mobile,id: this.uid })
}).then((response) => {
return response.json();
}).catch((error) => {
console.warn(error);
}).done();
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}
render() {
const data = this.state.apiData;
let dataDisplay = data.map(function(jsonData){
return (
<View key={jsonData.id}>
<View style={{flexDirection: 'row'}}>
<Text style={{color: '#000',width: 30}}>{jsonData.id}</Text>
<Text style={{color: '#00f',width: 60}}>{jsonData.name}</Text>
<Text style={{color: '#000',width: 140}}>{jsonData.email}</Text>
<Text style={{color: '#00f',width: 100}}>{jsonData.mobile}</Text>
</View>
</View>
)
});
return (
<View style={styles.container}>
<Text style={{fontSize: 20,textAlign: 'center',marginTop: 10}}>
My App Users
</Text>
<View style={{height: 2,backgroundColor: '#ccc',marginBottom: 10,width: '90%'}}></View>
<TextInput style={styles.input}
placeholder = 'id'
onChangeText ={(text) => {this.uid = text}}
value = {this.id}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'name'
onChangeText ={(text) => {this.name = text}}
value = {this.name}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'email'
onChangeText ={(text) => {this.email = text}}
value = {this.email}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'mobile'
onChangeText ={(text) => {this.mobile = text}}
value = {this.mobile}
underlineColorAndroid = 'transparent'
/>
<TouchableHighlight style={styles.button} onPress={this.onGetUsers}>
<Text style={styles.buttonText}>GET All Users</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onPostUser}>
<Text style={styles.buttonText}>POST a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onGetUser}>
<Text style={styles.buttonText}>GET a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onDeleteUser}>
<Text style={styles.buttonText}>DELETE a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onPutUser}>
<Text style={styles.buttonText}>PUT a User</Text>
</TouchableHighlight>
<ScrollView contentContainerStyle={styles.container}>
{dataDisplay}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginTop: 5,
flex: 1,
alignItems: 'center',
backgroundColor: '#fff',
},
input: {
textAlign: 'left',
height: 30,
width: '90%',
padding: 4,
marginBottom: 7,
fontSize: 16,
fontWeight:'500',
borderWidth: 1,
button: {
paddingTop: 10,
paddingBottom: 10,
borderRadius: 25,
marginTop: 3,
marginBottom: 3,
backgroundColor: '#00bcd4'
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontSize:16,
}
});
最后来看看iOS&Android模拟器中运行的效果截图吧