angular实现nodejs增删改查

说明:

我计划用nodejs来实现操作mysql中的表,增删改查的功能,

包括:

1.连接mysql数据库,

2.创建数据表,

3.写增删改查的方法,

4.postman里面去请求访问数据,

5.在angular里面,用表格展示所有数据,添加数据,删除数据等功能

效果图:

step0: 打开终端,进入项目目录untitled4,使用npm导入模块

bash 复制代码
npm install express body-parser --save
npm install mysql2 dotenv --save     
 npm install cors --save  
 npm install dotenv --save        
 npm install mysql --save  

step1:在package.json里面,验证刚刚导入的模块C:\Users\Administrator\WebstormProjects\untitled4\package.json

bash 复制代码
  "body-parser": "^1.20.3",
    "cors": "^2.8.5",
    "dotenv": "^16.4.7",
    "express": "^4.21.2",
    "mysql": "^2.18.1",
    "mysql2": "^3.12.0",

step2:配置数据库参数,用户名,密码,C:\Users\Administrator\WebstormProjects\untitled4.env

bash 复制代码
# .env 文件内容(放在项目根目录)
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=123456
DB_NAME=db_spring

step3:连接数据库 C:\Users\Administrator\WebstormProjects\untitled4\db.js

javascript 复制代码
// db.js
const mysql = require('mysql2');
require('dotenv').config();

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  port: process.env.DB_PORT,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

module.exports = pool.promise(); // 返回 Promise 风格的池对象

step4:写一个测试类,看看数据库是否连接成功C:\Users\Administrator\WebstormProjects\untitled4\test-connection.js

javascript 复制代码
// test-connection.js
const db = require('./db');

async function testConnection() {
  try {
    // 执行简单查询
    const [rows] = await db.query('SELECT 1 + 1 AS solution');
    console.log('✅ 连接成功!结果:', rows[0][0]);
  } catch (err) {
    console.error('❌ 连接失败:', err);
  } finally {
    // 关闭连接池
    await db.end();
  }
}

testConnection();

step5:在终端运行刚刚的 test-connection.js

bash 复制代码
PS C:\Users\Administrator\WebstormProjects\untitled4> node test-connection.js
✅ 连接成功!结果: undefined

step6:连接上数据库以后,开始创建数据库表,C:\Users\Administrator\WebstormProjects\untitled4\crud.js

javascript 复制代码
const db = require('./db');

// 创建表(仅需运行一次)
async function initializeTable() {
  const sql = `
    CREATE TABLE IF NOT EXISTS users (
      id INT AUTO_INCREMENT PRIMARY KEY,
      name VARCHAR(100) NOT NULL,
      email VARCHAR(100) UNIQUE NOT NULL,
      age INT DEFAULT 0
    );
  `;
  await db.query(sql);
  console.log('✅ 用户表已创建!');
}

// 查询所有用户
async function getAllUsers() {
  const [rows] = await db.query('SELECT * FROM users');
  return rows;
}

// 查询单个用户(根据ID)
async function getUserById(id) {
  const [rows] = await db.query('SELECT * FROM users WHERE id = ?', [id]);
  return rows[0]; // 返回单个用户对象或 null
}

// 插入用户
async function createUser(user) {
  const [result] = await db.query(
    'INSERT INTO users (name, email, age) VALUES (?, ?, ?)',
    [user.name, user.email, user.age]
  );
  return { id: result.insertId, ...user };
}

// 更新用户
async function updateUser(id, user) {
  const [result] = await db.query(
    'UPDATE users SET name = ?, email = ?, age = ? WHERE id = ?',
    [user.name, user.email, user.age, id]
  );
  return { id, ...user };
}

// 删除用户
async function deleteUser(id) {
  const [result] = await db.query('DELETE FROM users WHERE id = ?', [id]);
  return { affectedRows: result.affectedRows };
}

module.exports = {
  initializeTable,
  getAllUsers,
  getUserById,
  createUser,
  updateUser,
  deleteUser,
};

step7:数据库表,创建完成后,开始写后端请求类,处理get和post请求C:\Users\Administrator\WebstormProjects\untitled4\spring.js

javascript 复制代码
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const crud = require('./crud');

const app = express();
app.use(bodyParser.json());
// 开启跨域支持(允许所有来源访问)
app.use(cors());

// 初始化表(运行前执行一次)
(async () => {
  await crud.initializeTable();
})();

// API 路由
app.get('/users', async (req, res) => {
  const users = await crud.getAllUsers();
  res.json(users);
});

// 新增:根据ID查询用户
app.get('/users/:id', async (req, res) => {
  const id = parseInt(req.params.id);
  try {
    const user = await crud.getUserById(id);
    if (user) {
      res.status(200).json(user);
    } else {
      res.status(404).json({ message: '用户不存在' });
    }
  } catch (err) {
    console.error('查询用户错误:', err);
    res.status(500).json({ error: '服务器内部错误' });
  }
});

app.post('/users', async (req, res) => {
  const newUser = await crud.createUser(req.body);
  res.status(201).json(newUser);
});

app.put('/users/:id', async (req, res) => {
  const id = parseInt(req.params.id);
  const updatedUser = await crud.updateUser(id, req.body);
  res.json(updatedUser);
});

app.delete('/users/:id', async (req, res) => {
  const id = parseInt(req.params.id);
  const result = await crud.deleteUser(id);
  res.json({ message: `Deleted ${result.affectedRows} user(s)` });
});

// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`🚀 Server is running on port ${PORT}`);
});

step8:到这里,咱们的nodejs,后端部分和mysql部分就写完了,接下来,用postman测试,访问请求接口,看看是否能成功调用mysql表中的数据

查询具体数据

bash 复制代码
get请求 http://192.168.0.113:3000/users/3
{
    "id": 3,
    "name": "张仲景",
    "email": "[email protected]",
    "age": 108
}

查询所有

bash 复制代码
get请求 http://192.168.0.113:3000/users
[
    {
        "id": 1,
        "name": "王婆婆",
        "email": "[email protected]",
        "age": 30
    },
    {
        "id": 3,
        "name": "张仲景",
        "email": "[email protected]",
        "age": 108
    },
    {
        "id": 13,
        "name": "廖化",
        "email": "[email protected]",
        "age": 28
    },
    {
        "id": 14,
        "name": "黄波",
        "email": "[email protected]",
        "age": 23
    },
    {
        "id": 15,
        "name": "周瑜",
        "email": "[email protected]",
        "age": 52
    },
    {
        "id": 16,
        "name": "刘能",
        "email": "[email protected]",
        "age": 65
    }
]

新增数据

bash 复制代码
post请求,http://192.168.0.113:3000/users
{
    "id": 17,
    "name": "仲康",
    "email": "[email protected]",
    "age": 16
}

删除数据

bash 复制代码
delete请求,http://192.168.0.113:3000/users/17
{
    "message": "Deleted 1 user(s)"
}

修改数据

bash 复制代码
http://192.168.0.113:3000/users/16
{
    "id": 16,
    "name": "康男",
    "email": "[email protected]",
    "age": 19
}

step9:postman测试通过,表示后端完全写完了,接下来写angular前端代码

step10:在app.config里面配置provideHttpClient

C:\Users\Administrator\WebstormProjects\untitled4\src\app\app.config.ts

javascript 复制代码
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
import { provideIndexedDb } from 'ngx-indexed-db';
import { DB_CONFIG } from './db.config';

import { provideAnimations } from '@angular/platform-browser/animations';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';



export const appConfig: ApplicationConfig = {
  providers: [provideIndexedDb(DB_CONFIG),provideHttpClient(),provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),provideAnimations(), provideAnimationsAsync()]
};

step11:写一个http的封装类,增删改查的方法,

C:\Users\Administrator\WebstormProjects\untitled4\src\app\springboot\user.service.ts

javascript 复制代码
// src/app/user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private apiUrl = 'http://localhost:3000/users';

  constructor(private http: HttpClient) {}

  // 查询所有用户
  getAllUsers(): Observable<any> {
    return this.http.get(this.apiUrl);
  }

  // 创建用户
  createUser(user: any): Observable<any> {
    return this.http.post(this.apiUrl, user);
  }

  // 获取单个用户(新增)
  getUserById(id: number): Observable<any> {
    return this.http.get(`${this.apiUrl}/${id}`);
  }

  // 更新用户
  updateUser(id: number, user: any): Observable<any> {
    return this.http.put(`${this.apiUrl}/${id}`, user);
  }

  // 删除用户
  deleteUser(id: number): Observable<any> {
    return this.http.delete(`${this.apiUrl}/${id}`);
  }
}

step12:C:\Users\Administrator\WebstormProjects\untitled4\src\app\springboot\springboot.component.ts

javascript 复制代码
// src/app/springboot.component.ts
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgForm } from '@angular/forms';
import {NgForOf} from '@angular/common';
import { UserService } from './user.service';

@Component({
  selector: 'app-springboot',
  imports: [
    FormsModule,
    NgForOf
  ],
  templateUrl: './springboot.component.html',
  styleUrls: ['./springboot.component.css']
})
export class SpringbootComponent implements OnInit {
  users: any[] = [];
  isLoading = false;
  error: string = '';
  selectedUser: any = {};
  isEditMode: boolean = false;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.loadUsers();
  }

  loadUsers(): void {
    this.isLoading = true;
    this.userService.getAllUsers().subscribe(
      (data) => {
        this.users = data;
        this.isLoading = false;
      },
      (err) => {
        this.error = '加载用户失败';
        this.isLoading = false;
      }
    );
  }

  // 添加/修改用户
  submitForm(userForm: NgForm): void {
    if (userForm.invalid) return;

    if (this.isEditMode) {
      this.updateUser(this.selectedUser.id, this.selectedUser);
    } else {
      this.createUser(this.selectedUser);
    }

    // 重置表单和状态
    userForm.reset();
    this.selectedUser = {};
    this.isEditMode = false;
  }

  // 创建新用户
  createUser(user: any): void {
    this.userService.createUser(user).subscribe(
      (newUser) => {
        this.users.push(newUser);
      },
      (err) => {
        this.error = '创建用户失败';
      }
    );
  }

  // 编辑用户
  editUser(id: number): void {
    this.userService.getUserById(id).subscribe(
      (user) => {
        this.selectedUser = user;
        this.isEditMode = true;
      },
      (err) => {
        this.error = '加载用户失败';
      }
    );
  }

  // 更新用户
  updateUser(id: number, user: any): void {
    this.userService.updateUser(id, user).subscribe(() => {
      // 替换原用户数据
      this.users = this.users.map(u =>
        u.id === id ? { ...u, name: user.name, email: user.email, age: user.age } : u
      );
    });
  }

  // 删除用户
  deleteUser(id: number): void {
    this.userService.deleteUser(id).subscribe(() => {
      this.users = this.users.filter(u => u.id !== id);
    });
  }

  // 重置表单
  resetForm(): void {
    this.selectedUser = {};
    this.isEditMode = false;
  }
}

step13: C:\Users\Administrator\WebstormProjects\untitled4\src\app\springboot\springboot.component.html

xml 复制代码
<div class="container">
  <h2>用户管理</h2>

  <!-- 添加/编辑用户表单 -->
  <div class="card mb-3">
    <div class="card-header">
      <h3 class="card-title">添加/编辑用户</h3>
    </div>
    <div class="card-body">
      <form #userForm="ngForm" (ngSubmit)="submitForm(userForm)">
        <div class="form-group">
          <input type="text" class="form-control" name="name" [(ngModel)]="selectedUser.name" required>
        </div>
        <div class="form-group">
          <input type="email" class="form-control" name="email" [(ngModel)]="selectedUser.email" required>
        </div>
        <div class="form-group">
          <input type="number" class="form-control" name="age" [(ngModel)]="selectedUser.age" min="0">
        </div>
        <button type="submit" class="btn btn-modern">
          {{ isEditMode ? '保存' : '添加' }}
        </button>
        <button type="reset" class="btn btn-secondary-modern" (click)="resetForm()">
          清空
        </button>
      </form>
    </div>
  </div>

  <!-- 用户列表 -->
  <table class="table table-striped">
    <thead>
    <tr>
      <th>ID</th>
      <th>姓名</th>
      <th>邮箱</th>
      <th>年龄</th>
      <th>操作</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let user of users">
      <td>{{ user.id }}</td>
      <td>{{ user.name }}</td>
      <td>{{ user.email }}</td>
      <td>{{ user.age }}</td>
      <td>
        <button (click)="editUser(user.id)" class="btn btn-warning btn-sm">
          修改
        </button>
        <button (click)="deleteUser(user.id)" class="btn btn-danger btn-sm">
          删除
        </button>
      </td>
    </tr>
    </tbody>
  </table>
</div>

step14: C:\Users\Administrator\WebstormProjects\untitled4\src\app\springboot\springboot.component.css

css 复制代码
/* 容器全局样式 */
.container {
  max-width: 1200px;
  margin: 2rem auto;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 12px;  /* 整体圆角 */
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);  /* 柔和阴影 */
}

/* 卡片组件增强 */
.card {
  border: none;
  border-radius: 10px;  /* 卡片圆角 */
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);  /* 层级阴影 */
  background: white;
}
.card-header {
  background: linear-gradient(135deg, #6c5ce7, #4b4ced);  /* 渐变背景 */
  color: white;
  border-radius: 10px 10px 0 0;  /* 顶部圆角 */
}

/* 按钮现代化改造 */
.btn {
  border: none;
  border-radius: 8px;  /* 统一圆角 */
  padding: 10px 25px;
  transition: all 0.3s ease;  /* 平滑动效 */
  font-weight: 500;
}
.btn-primary {
  background: linear-gradient(45deg, #4b4ced, #6c5ce7);  /* 渐变背景 */
  color: white;
  box-shadow: 0 4px 6px rgba(75, 76, 237, 0.2);  /* 投影增强 */
}
.btn-primary:hover {
  transform: translateY(-2px);  /* 悬停微抬升 */
  box-shadow: 0 6px 12px rgba(75, 76, 237, 0.3);
}
.btn-secondary {
  background: #e9ecef;
  color: #495057;
}
.btn-sm {
  padding: 6px 15px;
  font-size: 0.9em;
}

/* 表格现代化设计 */
.table {
  border-collapse: separate;
  border-spacing: 0;
  background: white;
  border-radius: 10px;  /* 表格整体圆角 */
  overflow: hidden;  /* 隐藏溢出圆角 */
}
.table thead th {
  background: #f8f9fa;
  color: #495057;
  font-weight: 600;
  border-bottom: 2px solid #e9ecef;  /* 表头分割线 */
}
.table tbody tr:hover {
  background: #f8f9fa;  /* 行悬停高亮 */
}
.table-striped tbody tr:nth-of-type(odd) {
  background-color: rgba(241, 243, 245, 0.5);  /* 柔和条纹 */
}
.table td, .table th {
  padding: 15px;
  border-top: 1px solid #e9ecef;  /* 单元格分割线 */
}

/* 输入框微调 */
.form-control {
  border-radius: 6px;  /* 输入框圆角 */
  border: 1px solid #dee2e6;
  padding: 10px 15px;
}

end

相关推荐
wuhen_n10 分钟前
CSS元素动画篇:基于当前位置的变换动画(合集篇)
前端·css·html·css3·html5
A_aspectJ13 分钟前
【Bootstrap V4系列】学习入门教程之 组件-按钮(Buttons)
javascript·学习·bootstrap
caig00019 分钟前
JavaScript性能优化实战
开发语言·javascript·性能优化
专注VB编程开发20年1 小时前
JS检测htm哪个子节点的内容被修改addEventListener(‘input‘, (event)
前端·html5·js
凉生阿新1 小时前
【React】Hooks useReducer 详解,让状态管理更可预测、更高效
前端·react.js·前端框架
a181001_2 小时前
自制简易html指南针
前端·html·html5
BillKu3 小时前
Vue3取消网络请求的方法(AbortController)
前端·javascript·vue.js
海天胜景3 小时前
c# list<T> 合并
前端·c#
陈奕昆4 小时前
【LLaMA-Factory实战】Web UI快速上手:可视化大模型微调全流程
前端·ui·llama·大模型微调实战
Jedi Hongbin5 小时前
echarts自定义图表--柱状图-横向
前端·javascript·echarts