node + express 搭建后端服务,连接 mysql 数据库,存入 geojson 数据

建立mysql数据库

登录mysql后,创建一个新库。我的库名是geometry。
通过osm获得的poi信息切出上海杨浦区部分输出为geojson。
通过如下代码将geojson数据存入

/*
 * @Author: citrusrlia@foxmail.com
 * @FilePath: \shy-node-back\writeJsonInsert.js
 * @Date: 2021-05-24 11:21:32
 * @Description: geojson数据入库
 */
const mysql = require("mysql");
const fs = require("fs");

let result = fs.readFileSync("./statics/yangpu_poi.json"); //osm数据
let data = JSON.parse(result.toString());
let ready = data.features;

const connection = mysql.createConnection({
  host: "localhost",
  user: "************",
  password: "*************",
  database: "************",
  port: "6326",
});

connection.connect();
let AddParam = [];
for (let i = 0, l = ready.length; i < l; i++) {
  let osm_id = ready[i].properties.osm_id,
    type = ready[i].geometry.type,
    coordinateStr = ready[i].geometry.coordinates.toString(),
    code = ready[i].properties.code,
    fclass = ready[i].properties.fclass,
    name = ready[i].properties.name;
  AddParam = [osm_id, type, coordinateStr, code, fclass, name];
  connection.query(
    "INSERT INTO geometry(osm_id,type,coordinates,code,fclass,name) VALUES(?,?,?,?,?,?)",
    AddParam,
    function (error, results) {
      if (error) {
        console.log("INSERT ERROR - ", error.message);
        return;
      }
      console.log("INSERT ID:", results);
    }
  );
}

connection.end();

这里将经纬度数据转化为字符串存储,部分长度会超过255字节限制,字段类型需要改为长文本类型。


image.png

现在获得了储存了geojson数据的表。

使用express框架搭建服务

首先安装express和express脚手架

npm i express
npm i express-generator

运行 建立名叫app的项目 会得到如下图的目录结构

express app
image.png

先在public/javascripts中新建sqls.js 用module.exports输出各增删改查方法

/*
 * @Author: citrusrlia@foxmail.com
 * @FilePath: \app\public\javascripts\sqls.js
 * @Date: 2021-05-24 15:01:08
 * @Description: 对数据库的操作
 */
const mysql = require("mysql");
const connection = mysql.createConnection({
  host: "localhost",
  user: "*******",
  password: "***********",
  database: "*************",
  port: "6326",
});

function addItem(params, callback) {
  let sql = `INSERT INTO geometry(osm_id,type,coordinates,code,fclass,name,id) VALUES(?,?,?,?,?,?,?)`;
  let AddParam = [
    params.osm_id,
    params.type,
    params.coordinates,
    params.code,
    params.fclass,
    params.name,
    params.id,
  ];
  connection.query(sql, AddParam, function (err, result) {
    if (err) {
      console.log("Add Geometry ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function deleteByName(name, callback) {
  let sql = `DELETE FROM geometry where name=?`;
  connection.query(sql, [name], function (err, result) {
    if (err) {
      console.log("Delete Geometry ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function editById(params, id, callback) {
  let sql = `UPDATE geometry SET osm_id=?,type=?,coordinates=?,code=?,fclass=?,name=?,id=? where osm_id=? or id=?`;
  let UpdateParam = [
    params.osm_id,
    params.type,
    params.coordinates,
    params.code,
    params.fclass,
    params.name,
    params.id,
  ];
  connection.query(sql, [...UpdateParam, id, id], function (err, result) {
    if (err) {
      console.log("UPDATE Geometry ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function pagination(thispage, pages, callback) {
  let sql = `SELECT * from geometry limit ${(thispage - 1) * pages},${pages}`;
  connection.query(sql, function (err, result) {
    if (err) {
      console.log("pagination ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function getByClass(fclass, callback) {
  let sql = `SELECT * FROM geometry WHERE fclass = ?`;
  connection.query(sql, [fclass], function (err, result) {
    if (err) {
      console.log("GET By class ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function getById(id, callback) {
  let sql = `SELECT * FROM geometry WHERE id = ? or osm_id=?`;
  connection.query(sql, [id, id], function (err, result) {
    if (err) {
      console.log("GET By ID ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function getByName(name, callback) {
  let sql = `SELECT * FROM geometry WHERE name = ?`;
  connection.query(sql, [name], function (err, result) {
    if (err) {
      console.log("GET By Name ERROR - ", err.message);
      return;
    }
    callback(result);
  });
}

function getAllFclass(callback) {
  let sql = `SELECT fclass FROM geometry`;
  connection.query(sql, function (err, result) {
    if (err) {
      console.log("GET ALL CLASS ERROR - ", err.message);
      return;
    }
    let arr = [];
    for (let i = 0, l = result.length; i < l; i++) {
      if (!arr.includes(result[i].fclass)) {
        arr.push(result[i].fclass);
      }
    }
    callback(arr);
  });
}

function getByPosition(initPoint, range, jsonUrl) {
  try {
    initPoint = eval(initPoint + "//@ sourceURL=initpoint"); //便于调试eval代码
    let result = fs.readFileSync(jsonUrl);
    let data = JSON.parse(result.toString());
    let Arr = [];
    for (let i = 0, l = data.features.length; i < l; i++) {
      let center = data.features[i].geometry.coordinates[0].reduce(
        (acc, cur, index, array) => {
          let lng = acc[0] + cur[0],
            lat = acc[1] + cur[1];
          if (index === array.length - 1) {
            return [lng / array.length, lat / array.length];
          }
          return [lng, lat];
        },
        [0, 0]
      );
      let distance = caculateLL(center, initPoint);
      if (distance < range) {
        Arr.push(data.features[i]);
      }
    }
    return Arr;
  } catch (err) {
    console.log(err);
  }
}
/**
 * @author: citrusrlia@foxmail.com
 * @description: 计算两点间距离
 * @param {p1,p2 : Arr}
 * @return {number}
 */
function caculateLL(p1, p2) {
  let lat1 = p1[0],
    lng1 = p1[1],
    lat2 = p2[0],
    lng2 = p2[1];
  var radLat1 = (lat1 * Math.PI) / 180.0;
  var radLat2 = (lat2 * Math.PI) / 180.0;
  var a = radLat1 - radLat2;
  var b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
  var s =
    2 *
    Math.asin(
      Math.sqrt(
        Math.pow(Math.sin(a / 2), 2) +
          Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)
      )
    );
  s = s * 6378.137;
  s = Math.round(s * 10000) / 10;
  return s;
}

function getAll(callback) {
  // connection.connect();
  let sql = "SELECT * FROM geometry";
  connection.query(sql, function (err, result) {
    if (err) {
      console.log("GETALL ERROR - ", err.message);
      return;
    }
    callback(result);
  });
  // connection.end();
}

module.exports = {
  addItem,
  deleteByName,
  editById,
  pagination,
  getByClass,
  getById,
  getByName,
  getAllFclass,
  getByPosition,
  getAll,
};

接着修改路由index.js,在请求对应地址时返回对应sql结果。node-mysql查询结果无法通过return返回,需要传入回调函数在回调中做res.send(),返回结果。views中页面使用pug编写,可以通过修改app.set("view engine","html")改成html语言或其他语言。使用require引入sqls.js时,项目未编译,如下设置不会使index.js中 ./ 路径映射到根目录下。

app.use(express.static(path.join(__dirname, "public")));
var express = require("express");
var router = express.Router();
var sqls = require("../public/javascripts/sqls");
var url = require("url")

/* 展示views中地址 */
router.get("/", function (req, res, next) {
  res.render("index", { title: "Hello,简书的朋友!" });
});

router.get("/getByClass", function (req, res) {
  /**
   * @description: 根据类别查询对应条目
   * @param {类别:fclass}
   * @return {Array}
   */
  let params = url.parse(req.url, true).query;
  sqls.getByClass(params.fclass, (searchResult) => {
    res.send(searchResult);
  });
});

router.get("/getById", function (req, res) {
  /**
   * @author: citrusrlia@foxmail.com
   * @description: 根据osm_id查找对应条目
   * @param {String:osm_id}
   * @return {Object}
   */
  let params = url.parse(req.url, true).query;
  sqls.getById(params.id, (searchResult) => {
    res.send(searchResult);
  });
});

router.get("/getByName", function (req, res) {
  /**
   * @author: citrusrlia@foxmail.com
   * @description: 根据名称查找对应条目
   * @param {String:name}
   * @return {Arr}
   */
  let params = url.parse(req.url, true).query;
  sqls.getByName(params.name, (result) => {
    res.send(result);
  });
});

router.get("/pagination", function (req, res) {
  /**
   * @description: 分页查询对应条目
   * @param {查询页标page,每页条目数perpage}
   * @return {Array}
   */
  let params = url.parse(req.url, true).query;
  sqls.pagination(params.page, params.perpage, (searchResult) => {
    res.send(searchResult);
  });
});

router.post("/addItem", function (req, res) {
  /**
   * @description: 添加条目
   * @param {addData:Object}
   * @return {nothing}
   */
  let params = url.parse(req.url, true).query;
  sqls.addItem(params, (searchResult) => {
    if (searchResult) res.send("添加成功");
  });
});

router.post("/delectByName", function (req, res) {
  /**
   * @description: 删除条目
   * @param {条目名称:name}
   * @return {nothing}
   */
  let params = url.parse(req.url, true).query;
  sqls.delectByName(params.name, (searchResult) => {
    if (searchResult) res.send("删除成功");
  });
});

router.post("/editById", function (req, res) {
  /**
   * @description: 修改条目
   * @param {params:Object,条目名称:searchId}
   * @return {Array}
   */
  let params = url.parse(req.url, true).query;
  sqls.editById(params, params.searchId, (searchResult) => {
    if (searchResult) res.send("修改成功");
  });
});

router.get("/getAllFclass", function (req, res) {
  /**
   * @author: citrusrlia@foxmail.com
   * @description:获取所有fclass
   * @param {nothing}
   * @return {Arr}
   */
  let params = url.parse(req.url, true).query;
  sqls.getAllFclass((searchResult) => {
    res.send(searchResult);
  });
});

router.get("/getByPosition", function (req, res) {
  /**
   * @author: citrusrlia@foxmail.com
   * @description:获取点附近features
   * @param {initPoint:[lng,lat] ,range:number}
   * @return {Arr}
   */
  let params = url.parse(req.url, true).query;
  sqls.getByPosition(params.initPoint, params.range, (searchResult) => {
    res.send(searchResult);
  });
});

router.get("/getAll", function (req, res) {
  /**
   * @author: citrusrlia@foxmail.com
   * @description: 获取所有features
   * @param {}
   * @return {Arr}
   */
  let params = url.parse(req.url, true).query;
  sqls.getAll((searchResult) => {
    res.send(searchResult);
  });
});
module.exports = router;

调用

image.png

访问对应端口,成功拿到数据库中数据。

总结

由于本人系gis前端工程师,第一次自己做后端服务,文中不足之处希望在看本文的朋友多多留言指正,万分感谢!

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

推荐阅读更多精彩内容