如何在Angular 14中通过PHP请求MySQL数据库?
Angular 14 对接现有PHP查询接口实现指南
问题背景
我正在将原PHP架构的网站迁移至Angular 14,仅需实现查询文件名、对应作者及创建年份的数据库交互。希望以Angular友好的方式实现,避免权宜之计。现有PHP代码通过PDO连接MySQL,接收POST参数执行模糊查询,并用echo生成结果表格。不想废弃现有PHP代码,打算通过Angular服务订阅POST请求(如同消费API),将后端返回的数据绑定到Angular组件的HTML中。
一、改造PHP后端为JSON API
原PHP代码直接输出HTML表格,无法被Angular直接解析,需要改成返回JSON格式数据,同时修复SQL注入漏洞(原代码直接拼接变量到SQL语句,存在严重安全风险)。
修改后的PHP核心代码:
<?php // 解决跨域问题(如果Angular和PHP不在同一域名下) header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); try { // 数据库连接(替换为实际的DSN、用户名、密码) $connect = new PDO('mysql:host=localhost;dbname=你的数据库名', '用户名', '密码'); $connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 获取POST参数,为空时设为空字符串(用于模糊查询) $author = isset($_POST['name']) ? $_POST['name'] : ''; $title = isset($_POST['title']) ? $_POST['title'] : ''; $year = isset($_POST['year']) ? $_POST['year'] : ''; // 预处理SQL语句,避免SQL注入 $sql = "SELECT author, title, year, url FROM files WHERE author LIKE CONCAT('%', :author, '%') AND title LIKE CONCAT('%', :title, '%') AND year LIKE CONCAT('%', :year, '%') ORDER BY author"; $stmt = $connect->prepare($sql); $stmt->bindParam(':author', $author); $stmt->bindParam(':title', $title); $stmt->bindParam(':year', $year); $stmt->execute(); // 获取所有查询结果 $result = $stmt->fetchAll(PDO::FETCH_ASSOC); // 返回JSON格式数据 echo json_encode($result); } catch(PDOException $e) { // 异常处理,返回错误信息 echo json_encode(array("error" => $e->getMessage())); } ?>
注意:原代码存在字段名不一致问题(如查询
author但输出用autor,查询title用titulo),请确保数据库字段名和代码中的字段名完全匹配。
二、Angular 14 前端实现
1. 创建数据模型(Interface)
在src/app目录下创建file.model.ts:
export interface FileItem { author: string; title: string; year: string; url: string; }
2. 创建查询服务
使用Angular CLI生成服务:
ng generate service file-search
修改file-search.service.ts内容,注入HttpClient并实现POST请求:
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { FileItem } from './file.model'; @Injectable({ providedIn: 'root' }) export class FileSearchService { // 替换为你的PHP接口实际地址 private apiUrl = 'http://你的域名/查询接口.php'; constructor(private http: HttpClient) { } searchFiles(params: { name: string; title: string; year: string }): Observable<FileItem[]> { const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }); // 转换参数为POST表单格式 const body = new URLSearchParams(); body.set('name', params.name); body.set('title', params.title); body.set('year', params.year); return this.http.post<FileItem[]>(this.apiUrl, body.toString(), { headers }); } }
3. 配置HttpClientModule
在app.module.ts中导入HttpClientModule:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; // 导入模块 import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, HttpClientModule], // 添加到导入列表 providers: [], bootstrap: [AppComponent] }) export class AppModule { }
4. 组件中调用服务并绑定数据
修改app.component.ts:
import { Component } from '@angular/core'; import { FileSearchService } from './file-search.service'; import { FileItem } from './file.model'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { searchParams = { name: '', title: '', year: '' }; fileList: FileItem[] = []; errorMessage = ''; constructor(private fileSearchService: FileSearchService) { } onSearch(): void { this.fileSearchService.searchFiles(this.searchParams).subscribe({ next: (data) => { this.fileList = data; this.errorMessage = ''; }, error: (err) => { this.errorMessage = '查询失败:' + err.message; this.fileList = []; } }); } }
5. 组件模板渲染表格
修改app.component.html:
<div class="search-form"> <input type="text" [(ngModel)]="searchParams.name" placeholder="作者"> <input type="text" [(ngModel)]="searchParams.title" placeholder="文件名"> <input type="text" [(ngModel)]="searchParams.year" placeholder="创建年份"> <button (click)="onSearch()">查询</button> </div> <div *ngIf="errorMessage" class="error">{{ errorMessage }}</div> <table *ngIf="fileList.length > 0"> <thead> <tr> <th>作者</th> <th>文件名</th> <th>创建年份</th> </tr> </thead> <tbody> <tr *ngFor="let file of fileList"> <td>{{ file.author }}</td> <td><a [href]="file.url" target="_blank">{{ file.title }}</a></td> <td>{{ file.year }}</td> </tr> </tbody> </table> <p *ngIf="fileList.length === 0 && !errorMessage">暂无数据</p>
注意:使用
ngModel需要在app.module.ts中导入FormsModule:
import { FormsModule } from '@angular/forms'; @NgModule({ imports: [BrowserModule, HttpClientModule, FormsModule], // 添加FormsModule // ... })
三、关键注意事项
- SQL注入防护:必须使用PDO预处理语句,绝对不能直接将用户输入拼接进SQL语句,原代码的写法存在严重安全漏洞,必须修复。
- 跨域问题:如果Angular开发服务器(默认4200端口)和PHP服务器端口/域名不同,需要在PHP中添加CORS头(已在改造后的PHP代码中配置)。
- 字段名一致性:确保数据库字段名、PHP返回的JSON字段名、Angular模型字段名完全一致,否则会出现数据绑定失败的问题。
内容的提问来源于stack exchange,提问作者KimiH
相关产品推荐
相关产品推荐

