nodeJS开发一套完整的项目(6、省市县模块)

本章节我们谈谈省市县模块的编写,我们先把城市的基础数据展示出来,然后我们看看如何在后面如何调用。

城市基础数据

我们在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),同时您也可以扫描下方的二维码关注我们的公众号,每天我们都会分享经验,谢谢大家。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容