本章节我们谈谈省市县模块的编写,我们先把城市的基础数据展示出来,然后我们看看如何在后面如何调用。
城市基础数据
我们在initData文件夹里创建cities.js文件,里面是城市数据。由于数据量比较大,在这里无法贴出,后面我会把下载地址放出来。
创建城市model
在web->models->v1文件夹下创建city.js文件,具体代码如下:
/**
* Created by admin on 2017/9/28 0020.
*/
'use strict';
import mongoose from 'mongoose';
import cityData from '../../../initData/cities';
const citySchema = new mongoose.Schema({
data:{}
});
//添加 mongoose 静态方法,静态方法在Model层就能使用,statics是静态方法。methods是实例方法
citySchema.statics.cityGuess = function(name) {
/* promise是一个异步编程的抽象,它是一个返回值或抛出exception的代理对象,
一般promise对象都有一个then方法,这个then方法是我们如何获得返回值(成功实现承诺的结果值,称为fulfillment)
或抛出exception(拒绝承诺的理由,称为rejection),then是用两个可选的回调作为参数
Async/await的主要益处是可以避免回调地狱(callback hell)问题。
async 表示这是一个async函数,await只能用在这个函数里面。async 对象也是一个 promise 对象。
await 表示在这里等待promise返回结果了,再继续执行。
await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,不过那样就没有意义了…)
*/
return new Promise(async (resolve, reject) => {
const firstWord = name.substr(0,1).toUpperCase();
try{
const city = await this.findOne();
//Object.entries返回的是二维数组
Object.entries(city.data).forEach(item => {
if(item[0] == firstWord) {
item[1].forEach(cityItem => {
if(cityItem.pinyin == name) {
resolve(cityItem);
}
})
}
});
} catch(err) {
reject({
name: 'ERROR_DATA',
message: '查找数据失败'
});
console.error(err);
}
});
};
//热门城市
citySchema.statics.cityHot = function() {
return new Promise(async (resolve,reject) => {
try{
const city = await this.findOne();
resolve(city.data.hotCities);
} catch(err) {
reject({
name: 'ERROR_DATA',
message: '查找数据失败'
});
console.error(err);
}
});
};
//获取所有城市
citySchema.statics.cityGroup = function() {
return new Promist(async (resolve,reject) => {
try{
const city = await this.findOne();
const cityObj = city.data;
delete(cityObj._id);
delete(cityObj.hotCities);
resolve(cityObj);
} catch(err) {
reject({
name: 'ERROR_DATA',
message: '查找数据失败'
});
console.error(err);
}
});
};
//根据城市ID获取城市信息
citySchema.statics.getCityById = function(id) {
return new Promise(async (resolve,reject) => {
try{
const city = await this.findOne();
Object.entries(city.data).forEach(item => {
if(item[0] !== '_id' && item[0] !== 'hotCities') {
item[1].forEach(cityItem => {
if(cityItem == id) {
resolve(cityItem);
}
});
}
});
} catch(err) {
reject({
name: 'ERROR_DATA',
message: '查找数据失败'
});
}
});
};
const Cities = mongoose.model('Cities',citySchema);
Cities.findOne((err, data) => {
if(!data) {
Cities.create({data: cityData});
}
});
export default Cities;
编写城市控制器
在web->controller->v1文件夹下,创建city.js文件,具体代码如下:
/**
* Created by admin on 2017/9/20 0020.
*/
'use strict';
import Cities from '../../models/v1/city';
import pinyin from 'pinyin';
import AddressComponent from '../../prototype/addressComponent';
class CityHandle extends AddressComponent {
//构造函数
constructor() {
super();
this.getCity = this.getCity.bind(this);
this.getExactAddress = this.getExactAddress.bind(this);
this.pois = this.pois.bind(this);
}
//获取城市
async getCity(req, res, next) {
const type = req.query.type;
let cityInfo;
try{
switch(type) {
case "guess":
const city = await this.getCityName(req);
cityInfo = await Cities.cityGuess(city);
break;
case "hot":
cityInfo = await Cities.cityHot();
break;
case "group":
cityInfo = await Cities.cityGroup();
break;
default:
res.send({
name:'ERROR_QUERY_TYPE',
message:'参数错误'
});
return;
}
res.send(cityInfo);
} catch(err) {
res.send({
name: 'ERROR_DATA',
message: '获取数据失败'
})
}
}
//根据编号ID获取城市
async getCityById(req, res, next) {
const cityid = req.params.id;
if(isNaN(cityid)) {
res.send({
name:'ERROR_PARAMS_TYPE',
message:'参数错误'
});
return;
}
try{
const cityInfo = await Cities.getCityById(cityid);
res.send(cityInfo);
} catch(err) {
res.send({
name:'ERROR_DATA',
message:'获取数据失败'
})
}
};
//获取城市名称
async getCityName(req) {
let cityInfo;
try{
cityInfo = await this.guessPosition(req);
} catch(err) {
console.error('获取IP位置信息失败',err);
res.send({
name: 'ERROR_DATA',
message: '获取数据失败'
});
return;
}
//汉字转换成拼音
const pinyinArr = pinyin(cityInfo.city, {
style:pinyin.STYLE_NORMAL,
});
let cityName = '';
pinyinArr.forEach(item => {
cityName += item[0];
});
return cityName;
}
//获取地址
async getExactAddress(req, res, next) {
try{
const position = await this.geocoder(req);
res.send(position);
} catch(err) {
console.log('获取精确位置失败');
res.send({
name:'ERROR_DATA',
message:'获取精确位置失败'
})
}
}
async pois(req, res, next) {
const geohash = req.params.geohash;
try{
if(geohash.indexOf(',') == -1) {
throw new Error('参数错误');
}
} catch(err) {
console.log('参数错误');
res.send({
status: 0,
type: 'ERROR_PARAMS',
message: '参数错误'
});
return;
}
const poisArr = geohash.split(',');
try{
const result = await this.getpois(poisArr[0], poisArr[1]);
const address = {
address: result.result.address,
city: result.result.address_component.province,
geohash,
latitude: poisArr[0],
longitude: poisArr[1],
name: result.result.formatted_addresses.recommend,
};
res.send(address);
} catch(err) {
console.log('getpois返回信息失败');
res.send({
status: 0,
type: 'ERROR_DATA',
message: '获取数据失败'
})
}
}
}
export default new CityHandle();
编写路由信息
在routes文件夹创建v1.js文件,这里对应的模型、控制器里的信息,具体代码如下:
import express from 'express';
import CityHandle from '../web/controller/v1/city';
const baseHandle = new BaseComponent();
const router = express.Router();
router.get('/cities', CityHandle.getCity);
router.get('/cities/:id', CityHandle.getCityById);
router.get('/exactaddress', CityHandle.getExactAddress);
router.post('/addimg/:type', baseHandle.uploadImg);
export default router;
然后我们在routes->index.js里面把v1的内容加进去,具体如下:
'use strict';
import admin from './admin';
import statis from './statis';
import v1 from './v1';
export default app => {
app.use('/admin',admin);
app.use('/statis',statis);
app.use('/v1', v1);
};
下面我们就来测试我们的模块是否可行。打开目录下的cmd.dat,这个文件在一开始我们就创建过了,不懂的朋友可以看看第二节。
我们打开cmd.dat,然后输入“npm run dev”,显示如下:
然后在地址栏里输入 http://127.0.0.1:3000/v1/cities?type=hot,这是获取热点城市接口,数据显示如图:
其他的接口大家可以试试看,在此就不一一演示了。
相关章节
nodeJS开发一套完整的项目(1、基础配置)
nodeJS开发一套完整的项目(2、相关模块介绍)
nodeJS开发一套完整的项目(3、数据库链接和项目启动)
nodeJS开发一套完整的项目(4、编写底层功能模块)
nodeJS开发一套完整的项目(5、开发用户模块)
为了更好的服务大家,请加入我们的技术交流群:(511387930),同时您也可以扫描下方的二维码关注我们的公众号,每天我们都会分享经验,谢谢大家。