一、环境配置(Environments)

Article detail

前端

2026/4/20 · 45 分钟阅读

一、环境配置(Environments)

本文档描述基于 Angular 构建的流媒体服务注册(Signup)与邮箱验证(Verify Email)功能的前端代码结构、组件交互及与后端 API 的对接方式。所有代码均保持原样,仅添加解释性说明。


一、环境配置(Environments)

1.1 文件:environment.development.ts

路径src/environments/environment.development.ts
功能:开发环境下的全局配置变量,主要用于指定后端 API 的基础 URL。

//连接后端接口的环境配置文件
export const environment = {
  production: false,
  apiUrl: 'http://localhost:8080/api' // 替换为你的后端API地址
};
  • production: false:标识当前为开发环境。
  • apiUrl:后端 Spring Boot 服务的基础地址,所有 API 请求将以此为前缀。

1.2 文件:environment.ts

路径src/environments/environment.ts
功能:生产环境下的全局配置变量。通常在实际部署时,apiUrl 会被替换为线上服务器地址。

//连接后端接口的环境配置文件
export const environment = {
  production: true,
  apiUrl: 'http://localhost:8080/api' // 替换为你的后端API地址
};

💡 注意:生产环境中 apiUrl 应指向真实的线上后端域名,此处仍为本地地址仅作示例。


二、共享服务(Shared Services)

这些服务位于 src/app/shared/services/ 目录下,通过 Angular 的依赖注入机制在多个组件中复用。

2.1 认证服务:auth-service.ts

路径src/app/shared/services/auth-service.ts
功能:封装与后端认证相关的 HTTP 请求,并提供自定义表单验证器(密码一致性校验)。

import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment.development';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private apiUrl = environment.apiUrl + '/auth'; // 后端认证API的基础URL

  constructor(private http: HttpClient) {}

  // 自定义验证器:检查确认密码是否与密码一致
  passwrodMatchValidator(passwrodControlName: string): ValidatorFn {
    return (confirmControl: AbstractControl): ValidationErrors | null => {
      if (!confirmControl.parent) return null;
      const password = confirmControl.parent.get(passwrodControlName)?.value;
      const confirmPassword = confirmControl.value;
      if (password !== confirmPassword) {
        return { passwordMismatch: true };
      }
      return null;
    };
  }

  // 用户注册 POST /api/auth/signup
  signup(signupData: any): Observable<any> {
    return this.http.post<any>(`${this.apiUrl}/signup`, signupData);
  }

  // 邮箱验证 GET /api/auth/verify-email?token=xxx
  verifyEmail(token: string) {
    return this.http.get(`${this.apiUrl}/verify-email?token=${token}`);
  }
}

⚠️ 拼写提醒:方法名 passwrodMatchValidator 存在拼写错误(passwrod 应为 password),调用时需注意。

2.2 错误处理服务:error-handler-service.ts

路径src/app/shared/services/error-handler-service.ts
功能:统一处理 API 请求失败的错误,提取错误信息并通过通知服务展示给用户。

import { Injectable } from '@angular/core';
import { NotificationService } from './notification-service';

@Injectable({
  providedIn: 'root',
})
export class ErrorHandlerService {
  constructor(private notificationService: NotificationService) {}

  handle(err: any, fallbackMessage: string) {
    // 尝试从错误对象中提取后端返回的错误消息,否则使用备用消息
    const errorMsg = err.console.error.error || fallbackMessage;
    this.notificationService.error(errorMsg);
    console.error('API Error:', err);
  }
}

⚠️ 潜在问题err.console.error.error 路径极可能为 undefined,实际错误信息通常位于 err.error.messageerr.message。当前代码可能导致永远使用 fallbackMessage

2.3 通知服务:notification-service.ts

路径src/app/shared/services/notification-service.ts
功能:基于 Angular Material 的 MatSnackBar 提供全局的消息提示(成功/错误)。

import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';

@Injectable({
  providedIn: 'root',
})
export class NotificationService {
  constructor(private snackBar: MatSnackBar) {}

  // 成功提示(默认3秒后自动关闭)
  sccess(message: string, duration: number = 3000) {
    this.snackBar.open(message, 'Close', {
      duration: duration,
      horizontalPosition: 'center',
      verticalPosition: 'top',
      panelClass: ['notification-success'],
    });
  }

  // 错误提示(默认5秒后自动关闭)
  error(message: string, duration: number = 5000) {
    this.snackBar.open(message, 'Close', {
      duration: duration,
      horizontalPosition: 'center',
      verticalPosition: 'top',
      panelClass: ['notification-error'],
    });
  }
}

⚠️ 拼写提醒:方法名 sccess 拼写错误,应为 success。调用方需注意。


三、注册组件(Signup)

3.1 组件类:signup.ts

路径src/app/signup/signup.ts
功能:处理用户注册表单的交互逻辑,包括表单验证、提交数据到后端、处理响应及页面跳转。

import { Component, OnInit } from '@angular/core';
import { ErrorHandlerService } from '../shared/services/error-handler-service';
import { AuthService } from '../shared/services/auth-service';
import { NotificationService } from '../shared/services/notification-service';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
  selector: 'app-signup',
  standalone: false,
  templateUrl: './signup.html',
  styleUrls: ['./signup.css'],
})
export class Signup implements OnInit {
  hidePassword = true;
  hideConfirmPassword = true;
  signupForm!: FormGroup;
  loading = false;

  constructor(
    private fb: FormBuilder,
    private authService: AuthService,
    private router: Router,
    private route: ActivatedRoute,
    private notification: NotificationService,
    private errorHandlerService: ErrorHandlerService,
  ) {
    // 初始化响应式表单及验证规则
    this.signupForm = this.fb.group({
      fullName: ['', [Validators.required, Validators.minLength(2)]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(6)]],
      confirmPassword: ['', [Validators.required, this.authService.passwrodMatchValidator('password')]]
    });
  }

  ngOnInit(): void {
    // 若从落地页跳转携带了 email 参数,则自动填充邮箱字段
    const email = this.route.snapshot.queryParamMap.get('email');
    if (email) {
      this.signupForm.patchValue({ email: email });
      console.log('prefill signup email:', email);
    }
  }

  submit() {
    this.loading = true;
    const formData = this.signupForm.value;
    const data = {
      fullName: formData.fullName,
      email: formData.email?.trim().toLowerCase(),
      password: formData.password
    };

    this.authService.signup(data).subscribe({
      next: (response: any) => {
        this.loading = false;
        this.notification.sccess(response?.message || 'Signup successful! Please check your email to verify your account.');
        this.router.navigate(['/login']);
      },
      error: (err) => {
        this.loading = false;
        this.errorHandlerService.handle(err, 'Signup failed. Please try again later.');
      }
    });
  }
}

3.2 模板:signup.html

路径src/app/signup/signup.html
功能:定义注册页面的 UI 结构,包含全名、邮箱、密码、确认密码输入框及提交按钮,同时提供跳转到登录页的链接。

  • 使用 Angular Material 表单组件(mat-form-fieldmatInput 等)。
  • 密码可见性切换按钮。
  • 表单无效时禁用提交按钮。
  • 错误信息通过 mat-error 动态显示。

3.3 样式:signup.css

路径src/app/signup/signup.css
功能:提供与落地页一致的深色主题样式,包括背景遮罩、半透明卡片、输入框边框颜色定制等。

  • 背景图沿用 /landing.jpg
  • 卡片背景为 rgba(0, 0, 0, 0.75),营造玻璃态效果。
  • 通过 ::ng-deep 覆盖 Material 表单字段的默认边框颜色。

四、邮箱验证组件(Verify Email)

4.1 组件类:verify-email.ts

路径src/app/verify-email/verify-email.ts
功能:处理用户点击邮件中的验证链接后的验证逻辑。从 URL 提取 token 参数,调用后端验证接口,根据结果显示成功或失败界面。

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AuthService } from '../shared/services/auth-service';

@Component({
  selector: 'app-verify-email',
  standalone: false,
  templateUrl: './verify-email.html',
  styleUrls: ['./verify-email.css'],
})
export class VerifyEmail implements OnInit {
  loading: boolean = true;
  success: boolean = false;
  message: string = '';

  constructor(
    private route: ActivatedRoute,
    private authService: AuthService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    const token = this.route.snapshot.queryParamMap.get('token');
    console.log('[VerifyEmail] token:', token);

    if (!token) {
      this.loading = false;
      this.success = false;
      this.message = 'Invalid verification link. No token provided.';
      console.log('[VerifyEmail] No token provided');
      return;
    }

    this.authService.verifyEmail(token).subscribe({
      next: (response: any) => {
        this.loading = false;
        this.success = true;
        this.message = response?.message || 'Email verified successfully! You can now log in.';
        this.cdr.detectChanges();
        console.log('[VerifyEmail] Success:', response);
      },
      error: (err) => {
        this.loading = false;
        this.success = false;
        this.message = err?.error?.message || err?.error?.err || 'Verification failed. The link may be invalid or expired.';
        this.cdr.detectChanges();
        console.log('[VerifyEmail] Error:', err);
      }
    });
  }
}

4.2 模板:verify-email.html

路径src/app/verify-email/verify-email.html
功能:根据验证状态显示不同的 UI:

  • loading = true:显示加载动画。
  • success = true:显示成功图标及“Go to Login”按钮。
  • success = false:显示失败图标、错误信息及“Resend verification”链接。

4.3 样式:verify-email.css

路径src/app/verify-email/verify-email.css
功能:深色主题的验证结果展示页样式,包含成功/失败图标、响应式布局。


五、前后端对接说明

5.1 API 端点映射

前端方法HTTP 方法后端 URL请求体/参数
authService.signup(data)POSThttp://localhost:8080/api/auth/signup{ fullName, email, password }
authService.verifyEmail(token)GEThttp://localhost:8080/api/auth/verify-email?token=xxxtoken 作为查询参数

5.2 后端预期响应

注册成功(HTTP 200):

{
  "message": "Registration successful! Please check your email to verify your account"
}

邮箱验证成功(HTTP 200):

{
  "message": "Email verified successfully! you can now login!"
}

错误响应(由 GlobalExceptionHandler 统一返回):

{
  "timestamp": "2026-04-20T10:00:00Z",
  "error": "Email already exists"
}

5.3 环境切换

  • 开发时使用 environment.development.ts
  • 生产构建时自动替换为 environment.ts 中的配置。

六、已知问题与注意事项

问题影响建议
auth-service.tspasswrodMatchValidator 拼写错误调用时需使用错误拼写的方法名可保留,但注意命名一致性
error-handler-service.ts 中错误提取路径错误后端返回的真实错误信息可能无法显示调试时需留意控制台输出
notification-service.tssccess 拼写错误调用方必须使用 sccess 方法注意与常规拼写区分
验证页面组件名称与品牌不一致组件内显示 “PulseScreen”,但其他页面为 “Pudplanet”视觉上可能不统一,可后期调整
未定义 resend-verification 路由验证失败页面中的“Resend it”链接无法跳转需补充对应组件和路由配置

以上即为 Pudplanet 前端注册与邮箱验证模块的完整技术文档。所有代码均保持原样,仅补充了功能描述和对接说明。你可直接将其用于项目文档或团队分享。

评论

动作测试