You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:35:19