当前位置: 首页 > article >正文

angular实现nodejs增删改查

说明:
我计划用nodejs来实现操作mysql中的表,增删改查的功能,
包括:
1.连接mysql数据库,
2.创建数据表,
3.写增删改查的方法,
4.postman里面去请求访问数据,
5.在angular里面,用表格展示所有数据,添加数据,删除数据等功能

效果图:
在这里插入图片描述

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

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

  "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

# .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

// 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

// 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

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

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

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

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表中的数据

查询具体数据

get请求 http://192.168.0.113:3000/users/3
{
    "id": 3,
    "name": "张仲景",
    "email": "zhangsan@example.com",
    "age": 108
}

查询所有

get请求 http://192.168.0.113:3000/users
[
    {
        "id": 1,
        "name": "王婆婆",
        "email": "wangwu@example.com",
        "age": 30
    },
    {
        "id": 3,
        "name": "张仲景",
        "email": "zhangsan@example.com",
        "age": 108
    },
    {
        "id": 13,
        "name": "廖化",
        "email": "liaohua@example.com",
        "age": 28
    },
    {
        "id": 14,
        "name": "黄波",
        "email": "bozhong@example.com",
        "age": 23
    },
    {
        "id": 15,
        "name": "周瑜",
        "email": "zhaouyun@example.com",
        "age": 52
    },
    {
        "id": 16,
        "name": "刘能",
        "email": "znengoliu@example.com",
        "age": 65
    }
]

新增数据

post请求,http://192.168.0.113:3000/users
{
    "id": 17,
    "name": "仲康",
    "email": "zhankangn@example.com",
    "age": 16
}

删除数据

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

修改数据

http://192.168.0.113:3000/users/16
{
    "id": 16,
    "name": "康男",
    "email": "zjmnangn@example.com",
    "age": 19
}

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

step10:在app.config里面配置provideHttpClient
C:\Users\Administrator\WebstormProjects\untitled4\src\app\app.config.ts

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

// 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

// 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

<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

/* 容器全局样式 */
.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


http://www.kler.cn/a/571693.html

相关文章:

  • 前端2025
  • 开源之夏经验分享|Koupleless 社区黄兴抗:在开源中培养工程思维
  • Spring Boot Gradle 项目中使用 @Slf4j 注解
  • 基于微信小程序的竞赛报名系统设计与实现
  • 能做期权交易的标的物有哪些?
  • IO进程线程2
  • vscode设置不自动打开项目【超详细图解】
  • 深度学习R8周:RNN实现阿尔兹海默症(pytorch)
  • C++学习(七)(标准库+STL(iotstream公司,日期/时间,器皿,算法,迭代器,多线程))
  • 深入理解网络通信中的关键概念:HTTP、TCP与Socket的关系及TCP的可靠性保障
  • Google C++ 开源风格指南
  • 用AI学安卓游戏开发1——控制小球上下左右移动2
  • JavaEE基础之-sessioncookie
  • centos和ubunt下安装redis
  • 论文阅读和代码实现EfficientDet(BiFPN)
  • 基于vue框架的游戏商城系统cq070(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 大模型的实践应用36-基于AI Agent和通义千问大模型,支持多轮问答的智能问数和数据分析的应用场景
  • 如何保证域名网络安全性
  • 甘特图开发代码(测试版)
  • PyCharm 环境配置精髓:打造高效 Python 开发的基石