苍穹外卖技术要点1
1. 登录及身份验证(JWT + ThreadLocal + 拦截器)
实现步骤:
引入依赖:
在pom.xml
中引入JWT和Spring Security相关依赖:<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>生成JWT Token:
在用户登录成功后,生成JWT Token并返回给客户端:public String generateToken(User user) {
return Jwts.builder()
.setSubject(user.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}拦截器校验Token:
自定义拦截器,解析并校验Token:public class JwtInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (token != null && validateToken(token)) {
String username = getUsernameFromToken(token);
User user = userService.findByUsername(username);
UserContext.setCurrentUser(user); // 将用户信息存入ThreadLocal
return true;
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
}配置拦截器:
在Spring Boot中注册拦截器:
public class WebConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/api/**");
}
}ThreadLocal存储用户信息:
使用ThreadLocal
存储当前登录用户信息:public class UserContext {
private static final ThreadLocal<User> currentUser = new ThreadLocal<>();
public static void setCurrentUser(User user) {
currentUser.set(user);
}
public static User getCurrentUser() {
return currentUser.get();
}
public static void clear() {
currentUser.remove();
}
}
2. 分布式锁(Redis + Lua脚本)
实现步骤:
引入依赖:
在pom.xml
中引入Redis依赖:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>实现分布式锁:
使用Redis的SETNX
命令实现分布式锁,并通过Lua脚本保证原子性:public boolean tryLock(String key, String value, long expireTime) {
return redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
}
public void unlock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), value);
}
3. 菜品缓存(Redis)
实现步骤:
缓存菜品信息:
在查询菜品信息时,优先从Redis缓存中获取:public Dish getDishById(Long id) {
String key = "dish:" + id;
Dish dish = redisTemplate.opsForValue().get(key);
if (dish == null) {
dish = dishRepository.findById(id).orElse(null);
if (dish != null) {
redisTemplate.opsForValue().set(key, dish, 10, TimeUnit.MINUTES);
}
}
return dish;
}更新缓存:
在菜品信息更新时,同步更新缓存:public void updateDish(Dish dish) {
dishRepository.save(dish);
String key = "dish:" + dish.getId();
redisTemplate.opsForValue().set(key, dish, 10, TimeUnit.MINUTES);
}
4. 长连接(WebSocket)
实现步骤:
引入依赖:
在pom.xml
中引入WebSocket依赖:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>配置WebSocket:
在Spring Boot中配置WebSocket:
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new OrderWebSocketHandler(), "/ws/order").setAllowedOrigins("*");
}
}实现WebSocket处理器:
自定义WebSocket处理器,处理客户端消息:public class OrderWebSocketHandler extends TextWebSocketHandler {
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
// 处理客户端消息
}
}
5. 定时任务(Spring Task)
实现步骤:
启用定时任务:
在Spring Boot启动类上添加@EnableScheduling
注解:
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}实现定时任务:
使用@Scheduled
注解定义定时任务:
public class OrderTask {
// 每5分钟执行一次
public void cancelExpiredOrders() {
// 取消超时订单
}
}
6. 分布式Session(Redis + Hash)
实现步骤:
引入依赖:
在pom.xml
中引入Spring Session和Redis依赖:<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>配置分布式Session:
在application.properties
中配置Session存储为Redis:spring.session.store-type=redis
使用Hash存储用户信息:
在Redis中使用Hash存储用户信息:public void saveUser(User user) {
String key = "user:" + user.getId();
redisTemplate.opsForHash().put(key, "username", user.getUsername());
redisTemplate.opsForHash().put(key, "email", user.getEmail());
}
总结
在Spring Boot中实现这些技术点,主要通过以下步骤:
- 引入相关依赖:如JWT、Redis、WebSocket等。
- 配置Spring Boot:如拦截器、WebSocket、定时任务等。
- 编写业务逻辑:如Token生成、分布式锁、缓存处理等。
- 优化性能:如使用Redis缓存、分布式锁、WebSocket等。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 格 致!
评论