修改签到和更新逻辑
All checks were successful
构建并部署 Spring Boot 应用 / build-and-deploy (push) Successful in 8m53s

This commit is contained in:
2025-10-19 05:41:24 +08:00
parent 74c0908b58
commit c33cbd799d
9 changed files with 564 additions and 570 deletions

View File

@@ -91,7 +91,7 @@ src
系统通过WebSocket实现实时位置同步端点为`/ws/location`
##### 连接建立
客户端通过WebSocket连接到`/ws/location`端点建立连接
客户端通过WebSocket连接到`/ws/location?userId={userId}`端点建立连接需要在查询参数中提供用户ID
##### 消息格式
所有消息都使用JSON格式。
@@ -127,33 +127,40 @@ src
{
"userId": 123,
"name": "张三",
"role": "DELIVERY_PERSON"
},
{
"userId": 456,
"name": "李四",
"role": "ADMIN"
"role": "DELIVERY_PERSON",
"userStatus": true,
"lastUpdateTime": 1634567890000,
"locationData": {
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
}
}
]
}
```
3. **updateLocation(位置更新)** - 服务器向所有已签到用户广播位置更新
3. **userLocationList用户位置列表** - 服务器每30秒发送所有在线用户的位置列表
```json
{
"type": "updateLocation",
"userId": 123,
"userRole": "DELIVERY_PERSON",
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
"type": "userLocationList",
"users": [
{
"userId": 123,
"locationData": {
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
}
}
]
}
```
##### 交互流程
```
用户签到] --> B{签到成功?}
[用户签到] --> B{签到成功?}
B -->|是| C[建立WebSocket连接]
B -->|否| D[签到失败]
C --> E[自动订阅位置更新]
@@ -161,8 +168,7 @@ src
F --> G[接收在线用户列表]
G --> H[开始位置更新循环]
H --> I[发送位置更新]
I --> J[接收位置广播]
J --> H
I --> J[每30秒接收一次位置列表]
K[用户签退] --> L{签退成功?}
L -->|是| M[自动取消订阅并关闭WebSocket连接]
L -->|否| N[签退失败]
@@ -331,6 +337,7 @@ deploy.bat
- `GET /user/info` - 获取用户信息
- `POST /user/logout` - 用户登出
- `POST /user/signin` - 用户签到
- `POST /user/signout` - 用户签退
- `POST /user/register` - 注册为配送员
### 订单相关
@@ -341,7 +348,7 @@ deploy.bat
### 配送员相关
- `GET /delivery-persons` - 获取配送员列表
- `GET /delivery-persons/{id}` - 获取配送员详情
- `PUT /delivery-persons/{id}/location` - 更新配送员位置
- `GET /delivery-persons/{id}/orders` - 获取配送员订单
### 员工管理相关(仅限管理员访问)
- `GET /employees` - 获取员工列表
@@ -388,26 +395,33 @@ deploy.bat
{
"userId": 123,
"name": "张三",
"role": "DELIVERY_PERSON"
},
{
"userId": 456,
"name": "李四",
"role": "ADMIN"
"role": "DELIVERY_PERSON",
"userStatus": true,
"lastUpdateTime": 1634567890000,
"locationData": {
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
}
}
]
}
```
3. **updateLocation(位置更新)** - 服务器向所有已签到用户广播位置更新
3. **userLocationList用户位置列表** - 服务器每30秒发送所有在线用户的位置列表
```json
{
"type": "updateLocation",
"userId": 123,
"userRole": "DELIVERY_PERSON",
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
"type": "userLocationList",
"users": [
{
"userId": 123,
"locationData": {
"latitude": 25.0342,
"longitude": 102.7057,
"timestamp": 1634567890000
}
}
]
}
```
@@ -420,6 +434,7 @@ deploy.bat
- 用户需要先通过REST API签到然后才能建立WebSocket连接并接收位置更新
- 用户签退时服务器会自动取消订阅并关闭WebSocket连接
- 客户端不再需要发送subscribe/unsubscribe消息这些操作由服务器自动处理
- 服务器现在每30秒批量发送一次所有在线用户的位置信息而不是实时发送单个用户位置更新
### WebSocket位置同步增强新增
为了支持管理员和配送员都能接收位置更新信息我们对WebSocket位置同步功能进行了增强

View File

@@ -68,18 +68,6 @@ public class DeliveryPersonController {
response.setCurrentLocation(location);
return ResponseEntity.ok(response);
}
/**
* 更新指定货运人员位置。
* @param id 货运人员ID
* @param locationRequest 包含经纬度
* @return 操作结果
*/
@PutMapping("/{id}/location")
public ResponseEntity<String> updateLocation(@PathVariable Long id, @RequestBody LocationRequest locationRequest) {
deliveryPersonService.updateLocation(id, locationRequest.getLongitude(), locationRequest.getLatitude());
return ResponseEntity.ok("位置更新成功");
}
/**
* 获取货运人员的当前订单。
@@ -112,13 +100,4 @@ public class DeliveryPersonController {
}).collect(Collectors.toList());
return ResponseEntity.ok(orders);
}
/**
* 位置请求体
*/
@Data
public static class LocationRequest {
private Double longitude;
private Double latitude;
}
}

View File

@@ -1,91 +0,0 @@
package com.light.delivery.controller;
import com.light.delivery.service.LocationWebSocketHandler;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 位置同步控制器,提供已签到员工位置信息查询接口。
* 用于获取所有已签到员工的实时位置信息。
*/
@RestController
@RequestMapping("/location-sync")
public class LocationSyncController {
/**
* WebSocket位置处理器依赖注入
*/
@Autowired
private LocationWebSocketHandler locationWebSocketHandler;
/**
* 获取所有已签到员工的实时位置。
* 仅返回有位置信息的员工(最近有更新位置的)。
* @return 员工位置列表
*/
@GetMapping("/employees/locations")
public ResponseEntity<List<EmployeeLocation>> getEmployeeLocations() {
// 获取所有已签到的员工位置信息
Map<Long, LocationWebSocketHandler.UserInfo> userInfos = locationWebSocketHandler.getAllSignedInUsers();
List<EmployeeLocation> locations = userInfos.entrySet().stream()
.map(entry -> {
Long userId = entry.getKey();
LocationWebSocketHandler.UserInfo userInfo = entry.getValue();
EmployeeLocation location = new EmployeeLocation();
location.setEmployeeId(userId);
location.setLatitude(locationWebSocketHandler.getUserLatitude(userId));
location.setLongitude(locationWebSocketHandler.getUserLongitude(userId));
location.setStatus(locationWebSocketHandler.getUserStatus(userId));
location.setRole(userInfo.getRole() != null ? userInfo.getRole() : "");
location.setName(userInfo.getName() != null ? userInfo.getName() : "");
return location;
})
.collect(Collectors.toList());
return ResponseEntity.ok(locations);
}
/**
* 在线员工位置信息DTO用于向前端返回员工位置数据。
*/
@Data
public static class EmployeeLocation {
/**
* 员工ID
*/
private Long employeeId;
/**
* 姓名
*/
private String name;
/**
* 纬度
*/
private Double latitude;
/**
* 经度
*/
private Double longitude;
/**
* 状态
*/
private String status;
/**
* 角色
*/
private String role;
}
}

View File

@@ -180,15 +180,26 @@ public class UserController {
/**
* 用户签到接口。
* @param request HTTP请求对象用于提取认证令牌
* @param initialLocation 初始位置信息
* @return 更新后的用户信息
*/
@PostMapping("/signin")
public ResponseEntity<?> signIn(HttpServletRequest request) {
public ResponseEntity<?> signIn(HttpServletRequest request, @RequestBody LocationWebSocketHandler.LocationData initialLocation) {
String token = extractToken(request);
if (token == null) {
return ResponseEntity.badRequest().body("Authorization token is missing");
}
// 检查位置信息是否为空
if (initialLocation == null) {
return ResponseEntity.badRequest().body("Initial location information is required");
}
// 检查位置信息的必要字段是否为空
if (initialLocation.getLatitude() == null || initialLocation.getLongitude() == null) {
return ResponseEntity.badRequest().body("Latitude and longitude are required in location information");
}
try {
User user = userService.getUserInfo(token);
User updatedUser = userService.signIn(user.getId());
@@ -197,7 +208,7 @@ public class UserController {
// 通知WebSocket处理器用户已签到并自动订阅
try {
LocationWebSocketHandler handler = applicationContext.getBean(LocationWebSocketHandler.class);
handler.userSignedIn(user.getId());
handler.userSignedIn(user.getId(), initialLocation);
} catch (Exception e) {
System.err.println("通知WebSocket签到状态时出错: " + e.getMessage());
}

View File

@@ -20,13 +20,6 @@ public interface DeliveryPersonService {
* @return 配送员对象
*/
DeliveryPerson getDeliveryPersonById(Long id);
/**
* 更新配送员当前位置。
* @param id 配送员ID
* @param longitude 经度
* @param latitude 纬度
*/
void updateLocation(Long id, Double longitude, Double latitude);
/**
* 获取指定配送员的所有订单。
* @param id 配送员ID

View File

@@ -5,14 +5,6 @@ package com.light.delivery.service;
*/
public interface LocationSyncService {
/**
* 处理配送员位置更新
* @param deliveryPersonId 配送员ID
* @param longitude 经度
* @param latitude 纬度
*/
void handleLocationUpdate(Long deliveryPersonId, Double longitude, Double latitude);
/**
* 订阅位置更新
* @param sessionId 会话ID

View File

@@ -34,12 +34,6 @@ public class DeliveryPersonServiceImpl implements DeliveryPersonService {
return person.orElse(null);
}
@Override
public void updateLocation(Long id, Double longitude, Double latitude) {
// 使用 LocationSyncService 更新位置信息到服务器缓存,而不是直接更新数据库
locationSyncService.handleLocationUpdate(id, longitude, latitude);
}
@Override
public List<Order> getCurrentOrders(Long id) {
return orderRepository.findByDeliveryPersonId(id);

View File

@@ -34,19 +34,7 @@ public class LocationSyncServiceImpl implements LocationSyncService {
// 位置过期时间(分钟)
private static final int LOCATION_EXPIRE_MINUTES = 5;
@Override
public void handleLocationUpdate(Long deliveryPersonId, Double longitude, Double latitude) {
try {
// 更新内存缓存中的配送员位置,而不是数据库
deliveryPersonLongitudeMap.put(deliveryPersonId, longitude);
deliveryPersonLatitudeMap.put(deliveryPersonId, latitude);
// 更新最后更新时间
lastUpdateTimes.put(deliveryPersonId, LocalDateTime.now());
} catch (Exception e) {
System.err.println("更新配送员位置时出错: " + e.getMessage());
}
}
@Override
public void subscribe(String sessionId, Long deliveryPersonId) {