您好,登录后才能下订单哦!
随着电子商务的快速发展,秒杀活动已经成为各大电商平台吸引用户的重要手段之一。秒杀活动通常会在短时间内吸引大量用户参与,这对系统的并发处理能力和稳定性提出了极高的要求。本文将详细介绍如何使用Spring Boot、Redis和Vue.js实现一个高并发的秒杀系统。
Spring Boot是一个基于Spring框架的快速开发框架,它简化了Spring应用的初始搭建和开发过程。Spring Boot提供了大量的自动配置和依赖管理功能,使得开发者可以快速构建独立运行的、生产级别的Spring应用。
Redis是一个开源的内存数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis支持多种数据结构,如字符串、哈希、列表、集合等,并且提供了丰富的操作命令。在秒杀系统中,Redis主要用于缓存商品库存和用户信息,以提高系统的响应速度和并发处理能力。
Vue.js是一个渐进式JavaScript框架,用于构建用户界面。Vue.js的核心库只关注视图层,易于与其他库或现有项目集成。Vue.js提供了响应式的数据绑定和组件化的开发方式,使得前端开发更加高效和灵活。
秒杀系统的核心需求包括:
秒杀系统的架构设计如下:
秒杀系统的数据库设计如下:
商品表(product):
id
:商品ID,主键。name
:商品名称。price
:商品价格。stock
:商品库存。start_time
:秒杀开始时间。end_time
:秒杀结束时间。用户表(user):
id
:用户ID,主键。username
:用户名。password
:密码。email
:邮箱。订单表(order):
id
:订单ID,主键。user_id
:用户ID,外键。product_id
:商品ID,外键。order_time
:订单时间。status
:订单状态。使用Spring Initializr创建一个新的Spring Boot项目,选择以下依赖:
配置application.properties
文件,设置数据库连接和Redis连接信息。
spring.datasource.url=jdbc:mysql://localhost:3306/seckill?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.redis.host=localhost
spring.redis.port=6379
redis-server
vue create seckill-frontend
npm install axios vue-router vuex
Product
实体类。@Entity
@Data
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
private LocalDateTime startTime;
private LocalDateTime endTime;
}
ProductRepository
接口。public interface ProductRepository extends JpaRepository<Product, Long> {
}
ProductService
服务类。@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public List<Product> getAllProducts() {
return productRepository.findAll();
}
public Product getProductById(Long id) {
return productRepository.findById(id).orElse(null);
}
public Product saveProduct(Product product) {
return productRepository.save(product);
}
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
}
ProductController
控制器类。@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productService.saveProduct(product);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
return productService.saveProduct(product);
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
}
User
实体类。@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
}
UserRepository
接口。public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
UserService
服务类。@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User saveUser(User user) {
return userRepository.save(user);
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
UserController
控制器类。@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.saveUser(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.saveUser(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
SeckillService
服务类。@Service
public class SeckillService {
@Autowired
private ProductRepository productRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean seckill(Long productId, Long userId) {
String stockKey = "product_stock_" + productId;
String userKey = "seckill_user_" + productId;
// 检查用户是否已经参与过秒杀
if (redisTemplate.opsForSet().isMember(userKey, userId)) {
return false;
}
// 检查库存
Long stock = redisTemplate.opsForValue().decrement(stockKey);
if (stock == null || stock < 0) {
return false;
}
// 记录用户参与秒杀
redisTemplate.opsForSet().add(userKey, userId);
return true;
}
}
SeckillController
控制器类。@RestController
@RequestMapping("/api/seckill")
public class SeckillController {
@Autowired
private SeckillService seckillService;
@PostMapping("/{productId}")
public ResponseEntity<String> seckill(@PathVariable Long productId, @RequestParam Long userId) {
boolean result = seckillService.seckill(productId, userId);
if (result) {
return ResponseEntity.ok("秒杀成功");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("秒杀失败");
}
}
}
Order
实体类。@Entity
@Data
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private Long productId;
private LocalDateTime orderTime;
private String status;
}
OrderRepository
接口。public interface OrderRepository extends JpaRepository<Order, Long> {
}
OrderService
服务类。@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public List<Order> getAllOrders() {
return orderRepository.findAll();
}
public Order getOrderById(Long id) {
return orderRepository.findById(id).orElse(null);
}
public Order saveOrder(Order order) {
return orderRepository.save(order);
}
public void deleteOrder(Long id) {
orderRepository.deleteById(id);
}
}
OrderController
控制器类。@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping
public List<Order> getAllOrders() {
return orderService.getAllOrders();
}
@GetMapping("/{id}")
public Order getOrderById(@PathVariable Long id) {
return orderService.getOrderById(id);
}
@PostMapping
public Order createOrder(@RequestBody Order order) {
return orderService.saveOrder(order);
}
@PutMapping("/{id}")
public Order updateOrder(@PathVariable Long id, @RequestBody Order order) {
order.setId(id);
return orderService.saveOrder(order);
}
@DeleteMapping("/{id}")
public void deleteOrder(@PathVariable Long id) {
orderService.deleteOrder(id);
}
}
ProductList.vue
组件。<template>
<div>
<h1>商品列表</h1>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - {{ product.price }}元
<button @click="seckill(product.id)">秒杀</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
products: []
};
},
created() {
this.fetchProducts();
},
methods: {
fetchProducts() {
axios.get('/api/products')
.then(response => {
this.products = response.data;
})
.catch(error => {
console.error(error);
});
},
seckill(productId) {
const userId = 1; // 假设用户ID为1
axios.post(`/api/seckill/${productId}?userId=${userId}`)
.then(response => {
alert(response.data);
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
Login.vue
组件。<template>
<div>
<h1>用户登录</h1>
<form @submit.prevent="login">
<label for="username">用户名:</label>
<input type="text" id="username" v-model="username" required>
<label for="password">密码:</label>
<input type="password" id="password" v-model="password" required>
<button type="submit">登录</button>
</form>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
password: ''
};
},
methods: {
login() {
axios.post('/api/users/login', {
username: this.username,
password: this.password
})
.then(response => {
alert('登录成功');
this.$router.push('/');
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
Seckill.vue
组件。<template>
<div>
<h1>秒杀活动</h1>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - {{ product.price }}元
<button @click="seckill(product.id)">秒杀</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
products: []
};
},
created() {
this.fetchProducts();
},
methods: {
fetchProducts() {
axios.get('/api/products')
.then(response => {
this.products = response.data;
})
.catch(error => {
console.error(error);
});
},
seckill(productId) {
const userId = 1; // 假设用户ID为1
axios.post(`/api/seckill/${productId}?userId=${userId}`)
.then(response => {
alert(response.data);
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
OrderList.vue
组件。<template>
<div>
<h1>订单列表</h1>
<ul>
<li v-for="order in orders" :key="order.id">
订单ID: {{ order.id }} - 商品ID: {{ order.productId }} - 状态: {{ order.status }}
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
orders: []
};
},
created() {
this.fetchOrders();
},
methods: {
fetchOrders() {
axios.get('/api/orders')
.then(response => {
this.orders = response.data;
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
vue.config.js
文件,设置代理。module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
};
# 启动Spring Boot应用
mvn spring-boot:run
# 启动Vue.js应用
npm run serve
本文详细介绍了如何使用Spring Boot、Redis和Vue.js实现一个高并发的秒杀系统。通过合理的系统架构设计和性能优化,可以有效应对秒杀活动带来的高并发挑战。未来可以进一步优化系统的稳定性和扩展性,如引入消息队列、分布式缓存等。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。