如何搭建Angular+NodeJS+MySQL?Laravel系统重构技术咨询
我刚帮几个朋友搞定过类似的Laravel到Angular+Node的迁移,你的困惑真的太常见了——毕竟网上大部分教程要么只讲Angular的单页路由,要么盯着MongoDB这类NoSQL,很少把Angular+Node+MySQL的完整流程串起来。我给你拆解成两个核心部分,一步步来:
这部分其实和你熟悉的Laravel路由思路一致,只是把路由规则从后端移到了前端:
- 先创建Angular项目并生成需要的页面组件:
ng new your-project ng generate component home ng generate component user-list ng generate component user-detail - 然后在
app-routing.module.ts里配置路由规则(类似Laravel的web.php):import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { UserListComponent } from './user-list/user-list.component'; import { UserDetailComponent } from './user-detail/user-detail.component'; const routes: Routes = [ { path: '', component: HomeComponent }, // 默认路由对应首页 { path: 'users', component: UserListComponent }, // 用户列表页 { path: 'users/:id', component: UserDetailComponent }, // 带ID参数的详情页 { path: '**', redirectTo: '' } // 404页面重定向到首页 ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } - 最后在
app.component.html里添加路由出口和导航链接(类似Laravel的route()辅助函数):<nav> <a routerLink="/" routerLinkActive="active">首页</a> <a routerLink="/users" routerLinkActive="active">用户列表</a> </nav> <router-outlet></router-outlet> <!-- 匹配的组件会在这里渲染 -->
routerLinkActive可以给当前激活的导航项加样式,和Laravel的路由激活逻辑完全一致。
这部分是核心——因为原来Laravel直接连数据库,现在要通过NodeJS做中间层,本质上是把Laravel的API层换成了Express,SQL查询逻辑完全复用:
2.1 NodeJS 后端搭建(连接MySQL并提供API)
先初始化Node项目并安装依赖:
mkdir node-backend && cd node-backend npm init -y npm install express mysql2 cors
然后创建server.js,写数据库连接和接口:
const express = require('express'); const mysql = require('mysql2'); const cors = require('cors'); const app = express(); app.use(cors()); // 允许Angular跨域请求 app.use(express.json()); // 解析JSON请求体 // 数据库配置和你原来Laravel的.env完全一致 const db = mysql.createConnection({ host: 'localhost', user: 'your-db-user', password: 'your-db-password', database: 'your-db-name' }); db.connect((err) => { if (err) throw err; console.log('成功连接到MySQL数据库!'); }); // 获取用户列表的接口 app.get('/api/users', (req, res) => { const query = 'SELECT * FROM users'; // 就是你原来Laravel里写的SQL db.query(query, (err, results) => { if (err) res.status(500).send(err); res.json(results); }); }); // 获取单个用户详情的接口 app.get('/api/users/:id', (req, res) => { const userId = req.params.id; const query = 'SELECT * FROM users WHERE id = ?'; db.query(query, [userId], (err, results) => { if (err) res.status(500).send(err); res.json(results[0]); }); }); const PORT = 3000; app.listen(PORT, () => { console.log(`后端服务运行在端口 ${PORT}`); });
这个Node层就相当于原来Laravel的API路由部分,只是用Express实现,SQL查询逻辑完全复用。
2.2 Angular 服务封装HTTP请求
在Angular里,我们用服务统一处理API调用,避免组件代码冗余:
ng generate service user
然后在user.service.ts里写请求逻辑:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; // 建议定义TypeScript接口约束数据类型(类似Laravel模型) interface User { id: number; name: string; email: string; created_at: string; } @Injectable({ providedIn: 'root' }) export class UserService { private apiUrl = 'http://localhost:3000/api'; constructor(private http: HttpClient) { } // 获取用户列表 getUsers(): Observable<User[]> { return this.http.get<User[]>(`${this.apiUrl}/users`); } // 获取单个用户详情 getUserById(id: number): Observable<User> { return this.http.get<User>(`${this.apiUrl}/users/${id}`); } }
注意要在app.module.ts里导入HttpClientModule,否则无法使用HttpClient:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ // ...其他导入 HttpClientModule ], // ... }) export class AppModule { }
2.3 Angular 组件调用服务并展示数据
比如在user-list.component.ts里获取并渲染用户列表:
import { Component, OnInit } from '@angular/core'; import { UserService } from '../user.service'; import { User } from '../user.service'; @Component({ selector: 'app-user-list', templateUrl: './user-list.component.html', styleUrls: ['./user-list.component.css'] }) export class UserListComponent implements OnInit { users: User[] = []; constructor(private userService: UserService) { } ngOnInit(): void { this.userService.getUsers().subscribe(users => { this.users = users; }); } }
对应的模板user-list.component.html(类似Blade的循环渲染):
<h2>用户列表</h2> <ul> <li *ngFor="let user of users"> <a [routerLink]="['/users', user.id]">{{ user.name }}</a> <p>{{ user.email }}</p> </li> </ul>
用户详情页user-detail.component.ts获取单个用户数据:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { UserService } from '../user.service'; import { User } from '../user.service'; @Component({ selector: 'app-user-detail', templateUrl: './user-detail.component.html', styleUrls: ['./user-detail.component.css'] }) export class UserDetailComponent implements OnInit { user: User | undefined; constructor( private route: ActivatedRoute, private userService: UserService ) { } ngOnInit(): void { const userId = Number(this.route.snapshot.paramMap.get('id')); this.userService.getUserById(userId).subscribe(user => { this.user = user; }); } }
对应的模板user-detail.component.html:
<div *ngIf="user"> <h2>{{ user.name }} 的详情</h2> <p>邮箱: {{ user.email }}</p> <p>创建时间: {{ user.created_at | date:'yyyy-MM-dd' }}</p> <a routerLink="/users">返回列表</a> </div>
这里的| date管道就类似Laravel的{{ $user->created_at->format('Y-m-d') }},Angular自带很多实用管道。
额外注意点
- 跨域问题:开发环境用Node的
cors中间件即可;生产环境建议用Angular代理配置或Nginx反向代理,避免直接暴露Node端口。 - 错误处理:上面的代码简化了错误处理,实际项目要在
subscribe里添加错误回调,或用RxJS的catchError操作符。
内容的提问来源于stack exchange,提问作者Platiplus

