返回

定制化技术雷达之雷达图定制

前端

雷达图定制

在上一篇文章中,我们介绍了如何通过下载在线雷达的 JSON 文件,并利用简单的 Node.js 代码将它们自动构建成一个简单的静态网站并部署到 GitHub Pages 上,以便于我们以更加便捷的方式来维护雷达图上的信息。

不过,这毕竟是通过一段脚本去维护JSON 文件,并不方便,而且由于每次都需要通过脚本才能构建一个静态网站并部署到 GitHub Pages 上,如果仅仅是对于雷达图上的技术点和内容进行微调,这个过程显得过于繁琐。

因此,这篇文章的主要目的是介绍如何创建一个支持增删改查雷达图上技术点的 web 服务,并通过这个 web 服务提供的 API 来更新维护技术雷达。如此,我们在未来进行技术雷达更新的时候,只需通过浏览器访问我们的 web 服务,修改相应的数据,剩下的交给 web 服务进行自动处理即可。

web 服务开发环境搭建

首先,我们依然通过 npm 脚手架工具创建项目:

$ npm create-react-app radar-service
$ cd radar-service

而后依然修改 package.json 中的 scripts 来指定一个启动脚本,package.json 文件如下:

{
  "name": "radar-service",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}

注意,我们这里引入了一个新的依赖 express,这个库在 Node.js 中用于构建 web 服务。这个依赖的安装通过以下命令进行:

$ npm install express --save

Node.js 环境搭建完毕,我们开始敲代码。我们主要需要完成两步:

  1. 构建一个 express 应用,它提供 CRUD 接口来管理雷达图上的技术点。
  2. 与前端 React 应用对接,让前端通过 axios 来调用 web 服务的接口。

后端应用开发

安装数据模型

为了方便对雷达图上的技术点进行管理,我们需要一个数据模型,这里我们选择使用 SQLite 作为数据库,这里无需多解释,详情可以自行查阅相关资料。

首先,我们需要安装一个 SQLite 相关的驱动包,由于我们使用的是 TypeScript,因此需要安装一个支持 TypeScript 的包,这里我们选择 sqlite3,通过以下命令进行安装:

$ npm install sqlite3

构建数据库

数据库构建可以通过一个简单的建表语句来实现:

CREATE TABLE radar_tech (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  quadrant TEXT NOT NULL,
  name TEXT NOT NULL,
  rank INTEGER NOT NULL,
  description TEXT NOT NULL,
  icon_url TEXT NOT NULL,
  color TEXT NOT NULL
);

可以通过 sqlite3 命令行工具来执行这个命令:

$ sqlite3 radar.db
sqlite> CREATE TABLE radar_tech (
   ...>   id INTEGER PRIMARY KEY AUTOINCREMENT,
   ...>   quadrant TEXT NOT NULL,
   ...>   name TEXT NOT NULL,
   ...>   rank INTEGER NOT NULL,
   ...>   description TEXT NOT NULL,
   ...>   icon_url TEXT NOT NULL,
   ...>   color TEXT NOT NULL
   ...> );

express 应用构建

express 应用的构建是一个标准的 Node.js 应用的构建过程,这里不再赘述,需要关注的是我们主要利用 express 的路由来构建与雷达图上技术点进行 CRUD 操作的接口。

查询接口

通过以下路由来实现查询雷达图上所有技术点的接口:

app.get('/api/radar_tech', (req, res) => {
  db.all('SELECT * FROM radar_tech', [], (err, rows) => {
    if (err) {
      res.status(500).json({ error: err.message });
      return;
    }
    res.json(rows);
  });
});

创建接口

通过以下路由来实现创建雷达图上某个技术点的接口:

app.post('/api/radar_tech', (req, res) => {
  const newTech = req.body;
  db.run(
    'INSERT INTO radar_tech (quadrant, name, rank, description, icon_url, color) VALUES (?, ?, ?, ?, ?, ?)',
    [newTech.quadrant, newTech.name, newTech.rank, newTech.description, newTech.icon_url, newTech.color],
    (err, result) => {
      if (err) {
        res.status(500).json({ error: err.message });
        return;
      }
      res.json({ id: result.lastID, ...newTech });
    }
  );
});

更新接口

通过以下路由来实现更新雷达图上某个技术点的接口:

app.put('/api/radar_tech/:id', (req, res) => {
  const updatedTech = req.body;
  db.run(
    'UPDATE radar_tech SET quadrant = ?, name = ?, rank = ?, description = ?, icon_url = ?, color = ? WHERE id = ?',
    [updatedTech.quadrant, updatedTech.name, updatedTech.rank, updatedTech.description, updatedTech.icon_url, updatedTech.color, updatedTech.id],
    (err, result) => {
      if (err) {
        res.status(500).json({ error: err.message });
        return;
      }
      res.json(updatedTech);
    }
  );
});

删除接口

通过以下路由来实现删除雷达图上某个技术点的接口:

app.delete('/api/radar_tech/:id', (req, res) => {
  const id = req.params.id;
  db.run('DELETE FROM radar_tech WHERE id = ?', [id], (err, result) => {
    if (err) {
      res.status(500).json({ error: err.message });
      return;
    }
    res.json({ id });
  });
});

web 服务部署

web 服务部署主要是通过 express 的监听端口来实现的,通过以下代码来监听端口并部署 web 服务:

const port = process.env.PORT || 3001;
app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

这个 web 服务的端口号为 3001。

前端应用对接

至此,web 服务已经构建完成,前端应用的实现相对简单,这里我们使用 axios 来调用我们构建的 web 服务,并对前端界面进行一些简单的改造:

  1. 在 src/App.js 中,修改代码以使用 axios 进行 API 调用:
const App = () => {
  const [radarTechs, setRadarTechs] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsLoading(true);
    axios.get('/api/radar_tech')
      .then(res => {
        setRadarTechs(res.data);
        setIsLoading(false);
      })
      .catch(err => {
        console.error(err);
        setIsLoading(false);
      });
  }, []);

  // 其他代码略

  return (
    // 其他代码略
  );
};
  1. 在 src/components/RadarTech.js 中,修改代码以使用 axios 进行 API 调用:
const RadarTech = ({ radarTech, onDelete }) => {
  const [isEditing, setIsEditing] = useState(false);
  const [editedRadarTech, setEditedRadarTech] = useState(radarTech);

  const handleDelete = () => {
    axios.delete(`/api/radar_tech/${radarTech.id}`)
      .then(res => {
        onDelete(radarTech.id);
      })
      .catch(err => {
        console.error(err);
      });
  };

  // 其他代码略

  return (
    // 其他代码略
  );
};
  1. 在 src/components/RadarTechForm.js 中,修改代码以使用 axios 进行 API 调用:
const RadarTechForm = ({ onSubmit, initialRadarTech }) => {
  const [radarTech, setRadarTech] = useState(initialRadarTech);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setRadarTech({