目录
一、项目结构图
/shopping-website
├── /backend (Spring Boot 项目)
│ ├── /src
│ │ ├── /main
│ │ │ ├── /java
│ │ │ │ ├── /com
│ │ │ │ │ ├── /example
│ │ │ │ │ │ ├── /shopping
│ │ │ │ │ │ │ ├── /config # 配置文件,如Spring Security等
│ │ │ │ │ │ │ ├── /controller # 控制器,处理API请求
│ │ │ │ │ │ │ ├── /entity # 实体类,映射数据库表
│ │ │ │ │ │ │ ├── /exception # 异常处理类
│ │ │ │ │ │ │ ├── /repository # 数据访问层(JPA)
│ │ │ │ │ │ │ ├── /security # 安全配置,Spring Security配置
│ │ │ │ │ │ │ ├── /service # 业务逻辑层
│ │ │ │ │ │ │ └── /util # 工具类
│ │ │ │ │ │ ├── /resources
│ │ │ │ │ │ │ └── application.yml # 配置文件,数据库连接等
│ │ │ │ │ │ └── /static
│ │ └── /test
│ ├── /pom.xml # Maven 配置文件,包含所有依赖
│
├── /frontend (Angular 项目)
│ ├── /src
│ │ ├── /app
│ │ │ ├── /components # 公共组件
│ │ │ │ ├── /login
│ │ │ │ ├── /register
│ │ │ │ ├── /product-list
│ │ │ │ ├── /cart
│ │ │ │ └── /order
│ │ │ ├── /services # 服务层,处理API请求
│ │ │ │ ├── /auth.service.ts
│ │ │ │ ├── /product.service.ts
│ │ │ │ ├── /cart.service.ts
│ │ │ │ ├── /order.service.ts
│ │ │ ├── /guards # 路由守卫
│ │ │ │ └── /auth.guard.ts
│ │ │ ├── /models # 数据模型类
│ │ │ │ ├── /user.ts
│ │ │ │ ├── /product.ts
│ │ │ │ ├── /order.ts
│ │ │ └── /app.module.ts # Angular 主模块
│ │ ├── /assets # 静态资源(图片、字体等)
│ │ └── /environments # 环境配置文件
│ ├── /angular.json # Angular 配置文件
│ ├── /package.json # Node.js 配置文件
│ └── /tsconfig.json # TypeScript 配置文件
│
└── README.md # 项目说明文件
二、目录结构解析
后端 (Spring Boot)
-
/src/main/java/com/example/shopping/config
- SecurityConfig.java:Spring Security 配置类,设置权限控制。
- PaymentConfig.java:支付接口配置类(集成支付宝、微信支付等)。
-
/controller
处理HTTP请求的Controller类,通常负责接收前端请求、调用服务层逻辑并返回数据。例如:- UserController.java:处理用户注册、登录请求。
- ProductController.java:处理商品展示、商品查询等请求。
- OrderController.java:处理订单相关请求,订单创建、查询、状态更新等。
-
/entity
- User.java:用户实体类。
- Product.java:商品实体类。
- Order.java:订单实体类,包含订单的各个字段,如商品、用户、支付状态等。
-
/repository
- UserRepository.java:操作用户数据的JPA接口。
- ProductRepository.java:操作商品数据的JPA接口。
- OrderRepository.java:操作订单数据的JPA接口。
-
/security
- UserDetailsServiceImpl.java:用户认证服务,实现
UserDetailsService
接口,加载用户信息。
- UserDetailsServiceImpl.java:用户认证服务,实现
-
/service
- UserService.java:处理用户逻辑,包含注册、登录等业务逻辑。
- ProductService.java:商品逻辑处理,处理商品的添加、修改、查询等。
- OrderService.java:订单管理,处理订单的创建、支付、发货等业务。
- PaymentService.java:支付相关的服务,集成支付宝、微信支付等接口。
-
/util
- PaymentUtil.java:支付工具类,封装与第三方支付平台交互的工具方法。
- OrderUtil.java:订单处理工具类,包含生成订单号、处理订单状态等功能。
前端 (Angular)
-
/components
- login/:登录组件,提供用户登录界面和逻辑。
- register/:注册组件,提供用户注册界面和逻辑。
- product-list/:商品列表组件,展示商品信息。
- cart/:购物车组件,展示购物车中的商品,支持修改商品数量和删除商品。
- order/:订单组件,展示订单信息和订单管理功能。
-
/services
- auth.service.ts:认证服务,处理用户的登录、注册、权限检查等操作。
- product.service.ts:商品服务,提供与商品相关的API调用。
- cart.service.ts:购物车服务,提供购物车操作功能。
- order.service.ts:订单服务,提供订单创建、查询、支付等功能。
-
/guards
- auth.guard.ts:路由守卫,用于保护用户路由,确保未登录用户无法访问需要登录的页面。
-
/models
- user.ts:用户模型类,定义用户的数据结构。
- product.ts:商品模型类,定义商品的数据结构。
- order.ts:订单模型类,定义订单的数据结构。
-
/app.module.ts:主模块,包含Angular应用的模块配置,声明所有组件、服务和路由。
三、技术栈
- 前端:Angular + Bootstrap
- 后端:Spring Boot + Spring Security + JPA + MySQL
- 数据库:MySQL
四、具体功能实现
-
用户管理(登录、注册、权限控制)
- 前端:使用 Angular 路由守卫和服务实现登录、注册和角色管理。
- 后端:通过 Spring Security 配置用户权限,确保不同角色用户的不同访问权限。
-
支付功能(支付宝、微信支付等)
- 后端:集成支付宝和微信支付接口,处理支付请求、支付回调等。
- 前端:在订单确认页面显示支付二维码(支付宝、微信支付),并处理支付回调。
-
商品管理和购物车
- 后端:提供商品的增删改查接口,支持用户浏览商品,添加到购物车。
- 前端:购物车组件提供购物车的管理功能,支持增加、删除商品和修改商品数量。
-
订单管理(创建、支付、发货)
- 后端:管理订单的创建、支付、发货等流程,处理订单状态的更新。
- 前端:用户可以查看自己的订单,并进行支付和查看订单详情。管理员可以查看所有订单并发货。
-
后台管理
- 后端:管理员角色可以访问商品管理、订单管理、用户管理等功能。
- 前端:管理界面提供商品、订单、用户管理的后台页面。
五、数据库设计
- 用户表:用于存储用户信息。
- 角色表:用于存储用户角色(如管理员、普通用户等)。
- 商品表:用于存储商品信息。
- 订单表:用于存储订单信息。
- 订单项表:用于存储每个订单中的商品项。
- 购物车表:用于存储用户的购物车商品。
- 支付表:用于记录支付信息(与支付宝、微信等支付集成相关)。
-
User (用户表)
CREATE TABLE `user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID', `username` VARCHAR(100) NOT NULL UNIQUE COMMENT '用户名', `password` VARCHAR(255) NOT NULL COMMENT '用户密码', `email` VARCHAR(255) DEFAULT NULL COMMENT '邮箱', `phone` VARCHAR(15) DEFAULT NULL COMMENT '手机号', `address` TEXT DEFAULT NULL COMMENT '收货地址', `status` TINYINT(1) DEFAULT 1 COMMENT '状态 1-启用 0-禁用', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-
Role(角色表)
CREATE TABLE `role` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '角色ID', `role_name` VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称', `description` VARCHAR(255) DEFAULT NULL COMMENT '角色描述', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
-
user_role(用户角色关联表)
CREATE TABLE `user_role` ( `user_id` BIGINT(20) NOT NULL COMMENT '用户ID', `role_id` BIGINT(20) NOT NULL COMMENT '角色ID', PRIMARY KEY (`user_id`, `role_id`), CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_role` FOREIGN KEY (`role_id`) REFERENCES `role`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表';
-
product(商品表)
CREATE TABLE `product` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID', `name` VARCHAR(255) NOT NULL COMMENT '商品名称', `description` TEXT DEFAULT NULL COMMENT '商品描述', `price` DECIMAL(10, 2) NOT NULL COMMENT '商品价格', `stock` INT(11) NOT NULL DEFAULT 0 COMMENT '商品库存', `category_id` BIGINT(20) DEFAULT NULL COMMENT '商品类别ID', `image_url` VARCHAR(255) DEFAULT NULL COMMENT '商品图片URL', `status` TINYINT(1) DEFAULT 1 COMMENT '商品状态 1-上架 0-下架', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
-
order(订单表)
CREATE TABLE `order` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '订单ID', `user_id` BIGINT(20) NOT NULL COMMENT '用户ID', `total_price` DECIMAL(10, 2) NOT NULL COMMENT '订单总价', `status` ENUM('PENDING', 'PAID', 'SHIPPED', 'DELIVERED', 'CANCELLED') NOT NULL DEFAULT 'PENDING' COMMENT '订单状态', `shipping_address` TEXT NOT NULL COMMENT '收货地址', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `payment_method` VARCHAR(50) DEFAULT NULL COMMENT '支付方式', `payment_status` ENUM('PENDING', 'SUCCESS', 'FAILED') NOT NULL DEFAULT 'PENDING' COMMENT '支付状态', CONSTRAINT `fk_user_order` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
- order_item(订单项表)
CREATE TABLE `order_item` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '订单项ID', `order_id` BIGINT(20) NOT NULL COMMENT '订单ID', `product_id` BIGINT(20) NOT NULL COMMENT '商品ID', `quantity` INT(11) NOT NULL DEFAULT 1 COMMENT '商品数量', `unit_price` DECIMAL(10, 2) NOT NULL COMMENT '商品单价', CONSTRAINT `fk_order` FOREIGN KEY (`order_id`) REFERENCES `order`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_product` FOREIGN KEY (`product_id`) REFERENCES `product`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单项表';
- cart(购物车表)
CREATE TABLE `cart` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '购物车ID', `user_id` BIGINT(20) NOT NULL COMMENT '用户ID', `product_id` BIGINT(20) NOT NULL COMMENT '商品ID', `quantity` INT(11) NOT NULL DEFAULT 1 COMMENT '商品数量', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', CONSTRAINT `fk_user_cart` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_product_cart` FOREIGN KEY (`product_id`) REFERENCES `product`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车表';
- payment(支付表)
CREATE TABLE `payment` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '支付ID', `order_id` BIGINT(20) NOT NULL COMMENT '订单ID', `payment_method` ENUM('ALIPAY', 'WECHAT', 'CREDIT_CARD') NOT NULL COMMENT '支付方式', `payment_status` ENUM('PENDING', 'SUCCESS', 'FAILED') NOT NULL DEFAULT 'PENDING' COMMENT '支付状态', `payment_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '支付时间', `transaction_id` VARCHAR(255) DEFAULT NULL COMMENT '交易流水号', `amount` DECIMAL(10, 2) NOT NULL COMMENT '支付金额', CONSTRAINT `fk_order_payment` FOREIGN KEY (`order_id`) REFERENCES `order`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付表';
-
商品类别表
category
(可选)CREATE TABLE `category` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '类别ID', `name` VARCHAR(255) NOT NULL COMMENT '类别名称', `description` TEXT DEFAULT NULL COMMENT '类别描述', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品类别表';
-
触发器(可选)
在某些情况下,你可能需要一些触发器来自动更新库存或记录日志。
DELIMITER $$ CREATE TRIGGER update_stock_after_order_insert AFTER INSERT ON `order_item` FOR EACH ROW BEGIN UPDATE `product` SET `stock` = `stock` - NEW.quantity WHERE `id` = NEW.product_id; END$$ DELIMITER ;
六、后端实现
1. 设置Spring Boot项目
首先,创建一个Spring Boot项目,集成Spring Web, Spring Data JPA, Spring Security。
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Thymeleaf for templates -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
2. 数据库实体类
- User.java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
private String role; // ROLE_USER, ROLE_ADMIN
// getters and setters
}
- Product.java
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
private double price;
private int stock;
// getters and setters
}
- Cart.java
@Entity public class Cart { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne private User user; @ManyToOne private Product product; private int quantity; // getters and setters }
- Order.java
@Entity public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne private User user; private double totalPrice; private String status; // PENDING, COMPLETED private String address; private LocalDateTime createTime; @OneToMany(mappedBy = "order") private List<OrderItem> orderItems; // getters and setters }
- OrderItem.java
@Entity public class OrderItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne private Order order; @ManyToOne private Product product; private int quantity; private double price; // getters and setters }
3. 创建Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}
@Repository
public interface CartRepository extends JpaRepository<Cart, Long> {
List<Cart> findByUser(User user);
}
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUser(User user);
}
4. 创建Service层
- UserService.java
@Service public class UserService { @Autowired private UserRepository userRepository; public User register(User user) { // 处理密码加密 return userRepository.save(user); } public User login(String username, String password) { // 密码验证逻辑 return userRepository.findByUsername(username).orElse(null); } }
- ProductService.java
@Service public class ProductService { @Autowired private ProductRepository productRepository; public List<Product> getAllProducts() { return productRepository.findAll(); } public Product getProduct(Long id) { return productRepository.findById(id).orElse(null); } public Product addProduct(Product product) { return productRepository.save(product); } }
5. 创建Controller层
- UserController.java
@RestController @RequestMapping("/api/user") public class UserController { @Autowired private UserService userService; @PostMapping("/register") public ResponseEntity<User> register(@RequestBody User user) { return ResponseEntity.ok(userService.register(user)); } @PostMapping("/login") public ResponseEntity<User> login(@RequestParam String username, @RequestParam String password) { User user = userService.login(username, password); if (user == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); } return ResponseEntity.ok(user); } }
- ProductController.java
@RestController @RequestMapping("/api/products") public class ProductController { @Autowired private ProductService productService; @GetMapping public List<Product> getAllProducts() { return productService.getAllProducts(); } @GetMapping("/{id}") public Product getProduct(@PathVariable Long id) { return productService.getProduct(id); } }
- CartController.java
@RestController @RequestMapping("/api/cart") public class CartController { @Autowired private CartRepository cartRepository; @PostMapping("/add") public ResponseEntity<Cart> addToCart(@RequestBody Cart cart) { return ResponseEntity.ok(cartRepository.save(cart)); } @GetMapping("/list") public List<Cart> getCartItems(@RequestParam Long userId) { return cartRepository.findByUser(new User(userId)); } }
七、前端实现(Angular)
1、创建 Angular 服务层
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private baseUrl = `${environment.apiBaseUrl}/api/user`;
constructor(private http: HttpClient) {}
register(user: any): Observable<any> {
return this.http.post(`${this.baseUrl}/register`, user);
}
getUserByUsername(username: string): Observable<any> {
return this.http.get(`${this.baseUrl}/${username}`);
}
}
2、创建 Angular 路由配置
在 app-routing.module.ts
中配置路由,指向用户注册和商品展示页面。
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RegisterComponent } from './register/register.component';
import { ProductListComponent } from './product-list/product-list.component';
const routes: Routes = [
{ path: 'register', component: RegisterComponent },
{ path: 'products', component: ProductListComponent },
{ path: '', redirectTo: '/register', pathMatch: 'full' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
3、配置文件
确保在前端项目中配置了 API 基本路径和其他环境配置。比如,在 environments/environment.ts
中配置:
export const environment = {
production: false,
apiBaseUrl: 'http://localhost:8080'
};
4、用户登录与注册
- 使用Angular表单来处理用户输入。
register.component.ts import { Component } from '@angular/core'; import { AuthService } from '../services/auth.service'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) export class RegisterComponent { user = { username: '', password: '', email: '', phone: '', address: '' }; constructor(private authService: AuthService) {} register() { this.authService.register(this.user).subscribe(response => { console.log('User registered successfully!', response); }, error => { console.error('Error registering user', error); }); } }
- 与后端的
/api/user/register
和/api/user/login
接口交互。
5、商品浏览与添加购物车
- 显示商品列表(调用
/api/products
接口)。product.service.tsimport { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { environment } from '../environments/environment'; @Injectable({ providedIn: 'root' }) export class ProductService { private baseUrl = `${environment.apiBaseUrl}/api/products`; constructor(private http: HttpClient) {} addProduct(product: any): Observable<any> { return this.http.post(`${this.baseUrl}/add`, product); } getProduct(id: number): Observable<any> { return this.http.get(`${this.baseUrl}/${id}`); } }
product-list.component.ts
import { Component, OnInit } from '@angular/core'; import { ProductService } from '../services/product.service'; @Component({ selector: 'app-product-list', templateUrl: './product-list.component.html', styleUrls: ['./product-list.component.css'] }) export class ProductListComponent implements OnInit { products: any[] = []; constructor(private productService: ProductService) {} ngOnInit(): void { this.productService.getProduct(1).subscribe(data => { this.products = [data]; }); } }
- 添加商品到购物车(调用
/api/cart/add
接口)。
6、订单管理与收货地址
- 用户下单,提交购物车中的商品到订单接口。
- 用户管理自己的订单和收货地址。
7、后台管理系统
- 管理员可以增、删、改商品,查看所有用户和订单。
八、部署与测试
- 配置Spring Boot与数据库连接。
- 在MySQL中创建数据库并运行Spring Boot应用。
- 使用Angular构建前端并与后端API交互。