基于后台接口的图书管理案例-(二)-全文详解版

111 篇文章 2 订阅
54 篇文章 1 订阅

基于后台接口的图书管理案例-(二)-全文详解版

在前端mydemo文件夹中

在这里插入图片描述

第一步:在APP.js同层级的component下新建03-grid.js

第二步:在App.js中进行导入

App.js
import React from 'react';
import './App.css';
import TestBox from './component/03-grid.js'

function App () {
  return (
    <div>
      <TestBox/>
    </div>
  )
}

export default App;
03-grid.js文件如下
/*
  图书管理案例
*/
import React from 'react'
import './03-grid.css'
import axios from 'axios'
// 配置axios的基准请求路径
axios.defaults.baseURL = 'http://localhost:3001/'
// axios的响应拦截器
axios.interceptors.response.use((res) => {
  // res是axios包装之后的数据
  console.log(res)
  return res.data
})

class BookManager extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      list: [],
      bookId: '',
      bookName: '',
      // 标志位:控制当前是在添加图书还是在编辑图书(true表示添加;false表示编辑)
      flag: true
    }
  }

  loadData = async () => {
    // axios.get('books')
    //   .then(res => {
    //     // 更新状态数据
    //     this.setState({
    //       list: res.data
    //     })
    //   })
    let res = await axios.get('books')
    this.setState({
      list: res
    })
  }

  componentDidMount () {
    // 初始化数据(调用后台接口获取列表数据)
    this.loadData()
    // setTimeout(() => {
    //   // 假设list是后台返回的异步数据
    //   let list = [{
    //     id: 1,
    //     bname: '智能时代'
    //   }, {
    //     id: 2,
    //     bname: '肖申克的救赎'
    //   }, {
    //     id: 3,
    //     bname: '阿甘正传'
    //   }, {
    //     id: 4,
    //     bname: '浪潮之巅'
    //   }]
    //   this.setState({
    //     list: list
    //   })
    // }, 1000)
  }

  handleId = (e) => {
    this.setState({
      bookId: e.target.value
    })
  }

  handleBname = (e) => {
    this.setState({
      bookName: e.target.value
    })
  }

  handleItem = (e) => {
    this.setState({
      // ES6新特性:对象的属性名称可以是动态的
      [e.target.id]: e.target.value
    })
  }

  addBook = async () => {
    /*
      添加图书:
      1、获取表单数据
      2、调用后台接口进行添加
      3、重新刷新最新类别
      4、清空表单
    */
    // 表单验证:1、非空验证;2、重复性验证
    if (!this.state.bookName) {
      // 提示输入,终止后续代码执行-非空验证
      alert('请输入图书名称')
      return
    }
    // 非空验证 数组方法some(判断数组中是否有符合条件的数据,主要有一个符合就返回true)
    let existFlag = await axios.get('books/book/' + this.state.bookName)
    if (existFlag.status === 1) {
      // 名称重复,终止后续代码,并给一个提示
      alert('图书名称重复了')
      return 
    }
    let res = await axios.post('books', {
      name: this.state.bookName
    })
    if (res.status === 200) {
      // 添加成功,刷新列表
      this.loadData()
      this.setState({
        // 清空图书表单
        bookName: ''
      })
    }
  }

  editBook = async () => {
    /*
      编辑图书
      1、获取表单最新数据
      2、调用接口提交数据
      3、刷新列表并清空表单
    */
    let res = await axios.put('books/' + this.state.bookId, {
      name: this.state.bookName
    })
    if (res.status === 200) {
      // 编辑成功,刷新列表,清空表单
      this.loadData()
      this.setState({
        bookId: '',
        bookName: '',
        flag: true
      })
    }
  }

  handleSubmit = () => {
    // console.log(this.state.bookId)
    // console.log(this.state.bookName)
    if (this.state.flag) {
      // 添加图书
      this.addBook()
    } else {
      // 编辑图书
      this.editBook()
    }
  }

  toEdit = async (id) => {
    /*
      编辑的第一步
      1、获取要编辑的图书id
      2、根据id调用接口获取编辑的图书信息
      3、填充表单
    */
    let res = await axios.get('books/' + id)
    this.setState({
      bookId: res.id,
      bookName: res.name,
      flag: false
    })
  }

  handleDelete = async (id) => {
    /*
      删除图书
      1、获取要删除的图书ID
      2、调用接口删除图书
      3、刷新列表
    */
    let res = await axios.delete('books/' + id)
    if (res.status === 200) {
      // 删除成功,刷新列表
      this.loadData()
    }
  }

  render () {
    // 动态生成表格的列表
    let listTag = this.state.list.map(item => {
      return (
        <tr key={item.id}>
          <td>{item.id}</td>
          <td>{item.name}</td>
          <td>
            <a href="#" onClick={this.toEdit.bind(this, item.id)}>编辑</a>
            <span>|</span>
            <a href="#" onClick={this.handleDelete.bind(this, item.id)}>删除</a>
          </td>
        </tr>
      )
    })
    return (
      <div className='book'>
        <div className="title">图书管理系统</div>
        <div className="form">
          {/*<label htmlFor="bookId">图书编号</label>
          <input readOnly={!this.state.flag} value={this.state.bookId} onChange={this.handleItem} type="text" id='bookId'/>*/}
          <label htmlFor="bookName">图书名称</label>
          <input value={this.state.bookName} onChange={this.handleItem} type="text" id='bookName'/>
          <button onClick={this.handleSubmit}>提交</button>
        </div>
        <div className="grid">
          <table>
            <thead>
              <tr>
                <th>图书编号</th>
                <th>图书名称</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              {this.state.list.length===0 && <tr>
                <td colSpan='3'>正在加载...</td>
              </tr>}
              {listTag}
            </tbody>
          </table>
        </div>
      </div>
    )
  }
}

export default BookManager
03-grid.css文件如下
.book .title {
  text-align: center;
  background-color: lightblue;
  color: #fff;
  font-size: 30px;
}
.book .form {
  padding: 10px 0;
}
.book .grid table {
  border-collapse: collapse;
  width: 100%;
  text-align: center;
}
.book .grid table th, td {
  border: 1px solid blue;
}

node index.js启动服务器后;npm run start启动项目,(静态或接口数据)页面如下:

在这里插入图片描述

在服务器mybook文件夹中

node index.js启动服务器

在这里插入图片描述

第一步:在mybook文件中,cmd启动命令行窗口,npm i axios安装包,并在03-grid.js中进行引入

import axios from ‘axios’

必要基础配置简述

// 配置axios的基准请求路径
axios.defaults.baseURL = 'http://localhost:3001/'
// axios的响应拦截器
axios.interceptors.response.use((res) => {
  // res是axios包装之后的数据
  console.log(res)
  return res.data
})

在data.json中定义接口数据

[
    {
        "name": "三国演义",
        "date": 2525609975000,
        "id": 5
    },
    {
        "name": "水浒传",
        "date": 2525609975000,
        "id": 6
    },
    {
        "name": "浪潮之巅",
        "date": 2525609975000,
        "id": "11"
    },
    {
        "name": "JavaScript",
        "date": 2525609975000,
        "id": 12
    },
    {
        "name": "编辑成功",
        "date": 2525609975000,
        "id": "13"
    },
    {
        "name": "234",
        "date": 2525609975000,
        "id": 14
    }
]
index.js
const express = require('express');
const path = require('path');
const router = require('./router.js');
const bodyParser = require('body-parser');
const app = express();

// 处理请求参数
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// 设置允许跨域访问该服务, cors
app.all('*', function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, mytoken');
  next();
});

// 启动静态资源服务
app.use(express.static('public'));

// app.post('hello', (req,res) => {
//   let p = req.body;
//   res.end('hello');
// })

// 配置路由
app.use(router);
// 监听端口
app.listen(3001, ()=>{
    console.log('running...');
});
router.js
/*
  路由模块
*/
const express = require('express');
const router = express.Router();
const service = require('./service.js');

// 查询图书列表
router.get('/books',service.getAllBooks);
// 添加图书(提交表单)
router.post('/books',service.addBook);
// 跳转到编辑图书信息页面
router.get('/books/:id',service.toEditBook);
// router.get('/toEditBook',service.toEditBook);
// 编辑图书提交表单
router.put('/books/:id',service.editBook);
// 删除图书信息
router.delete('/books/:id',service.deleteBook);
// 验证图书名称是否存在
router.get('/books/book/:name',service.checkName);

module.exports = router;
service.js
const data = require('./data.json');
const path = require('path');
const fs = require('fs');

// 自动生成图书编号(自增)
let maxBookCode = ()=>{
    let arr = [];
    data.forEach((item)=>{
        arr.push(item.id);
    });
    if(arr.length === 0) {
        return 0;
    } else {
        return Math.max.apply(null,arr);
    }
}
// 把内存数据写入文件
let writeDataToFile = (res) => {
    fs.writeFile(path.join(__dirname,'data.json'),JSON.stringify(data,null,4),(err)=>{
        if(err){
            res.json({
                status: 500
            });
        }
        res.json({
            status: 200
        });
    });
}
// 验证图书名称是否存在
exports.checkName = (req,res) => {
    let name = req.params.name;
    console.log(req.params)
    let flag = false;
    data.some(item=>{
        if(name == item.name) {
            flag = true;
            return true;
        }
    })
    if(flag) {
        res.json({
            status: 1
        })
    }else{
        res.json({
            status: 2
        })
    }
}

// 获取图书列表数据
exports.getAllBooks = (req,res) => {
    res.json(data);
}

// 添加图书保存数据
exports.addBook = (req,res) => {
    // 获取表单数据
    let info = req.body;
    let book = {};
    for(let key in info){
        book[key] = info[key];
    }
    book.date = 2525609975000;
    book.id = maxBookCode() + 1;
    data.push(book);
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
// 跳转编辑图书页面
exports.toEditBook = (req,res) => {
    let id = req.params.id;
    let book = {};
    data.some((item)=>{
        if(id == item.id){
            book = item;
            return true;
        }
    });
    res.json(book);
}
// 编辑图书更新数据
exports.editBook = (req,res) => {
    let info = req.body;
    info.id = req.params.id;
    data.some((item)=>{
        if(info.id == item.id){
            for(let key in info){
                item[key] = info[key];
            }
            return true;
        }
    });
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
// 删除图书信息
exports.deleteBook = (req,res) => {
    let id = req.params.id;
    data.some((item,index)=>{
        if(id == item.id){
            // 删除数组的一项数据
            data.splice(index,1);
            return true;
        }
    });
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
css/index.css
.grid {
  margin: auto;
  width: 530px;
  text-align: center;
}
.grid table {
  border-top: 1px solid #C2D89A;
  width: 100%;
  border-collapse: collapse;
}
.grid th,td {
  padding: 10;
  border: 1px dashed #F3DCAB;
  height: 35px;
  line-height: 35px;
}
.grid th {
  background-color: #F3DCAB;
}
.grid .book {
  padding-bottom: 10px;
  padding-top: 5px;
  background-color: #F3DCAB;
}
.grid .total {
  height: 30px;
  line-height: 30px;
  background-color: #F3DCAB;
  border-top: 1px solid #C2D89A;
}

s/index.css

.grid {
  margin: auto;
  width: 530px;
  text-align: center;
}
.grid table {
  border-top: 1px solid #C2D89A;
  width: 100%;
  border-collapse: collapse;
}
.grid th,td {
  padding: 10;
  border: 1px dashed #F3DCAB;
  height: 35px;
  line-height: 35px;
}
.grid th {
  background-color: #F3DCAB;
}
.grid .book {
  padding-bottom: 10px;
  padding-top: 5px;
  background-color: #F3DCAB;
}
.grid .total {
  height: 30px;
  line-height: 30px;
  background-color: #F3DCAB;
  border-top: 1px solid #C2D89A;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值