React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

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"
  }
}

项目文件的层次结构

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

将MySQL启动服务的目录配置成全局路径:

myths-Mac:~ myth$ pwd
/Users/myth

myths-Mac:~ myth$ echo 'export PATH=$PATH:/usr/local/mysql/bin' >> ~/.bash_profile

你忘记了MySQL数据库的root密码

首先在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> use mysql

mysql> UPDATE user SET authentication_string=PASSWORD('[email protected]#tw') WHERE user='root';

mysql> quit

myths-Mac:~ myth$ mysql -uroot -p

回车输入密码 [email protected]#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','[email protected]','13570845544');

mysql> insert into users(`id`,`name`,`email`,`mobile`) values(2,'Jason','[email protected]','1380013800');

mysql> quit

我的苹果系统网卡地址是:192.168.123.47

myths-Mac:~ myth$ ifconfig
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,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    options=b<RXCSUM,TXCSUM,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,RUNNING,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',function(req,res){
    conn.query('INSERT INTO users SET ?',req.body,function(error,rows,fields){
        if(!!error) console.log('error');
        else {
            console.log(req.body)
            console.log(rows);
            res.send(JSON.stringify(rows));
        }
    })
})

app.get('/users/:id',function(req,res){
    conn.query('SELECT * FROM users WHERE id=?',req.params.id,function(error,rows,fields){
        if(!!error) console.log('error');
        else {
            console.log(rows);
            res.send(JSON.stringify(rows));
        }
    })
});

app.delete('/users/:id',function(req,res){
    conn.query('DELETE FROM users WHERE id=?',req.params.id,function(error,rows,fields){
        if(!!error) console.log('error');
        else {
            console.log(rows);
            res.end('deleted successfully');
        }
    })
});

app.put('/users',function(req,res){
    conn.query('UPDATE users SET name=?,email=?,mobile=? WHERE id=?',
    [req.body.name,req.body.email,req.body.mobile,req.body.id],function(error,rows,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":"[email protected]","mobile":"13570845544"},{"id":2,"name":"Jason","emial":"[email protected]","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,"name":"Jack","email":"[email protected]","mobile":"13570845544"},

{"id":2,"name":"Jason","email":"[email protected]","mobile":"13800138000"}]

(二). 新增一个用户

Method

POST  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  [email protected]
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  | [email protected] | 13570845544 |
|  2 | Jason | [email protected] | 13800138000 |
|  3 | James | [email protected]  | 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":"[email protected]","mobile":"13800888010"}]

(四). 根据主键删除一个用户

Method

DELETE  http://192.168.123.47:9090/users/3

Output Raw

deleted successfully

查看刚刚删除的1条记录(主键 id =3)是否真的不存在,显示它已经被删除:

mysql> select * from users;
+----+-------+----------------+-------------+
| id | name  | email          | mobile      |
+----+-------+----------------+-------------+
|  1 | Jack  | [email protected] | 13570845544 |
|  2 | Jason | [email protected] | 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  [email protected]
mobile 13800888010
id         2

Output Pretty

{"fieldCount":0,"affectedRows":1,"insertId":0,"serverStatus":2,"warningCount":0,"message":"(Rows matched: 1  Changed: 1  Warnings: 0","protocol41":true,"changedRows":1}

查看刚刚删修改的1条记录(主键 id =2)是否真的已被更改,显示它已经被修改过了:

mysql> select * from users;
+----+-------+----------------+-------------+
| id | name  | email          | mobile      |
+----+-------+----------------+-------------+
|  1 | Jack  | [email protected] | 13570845544 |
|  2 | James | [email protected]  | 13800888010 |
+----+-------+----------------+-------------+
2 rows in set (0.00 sec)

mysql>

现在接下来实现移动端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,{
     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;
  }

    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',
       headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
       },
       body: JSON.stringify({ name: this.name, email: this.email, 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,
    width: '90%',
    backgroundColor: '#00bcd4'
  },
  buttonText: {
    color: '#fff',
    textAlign: 'center',
    fontSize:16,
    fontWeight:'500',
  }

});

最后来看看iOS&Android模拟器中运行的效果截图吧

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口