引言
随着电子商务的快速发展,校园内的快递业务量呈现爆发式增长。传统的快递管理模式已经难以满足高校师生的需求,各种问题层出不穷:快递积压、取件难、配送慢、信息不透明等。本文将详细介绍一个基于Java全栈技术的校园快递管理与配送系统的设计与实现,旨在提供一个高效、便捷、智能的校园快递解决方案。
系统概述
校园快递管理与配送系统是一个面向高校的综合性快递服务平台,主要服务对象包括学生、教职工、快递员和系统管理员。系统采用Java全栈技术栈开发,包括前端、后端、数据库和移动端应用,实现了快递信息管理、智能派件、路径规划、用户互动等功能。
技术栈选择
前端技术
- Vue.js 3:采用组合式API,提供响应式UI界面
- Element Plus:基于Vue 3的组件库,提供丰富的UI组件
- Axios:处理HTTP请求
- ECharts:数据可视化图表
- 高德地图API:实现校园地图和路径规划
后端技术
- Spring Boot 2.7:简化Spring应用开发
- Spring Security:认证和授权框架
- Spring Data JPA:简化数据库访问
- Spring Cloud:微服务架构支持
- JWT:无状态身份验证
数据库
- MySQL 8.0:关系型数据库
- Redis:缓存和会话管理
- MongoDB:存储非结构化数据,如用户反馈
移动端
- Android原生:Java开发
- iOS原生:Swift开发
- Flutter:跨平台解决方案
DevOps
- Git:版本控制
- Jenkins:CI/CD
- Docker:容器化部署
- Kubernetes:容器编排
系统架构
系统采用前后端分离的微服务架构,主要分为以下几个部分:
- 用户服务:负责用户注册、登录、认证和授权
- 快递服务:管理快递信息,包括录入、查询、更新和删除
- 配送服务:负责快递派送、路径规划和配送状态跟踪
- 通知服务:处理系统消息推送,如短信、邮件和应用内通知
- 数据分析服务:收集和分析系统数据,生成报表和可视化图表
- API网关:统一接口管理,处理跨域请求和负载均衡
数据库设计
系统数据库主要包含以下核心表:
- 用户表(user):存储用户基本信息
- 快递表(express):存储快递基本信息
- 快递柜表(locker):存储快递柜信息
- 配送任务表(delivery_task):存储配送任务信息
- 配送路径表(delivery_route):存储配送路径信息
- 通知表(notification):存储系统通知信息
- 反馈表(feedback):存储用户反馈信息
用户表(user)设计
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`user_type` tinyint NOT NULL COMMENT '用户类型:1-学生,2-教职工,3-快递员,4-管理员',
`student_id` varchar(20) DEFAULT NULL COMMENT '学号',
`department` varchar(50) DEFAULT NULL COMMENT '院系/部门',
`dormitory` varchar(50) DEFAULT NULL COMMENT '宿舍号',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-禁用,1-启用',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
UNIQUE KEY `uk_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
快递表(express)设计
CREATE TABLE `express` (
`id` bigint NOT NULL AUTO_INCREMENT,
`express_code` varchar(50) NOT NULL COMMENT '快递单号',
`express_company` varchar(50) NOT NULL COMMENT '快递公司',
`sender_name` varchar(50) NOT NULL COMMENT '寄件人姓名',
`sender_phone` varchar(20) NOT NULL COMMENT '寄件人电话',
`receiver_id` bigint NOT NULL COMMENT '收件人ID',
`receiver_name` varchar(50) NOT NULL COMMENT '收件人姓名',
`receiver_phone` varchar(20) NOT NULL COMMENT '收件人电话',
`receiver_address` varchar(255) NOT NULL COMMENT '收件地址',
`express_type` tinyint NOT NULL COMMENT '快递类型:1-小件,2-中件,3-大件',
`express_status` tinyint NOT NULL COMMENT '快递状态:1-待入库,2-已入库,3-待配送,4-配送中,5-已送达,6-已取件,7-异常',
`locker_id` bigint DEFAULT NULL COMMENT '快递柜ID',
`locker_cell_no` varchar(20) DEFAULT NULL COMMENT '快递柜格口号',
`arrival_time` datetime DEFAULT NULL COMMENT '到达时间',
`delivery_time` datetime DEFAULT NULL COMMENT '送达时间',
`pickup_time` datetime DEFAULT NULL COMMENT '取件时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_express_code` (`express_code`),
KEY `idx_receiver_id` (`receiver_id`),
KEY `idx_express_status` (`express_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快递表';
核心功能实现
1. 用户认证与授权
采用Spring Security + JWT实现无状态认证,代码示例:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
2. 快递信息管理
快递服务实现了快递信息的CRUD操作,包括录入、查询、更新和删除功能。
@Service
public class ExpressServiceImpl implements ExpressService {
@Autowired
private ExpressRepository expressRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private NotificationService notificationService;
@Override
public ExpressDTO createExpress(ExpressCreateRequest request) {
// 验证收件人是否存在
User receiver = userRepository.findById(request.getReceiverId())
.orElseThrow(() -> new ResourceNotFoundException("User", "id", request.getReceiverId()));
// 创建快递实体
Express express = new Express();
express.setExpressCode(request.getExpressCode());
express.setExpressCompany(request.getExpressCompany());
express.setSenderName(request.getSenderName());
express.setSenderPhone(request.getSenderPhone());
express.setReceiverId(receiver.getId());
express.setReceiverName(receiver.getRealName());
express.setReceiverPhone(receiver.getPhone());
express.setReceiverAddress(request.getReceiverAddress());
express.setExpressType(request.getExpressType());
express.setExpressStatus(ExpressStatus.WAITING_STORAGE.getCode());
express.setRemark(request.getRemark());
// 保存快递信息
Express savedExpress = expressRepository.save(express);
// 发送通知给收件人
notificationService.sendExpressArrivalNotification(savedExpress);
return ExpressMapper.INSTANCE.toDTO(savedExpress);
}
@Override
public Page<ExpressDTO> getExpressList(ExpressQueryRequest request, Pageable pageable) {
Specification<Express> spec = (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.hasText(request.getExpressCode())) {
predicates.add(criteriaBuilder.like(root.get("expressCode"), "%" + request.getExpressCode() + "%"));
}
if (StringUtils.hasText(request.getExpressCompany())) {
predicates.add(criteriaBuilder.equal(root.get("expressCompany"), request.getExpressCompany()));
}
if (request.getReceiverId() != null) {
predicates.add(criteriaBuilder.equal(root.get("receiverId"), request.getReceiverId()));
}
if (request.getExpressStatus() != null) {
predicates.add(criteriaBuilder.equal(root.get("expressStatus"), request.getExpressStatus()));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
Page<Express> expressPage = expressRepository.findAll(spec, pageable);
return expressPage.map(ExpressMapper.INSTANCE::toDTO);
}
// 其他方法实现...
}
3. 智能配送系统
配送服务实现了智能派件、路径规划和配送状态跟踪功能。
@Service
public class DeliveryServiceImpl implements DeliveryService {
@Autowired
private DeliveryTaskRepository deliveryTaskRepository;
@Autowired
private ExpressRepository expressRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private RouteOptimizationService routeOptimizationService;
@Override
@Transactional
public DeliveryTaskDTO createDeliveryTask(DeliveryTaskCreateRequest request) {
// 验证快递员是否存在
User courier = userRepository.findById(request.getCourierId())
.orElseThrow(() -> new ResourceNotFoundException("User", "id", request.getCourierId()));
// 验证用户类型是否为快递员
if (courier.getUserType() != UserType.COURIER.getCode()) {
throw new BadRequestException("User is not a courier");
}
// 创建配送任务
DeliveryTask task = new DeliveryTask();
task.setCourierId(courier.getId());
task.setTaskDate(LocalDate.now());
task.setTaskStatus(DeliveryTaskStatus.CREATED.getCode());
// 保存配送任务
DeliveryTask savedTask = deliveryTaskRepository.save(task);
// 分配快递到配送任务
List<Express> expressList = expressRepository.findAllById(request.getExpressIds());
for (Express express : expressList) {
express.setExpressStatus(ExpressStatus.DELIVERING.getCode());
express.setDeliveryTaskId(savedTask.getId());
}
expressRepository.saveAll(expressList);
// 生成最优配送路径
List<DeliveryPoint> deliveryPoints = expressList.stream()
.map(this::convertToDeliveryPoint)
.collect(Collectors.toList());
List<DeliveryPoint> optimizedRoute = routeOptimizationService.optimizeRoute(deliveryPoints);
// 保存配送路径
saveDeliveryRoute(savedTask.getId(), optimizedRoute);
return DeliveryTaskMapper.INSTANCE.toDTO(savedTask);
}
// 其他方法实现...
}
4. 移动端应用
为了方便用户使用,系统提供了移动端应用,包括Android和iOS版本。以下是Android版本的部分代码示例:
public class ExpressListActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ExpressAdapter adapter;
private SwipeRefreshLayout swipeRefreshLayout;
private ExpressViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_express_list);
// 初始化视图
recyclerView = findViewById(R.id.recycler_view);
swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout);
// 设置布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// 初始化适配器
adapter = new ExpressAdapter(new ArrayList<>());
recyclerView.setAdapter(adapter);
// 初始化ViewModel
viewModel = new ViewModelProvider(this).get(ExpressViewModel.class);
// 观察数据变化
viewModel.getExpressList().observe(this, expressItems -> {
adapter.updateData(expressItems);
swipeRefreshLayout.setRefreshing(false);
});
// 设置下拉刷新监听器
swipeRefreshLayout.setOnRefreshListener(() -> {
viewModel.refreshExpressList();
});
// 加载数据
viewModel.loadExpressList();
}
}
系统部署
系统采用Docker容器化部署,使用Kubernetes进行容器编排,实现高可用和弹性伸缩。
# docker-compose.yml
version: '3'
services:
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=campus_express
volumes:
- mysql-data:/var/lib/mysql
networks:
- app-network
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-network
api-gateway:
image: campus-express/api-gateway:latest
ports:
- "8080:8080"
depends_on:
- user-service
- express-service
- delivery-service
- notification-service
networks:
- app-network
user-service:
image: campus-express/user-service:latest
depends_on:
- mysql
- redis
networks:
- app-network
express-service:
image: campus-express/express-service:latest
depends_on:
- mysql
networks:
- app-network
delivery-service:
image: campus-express/delivery-service:latest
depends_on:
- mysql
networks:
- app-network
notification-service:
image: campus-express/notification-service:latest
depends_on:
- mysql
- redis
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
mysql-data:
redis-data:
系统性能优化
为了提高系统性能,采取了以下优化措施:
-
数据库优化:
- 合理设计索引
- 使用读写分离
- 实现分库分表
- 优化SQL语句
-
缓存优化:
- 使用Redis缓存热点数据
- 实现多级缓存策略
- 合理设置缓存过期时间
-
JVM优化:
- 调整堆内存大小
- 选择合适的垃圾收集器
- 优化JVM参数
-
前端优化:
- 使用懒加载
- 压缩静态资源
- 使用CDN加速
- 实现前端缓存
系统安全性
系统安全性是校园快递管理系统的重要考虑因素,主要采取了以下安全措施:
-
认证与授权:
- 基于JWT的无状态认证
- 细粒度的权限控制
- 防止CSRF攻击
-
数据安全:
- 敏感数据加密存储
- 传输数据HTTPS加密
- 防止SQL注入攻击
-
接口安全:
- 接口限流
- 防止重放攻击
- 参数验证
-
日志审计:
- 记录用户操作日志
- 系统异常监控
- 安全事件告警
系统测试
系统测试采用多层次测试策略,包括单元测试、集成测试、性能测试和安全测试。
@SpringBootTest
public class ExpressServiceTest {
@Autowired
private ExpressService expressService;
@MockBean
private ExpressRepository expressRepository;
@MockBean
private UserRepository userRepository;
@MockBean
private NotificationService notificationService;
@Test
public void testCreateExpress() {
// 准备测试数据
User receiver = new User();
receiver.setId(1L);
receiver.setRealName("张三");
receiver.setPhone("13800138000");
Express express = new Express();
express.setId(1L);
express.setExpressCode("SF1234567890");
express.setExpressCompany("顺丰速运");
express.setReceiverId(1L);
express.setReceiverName("张三");
express.setReceiverPhone("13800138000");
ExpressCreateRequest request = new ExpressCreateRequest();
request.setExpressCode("SF1234567890");
request.setExpressCompany("顺丰速运");
request.setSenderName("李四");
request.setSenderPhone("13900139000");
request.setReceiverId(1L);
request.setReceiverAddress("第一宿舍楼101");
request.setExpressType(1);
// 设置Mock行为
when(userRepository.findById(1L)).thenReturn(Optional.of(receiver));
when(expressRepository.save(any(Express.class))).thenReturn(express);
// 执行测试
ExpressDTO result = expressService.createExpress(request);
// 验证结果
assertNotNull(result);
assertEquals("SF1234567890", result.getExpressCode());
assertEquals("顺丰速运", result.getExpressCompany());
assertEquals(1L, result.getReceiverId().longValue());
// 验证交互
verify(userRepository).findById(1L);
verify(expressRepository).save(any(Express.class));
verify(notificationService).sendExpressArrivalNotification(any(Express.class));
}
}
未来展望
校园快递管理与配送系统还有很大的发展空间,未来可以考虑以下几个方向:
-
引入人工智能:
- 智能客服
- 配送路径优化
- 需求预测
-
物联网集成:
- 智能快递柜
- 无人配送车
- 实时定位追踪
-
大数据分析:
- 用户行为分析
- 配送效率优化
- 智能决策支持
-
生态系统扩展:
- 校园电商集成
- 社交功能
- 校园服务平台
总结
本文详细介绍了基于Java全栈技术的校园快递管理与配送系统的设计与实现。该系统采用前后端分离的微服务架构,实现了快递信息管理、智能派件、路径规划、用户互动等功能,为高校师生提供了高效、便捷、智能的校园快递解决方案。
通过该系统的实施,可以有效解决校园快递积压、取件难、配送慢、信息不透明等问题,提高校园快递服务质量,改善师生用户体验。
源代码
Directory Content Summary
Source Directory: ./campus-express-system
Directory Structure
campus-express-system/
express-service/
pom.xml
src/
main/
java/
com/
campus/
express/
ExpressServiceApplication.java
controller/
DeliveryAreaController.java
DeliveryController.java
DeliveryRouteController.java
NotificationController.java
NotificationTemplateController.java
dto/
ApiResponse.java
CabinetCellDTO.java
CabinetCreateRequest.java
CabinetDTO.java
CabinetUpdateRequest.java
DeliveryAreaCreateRequest.java
DeliveryAreaDTO.java
DeliveryAreaUpdateRequest.java
DeliveryCreateRequest.java
DeliveryDTO.java
DeliveryRouteCreateRequest.java
DeliveryRouteDTO.java
DeliveryRouteUpdateRequest.java
DeliveryUpdateRequest.java
ExpressCreateRequest.java
ExpressDTO.java
ExpressTrackingDTO.java
ExpressUpdateRequest.java
NotificationCreateRequest.java
NotificationDTO.java
NotificationSendRequest.java
NotificationTemplateCreateRequest.java
NotificationTemplateDTO.java
NotificationTemplateUpdateRequest.java
NotificationUpdateRequest.java
exception/
BusinessException.java
ErrorResponse.java
GlobalExceptionHandler.java
ResourceNotFoundException.java
model/
Cabinet.java
CabinetCell.java
Delivery.java
DeliveryArea.java
DeliveryRoute.java
Express.java
ExpressTracking.java
Notification.java
NotificationTemplate.java
repository/
CabinetCellRepository.java
CabinetRepository.java
DeliveryAreaRepository.java
DeliveryRepository.java
DeliveryRouteRepository.java
ExpressRepository.java
ExpressTrackingRepository.java
NotificationRepository.java
NotificationTemplateRepository.java
service/
CabinetCellService.java
CabinetService.java
DeliveryAreaService.java
DeliveryRouteService.java
DeliveryService.java
ExpressService.java
ExpressTrackingService.java
NotificationSender.java
NotificationService.java
NotificationTemplateService.java
impl/
CabinetCellServiceImpl.java
CabinetServiceImpl.java
DeliveryAreaServiceImpl.java
DeliveryRouteServiceImpl.java
DeliveryServiceImpl.java
ExpressServiceImpl.java
ExpressTrackingServiceImpl.java
InAppNotificationSender.java
NotificationServiceImpl.java
NotificationTemplateServiceImpl.java
util/
NotificationUtils.java
resources/
application.yml
db/
data.sql
schema.sql
express-ui/
package.json
public/
static/
src/
App.vue
main.js
api/
notification.js
assets/
components/
Notification/
index.vue
NotificationList.vue
NotificationManager.js
layout/
index.vue
components/
AppMain.vue
Navbar.vue
Sidebar/
index.vue
Item.vue
Link.vue
Logo.vue
SidebarItem.vue
TagsView/
index.vue
ScrollPane.vue
plugins/
notification.js
router/
index.js
store/
utils/
notification.js
views/
delivery/
express/
login/
notification/
dashboard.vue
detail.vue
history.vue
list.vue
my-notifications.vue
send.vue
settings.vue
statistics.vue
template-editor.vue
template.vue
system/
user-service/
pom.xml
src/
main/
java/
com/
campus/
express/
user/
UserServiceApplication.java
config/
CorsConfig.java
DataInitializer.java
JwtAuthenticationEntryPoint.java
JwtAuthenticationFilter.java
SecurityConfig.java
controller/
AuthController.java
RoleController.java
UserController.java
dto/
ApiResponse.java
JwtResponse.java
LoginRequest.java
PasswordChangeRequest.java
SignupRequest.java
UserDTO.java
exception/
BadRequestException.java
GlobalExceptionHandler.java
ResourceNotFoundException.java
model/
Role.java
User.java
repository/
RoleRepository.java
UserRepository.java
service/
SecurityService.java
UserDetailsServiceImpl.java
UserService.java
UserServiceImpl.java
util/
JwtUtils.java
resources/
application.yml
target/
classes/
application.yml
com/
campus/
express/
user/
config/
controller/
dto/
exception/
model/
repository/
service/
util/
generated-sources/
annotations/
generated-test-sources/
test-annotations/
test-classes/
File Contents
express-service\pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/>
</parent>
<groupId>com.campus.express</groupId>
<artifactId>express-service</artifactId>
<version>1.0.0</version>
<name>express-service</name>
<description>Express Service for Campus Express Management System</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<jjwt.version>0.11.5</jjwt.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
express-service\src\main\java\com\campus\express\ExpressServiceApplication.java
package com.campus.express;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 快递服务应用程序入口
*/
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ExpressServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ExpressServiceApplication.class, args);
}
}
express-service\src\main\java\com\campus\express\controller\DeliveryAreaController.java
package com.campus.express.controller;
import com.campus.express.dto.DeliveryAreaCreateRequest;
import com.campus.express.dto.DeliveryAreaDTO;
import com.campus.express.dto.DeliveryAreaUpdateRequest;
import com.campus.express.service.DeliveryAreaService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 配送区域控制器
*/
@RestController
@RequestMapping("/api/delivery-areas")
@RequiredArgsConstructor
@Slf4j
public class DeliveryAreaController {
private final DeliveryAreaService deliveryAreaService;
/**
* 创建配送区域
*
* @param request 创建配送区域请求
* @return 配送区域DTO
*/
@PostMapping
public ResponseEntity<DeliveryAreaDTO> createDeliveryArea(@Valid @RequestBody DeliveryAreaCreateRequest request) {
log.info("REST request to create delivery area: {}", request);
DeliveryAreaDTO result = deliveryAreaService.createDeliveryArea(request);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}
/**
* 根据ID查询配送区域
*
* @param id 配送区域ID
* @return 配送区域DTO
*/
@GetMapping("/{id}")
public ResponseEntity<DeliveryAreaDTO> getDeliveryAreaById(@PathVariable Long id) {
log.info("REST request to get delivery area by ID: {}", id);
DeliveryAreaDTO result = deliveryAreaService.getDeliveryAreaById(id);
return ResponseEntity.ok(result);
}
/**
* 根据区域代码查询配送区域
*
* @param areaCode 区域代码
* @return 配送区域DTO
*/
@GetMapping("/area-code/{areaCode}")
public ResponseEntity<DeliveryAreaDTO> getDeliveryAreaByAreaCode(@PathVariable String areaCode) {
log.info("REST request to get delivery area by area code: {}", areaCode);
DeliveryAreaDTO result = deliveryAreaService.getDeliveryAreaByAreaCode(areaCode);
return ResponseEntity.ok(result);
}
/**
* 更新配送区域
*
* @param id 配送区域ID
* @param request 更新配送区域请求
* @return 更新后的配送区域DTO
*/
@PutMapping("/{id}")
public ResponseEntity<DeliveryAreaDTO> updateDeliveryArea(
@PathVariable Long id,
@Valid @RequestBody DeliveryAreaUpdateRequest request) {
log.info("REST request to update delivery area with ID: {}, request: {}", id, request);
DeliveryAreaDTO result = deliveryAreaService.updateDeliveryArea(id, request);
return ResponseEntity.ok(result);
}
/**
* 删除配送区域
*
* @param id 配送区域ID
* @return 无内容响应
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteDeliveryArea(@PathVariable Long id) {
log.info("REST request to delete delivery area with ID: {}", id);
deliveryAreaService.deleteDeliveryArea(id);
return ResponseEntity.noContent().build();
}
/**
* 分页查询配送区域列表
*
* @param pageable 分页参数
* @return 配送区域DTO分页列表
*/
@GetMapping
public ResponseEntity<Page<DeliveryAreaDTO>> getDeliveryAreas(Pageable pageable) {
log.info("REST request to get delivery areas with pagination: {}", pageable);
Page<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreas(pageable);
return ResponseEntity.ok(result);
}
/**
* 根据名称关键字分页查询配送区域列表
*
* @param name 名称关键字
* @param pageable 分页参数
* @return 配送区域DTO分页列表
*/
@GetMapping("/search")
public ResponseEntity<Page<DeliveryAreaDTO>> getDeliveryAreasByName(
@RequestParam String name,
Pageable pageable) {
log.info("REST request to get delivery areas by name: {} with pagination: {}", name, pageable);
Page<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreasByName(name, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据状态分页查询配送区域列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送区域DTO分页列表
*/
@GetMapping("/status/{status}")
public ResponseEntity<Page<DeliveryAreaDTO>> getDeliveryAreasByStatus(
@PathVariable Integer status,
Pageable pageable) {
log.info("REST request to get delivery areas by status: {} with pagination: {}", status, pageable);
Page<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreasByStatus(status, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据级别查询配送区域列表
*
* @param level 级别
* @return 配送区域DTO列表
*/
@GetMapping("/level/{level}")
public ResponseEntity<List<DeliveryAreaDTO>> getDeliveryAreasByLevel(@PathVariable Integer level) {
log.info("REST request to get delivery areas by level: {}", level);
List<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreasByLevel(level);
return ResponseEntity.ok(result);
}
/**
* 根据父区域ID查询子区域列表
*
* @param parentId 父区域ID
* @return 配送区域DTO列表
*/
@GetMapping("/parent/{parentId}")
public ResponseEntity<List<DeliveryAreaDTO>> getDeliveryAreasByParentId(@PathVariable Long parentId) {
log.info("REST request to get delivery areas by parent ID: {}", parentId);
List<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreasByParentId(parentId);
return ResponseEntity.ok(result);
}
/**
* 获取区域树
*
* @return 区域树
*/
@GetMapping("/tree")
public ResponseEntity<List<DeliveryAreaDTO>> getDeliveryAreaTree() {
log.info("REST request to get delivery area tree");
List<DeliveryAreaDTO> result = deliveryAreaService.getDeliveryAreaTree();
return ResponseEntity.ok(result);
}
/**
* 更新配送区域状态
*
* @param id 配送区域ID
* @param status 状态
* @return 更新后的配送区域DTO
*/
@PutMapping("/{id}/status/{status}")
public ResponseEntity<DeliveryAreaDTO> updateAreaStatus(
@PathVariable Long id,
@PathVariable Integer status) {
log.info("REST request to update delivery area status with ID: {}, status: {}", id, status);
DeliveryAreaDTO result = deliveryAreaService.updateAreaStatus(id, status);
return ResponseEntity.ok(result);
}
/**
* 统计配送区域数量
*
* @return 配送区域数量
*/
@GetMapping("/count")
public ResponseEntity<Map<String, Long>> countDeliveryAreas() {
log.info("REST request to count delivery areas");
Map<String, Long> result = deliveryAreaService.countDeliveryAreas(new HashMap<>());
return ResponseEntity.ok(result);
}
}
express-service\src\main\java\com\campus\express\controller\DeliveryController.java
package com.campus.express.controller;
import com.campus.express.dto.DeliveryCreateRequest;
import com.campus.express.dto.DeliveryDTO;
import com.campus.express.dto.DeliveryUpdateRequest;
import com.campus.express.service.DeliveryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* 配送任务控制器
*/
@RestController
@RequestMapping("/api/deliveries")
@RequiredArgsConstructor
@Slf4j
public class DeliveryController {
private final DeliveryService deliveryService;
/**
* 创建配送任务
*
* @param request 创建配送任务请求
* @return 配送任务DTO
*/
@PostMapping
public ResponseEntity<DeliveryDTO> createDelivery(@Valid @RequestBody DeliveryCreateRequest request) {
log.info("REST request to create delivery task: {}", request);
DeliveryDTO result = deliveryService.createDelivery(request);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}
/**
* 根据ID查询配送任务
*
* @param id 配送任务ID
* @return 配送任务DTO
*/
@GetMapping("/{id}")
public ResponseEntity<DeliveryDTO> getDeliveryById(@PathVariable Long id) {
log.info("REST request to get delivery task by ID: {}", id);
DeliveryDTO result = deliveryService.getDeliveryById(id);
return ResponseEntity.ok(result);
}
/**
* 根据快递ID查询配送任务
*
* @param expressId 快递ID
* @return 配送任务DTO
*/
@GetMapping("/express/{expressId}")
public ResponseEntity<DeliveryDTO> getDeliveryByExpressId(@PathVariable Long expressId) {
log.info("REST request to get delivery task by express ID: {}", expressId);
DeliveryDTO result = deliveryService.getDeliveryByExpressId(expressId);
return ResponseEntity.ok(result);
}
/**
* 更新配送任务
*
* @param id 配送任务ID
* @param request 更新配送任务请求
* @return 更新后的配送任务DTO
*/
@PutMapping("/{id}")
public ResponseEntity<DeliveryDTO> updateDelivery(
@PathVariable Long id,
@Valid @RequestBody DeliveryUpdateRequest request) {
log.info("REST request to update delivery task with ID: {}, request: {}", id, request);
DeliveryDTO result = deliveryService.updateDelivery(id, request);
return ResponseEntity.ok(result);
}
/**
* 删除配送任务
*
* @param id 配送任务ID
* @return 无内容响应
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteDelivery(@PathVariable Long id) {
log.info("REST request to delete delivery task with ID: {}", id);
deliveryService.deleteDelivery(id);
return ResponseEntity.noContent().build();
}
/**
* 分页查询配送任务列表
*
* @param pageable 分页参数
* @return 配送任务DTO分页列表
*/
@GetMapping
public ResponseEntity<Page<DeliveryDTO>> getDeliveries(Pageable pageable) {
log.info("REST request to get delivery tasks with pagination: {}", pageable);
Page<DeliveryDTO> result = deliveryService.getDeliveries(pageable);
return ResponseEntity.ok(result);
}
/**
* 根据状态分页查询配送任务列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送任务DTO分页列表
*/
@GetMapping("/status/{status}")
public ResponseEntity<Page<DeliveryDTO>> getDeliveriesByStatus(
@PathVariable Integer status,
Pageable pageable) {
log.info("REST request to get delivery tasks by status: {} with pagination: {}", status, pageable);
Page<DeliveryDTO> result = deliveryService.getDeliveriesByStatus(status, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据配送员ID分页查询配送任务列表
*
* @param courierId 配送员ID
* @param pageable 分页参数
* @return 配送任务DTO分页列表
*/
@GetMapping("/courier/{courierId}")
public ResponseEntity<Page<DeliveryDTO>> getDeliveriesByCourierId(
@PathVariable Long courierId,
Pageable pageable) {
log.info("REST request to get delivery tasks by courier ID: {} with pagination: {}", courierId, pageable);
Page<DeliveryDTO> result = deliveryService.getDeliveriesByCourierId(courierId, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据配送区域分页查询配送任务列表
*
* @param area 配送区域
* @param pageable 分页参数
* @return 配送任务DTO分页列表
*/
@GetMapping("/area")
public ResponseEntity<Page<DeliveryDTO>> getDeliveriesByArea(
@RequestParam String area,
Pageable pageable) {
log.info("REST request to get delivery tasks by area: {} with pagination: {}", area, pageable);
Page<DeliveryDTO> result = deliveryService.getDeliveriesByArea(area, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据创建时间范围分页查询配送任务列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 配送任务DTO分页列表
*/
@GetMapping("/created-time")
public ResponseEntity<Page<DeliveryDTO>> getDeliveriesByCreatedTimeBetween(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime,
Pageable pageable) {
log.info("REST request to get delivery tasks by created time between: {} and {} with pagination: {}", startTime, endTime, pageable);
Page<DeliveryDTO> result = deliveryService.getDeliveriesByCreatedTimeBetween(startTime, endTime, pageable);
return ResponseEntity.ok(result);
}
/**
* 分配配送员
*
* @param id 配送任务ID
* @param courierId 配送员ID
* @param courierName 配送员姓名
* @param courierPhone 配送员电话
* @return 更新后的配送任务DTO
*/
@PutMapping("/{id}/assign-courier")
public ResponseEntity<DeliveryDTO> assignCourier(
@PathVariable Long id,
@RequestParam Long courierId,
@RequestParam String courierName,
@RequestParam String courierPhone) {
log.info("REST request to assign courier to delivery task with ID: {}, courier ID: {}", id, courierId);
DeliveryDTO result = deliveryService.assignCourier(id, courierId, courierName, courierPhone);
return ResponseEntity.ok(result);
}
/**
* 更新配送任务状态
*
* @param id 配送任务ID
* @param status 状态
* @return 更新后的配送任务DTO
*/
@PutMapping("/{id}/status/{status}")
public ResponseEntity<DeliveryDTO> updateDeliveryStatus(
@PathVariable Long id,
@PathVariable Integer status) {
log.info("REST request to update delivery task status with ID: {}, status: {}", id, status);
DeliveryDTO result = deliveryService.updateDeliveryStatus(id, status);
return ResponseEntity.ok(result);
}
/**
* 取消配送任务
*
* @param id 配送任务ID
* @param reason 取消原因
* @return 更新后的配送任务DTO
*/
@PutMapping("/{id}/cancel")
public ResponseEntity<DeliveryDTO> cancelDelivery(
@PathVariable Long id,
@RequestParam String reason) {
log.info("REST request to cancel delivery task with ID: {}, reason: {}", id, reason);
DeliveryDTO result = deliveryService.cancelDelivery(id, reason);
return ResponseEntity.ok(result);
}
/**
* 生成配送验证码
*
* @return 配送验证码
*/
@GetMapping("/generate-code")
public ResponseEntity<Map<String, String>> generateDeliveryCode() {
log.info("REST request to generate delivery code");
String code = deliveryService.generateDeliveryCode();
Map<String, String> result = new HashMap<>();
result.put("code", code);
return ResponseEntity.ok(result);
}
/**
* 验证配送验证码
*
* @param id 配送任务ID
* @param code 验证码
* @return 是否验证成功
*/
@GetMapping("/{id}/verify-code")
public ResponseEntity<Map<String, Boolean>> verifyDeliveryCode(
@PathVariable Long id,
@RequestParam String code) {
log.info("REST request to verify delivery code for delivery task with ID: {}", id);
boolean verified = deliveryService.verifyDeliveryCode(id, code);
Map<String, Boolean> result = new HashMap<>();
result.put("verified", verified);
return ResponseEntity.ok(result);
}
/**
* 统计配送任务数量
*
* @return 配送任务数量
*/
@GetMapping("/count")
public ResponseEntity<Map<String, Long>> countDeliveries() {
log.info("REST request to count delivery tasks");
Map<String, Long> result = deliveryService.countDeliveries(new HashMap<>());
return ResponseEntity.ok(result);
}
}
express-service\src\main\java\com\campus\express\controller\DeliveryRouteController.java
package com.campus.express.controller;
import com.campus.express.dto.DeliveryRouteCreateRequest;
import com.campus.express.dto.DeliveryRouteDTO;
import com.campus.express.dto.DeliveryRouteUpdateRequest;
import com.campus.express.service.DeliveryRouteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 配送路线控制器
*/
@RestController
@RequestMapping("/api/delivery-routes")
@RequiredArgsConstructor
@Slf4j
public class DeliveryRouteController {
private final DeliveryRouteService deliveryRouteService;
/**
* 创建配送路线
*
* @param request 创建配送路线请求
* @return 配送路线DTO
*/
@PostMapping
public ResponseEntity<DeliveryRouteDTO> createDeliveryRoute(@Valid @RequestBody DeliveryRouteCreateRequest request) {
log.info("REST request to create delivery route: {}", request);
DeliveryRouteDTO result = deliveryRouteService.createDeliveryRoute(request);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}
/**
* 根据ID查询配送路线
*
* @param id 配送路线ID
* @return 配送路线DTO
*/
@GetMapping("/{id}")
public ResponseEntity<DeliveryRouteDTO> getDeliveryRouteById(@PathVariable Long id) {
log.info("REST request to get delivery route by ID: {}", id);
DeliveryRouteDTO result = deliveryRouteService.getDeliveryRouteById(id);
return ResponseEntity.ok(result);
}
/**
* 根据路线编号查询配送路线
*
* @param routeNumber 路线编号
* @return 配送路线DTO
*/
@GetMapping("/route-number/{routeNumber}")
public ResponseEntity<DeliveryRouteDTO> getDeliveryRouteByRouteNumber(@PathVariable String routeNumber) {
log.info("REST request to get delivery route by route number: {}", routeNumber);
DeliveryRouteDTO result = deliveryRouteService.getDeliveryRouteByRouteNumber(routeNumber);
return ResponseEntity.ok(result);
}
/**
* 更新配送路线
*
* @param id 配送路线ID
* @param request 更新配送路线请求
* @return 更新后的配送路线DTO
*/
@PutMapping("/{id}")
public ResponseEntity<DeliveryRouteDTO> updateDeliveryRoute(
@PathVariable Long id,
@Valid @RequestBody DeliveryRouteUpdateRequest request) {
log.info("REST request to update delivery route with ID: {}, request: {}", id, request);
DeliveryRouteDTO result = deliveryRouteService.updateDeliveryRoute(id, request);
return ResponseEntity.ok(result);
}
/**
* 删除配送路线
*
* @param id 配送路线ID
* @return 无内容响应
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteDeliveryRoute(@PathVariable Long id) {
log.info("REST request to delete delivery route with ID: {}", id);
deliveryRouteService.deleteDeliveryRoute(id);
return ResponseEntity.noContent().build();
}
/**
* 分页查询配送路线列表
*
* @param pageable 分页参数
* @return 配送路线DTO分页列表
*/
@GetMapping
public ResponseEntity<Page<DeliveryRouteDTO>> getDeliveryRoutes(Pageable pageable) {
log.info("REST request to get delivery routes with pagination: {}", pageable);
Page<DeliveryRouteDTO> result = deliveryRouteService.getDeliveryRoutes(pageable);
return ResponseEntity.ok(result);
}
/**
* 根据名称关键字分页查询配送路线列表
*
* @param name 名称关键字
* @param pageable 分页参数
* @return 配送路线DTO分页列表
*/
@GetMapping("/search")
public ResponseEntity<Page<DeliveryRouteDTO>> getDeliveryRoutesByName(
@RequestParam String name,
Pageable pageable) {
log.info("REST request to get delivery routes by name: {} with pagination: {}", name, pageable);
Page<DeliveryRouteDTO> result = deliveryRouteService.getDeliveryRoutesByName(name, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据状态分页查询配送路线列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送路线DTO分页列表
*/
@GetMapping("/status/{status}")
public ResponseEntity<Page<DeliveryRouteDTO>> getDeliveryRoutesByStatus(
@PathVariable Integer status,
Pageable pageable) {
log.info("REST request to get delivery routes by status: {} with pagination: {}", status, pageable);
Page<DeliveryRouteDTO> result = deliveryRouteService.getDeliveryRoutesByStatus(status, pageable);
return ResponseEntity.ok(result);
}
/**
* 根据区域查询配送路线列表
*
* @param area 区域
* @return 配送路线DTO列表
*/
@GetMapping("/area/{area}")
public ResponseEntity<List<DeliveryRouteDTO>> getDeliveryRoutesByArea(@PathVariable String area) {
log.info("REST request to get delivery routes by area: {}", area);
List<DeliveryRouteDTO> result = deliveryRouteService.getDeliveryRoutesByArea(area);
return ResponseEntity.ok(result);
}
/**
* 根据配送员ID查询配送路线列表
*
* @param courierId 配送员ID
* @return 配送路线DTO列表
*/
@GetMapping("/courier/{courierId}")
public ResponseEntity<List<DeliveryRouteDTO>> getDeliveryRoutesByCourierId(@PathVariable Long courierId) {
log.info("REST request to get delivery routes by courier ID: {}", courierId);
List<DeliveryRouteDTO> result = deliveryRouteService.getDeliveryRoutesByCourierId(courierId);
return ResponseEntity.ok(result);
}
/**
* 分配配送员
*
* @param id 配送路线ID
* @param courierId 配送员ID
* @param courierName 配送员姓名
* @return 更新后的配送路线DTO
*/
@PutMapping("/{id}/assign-courier")
public ResponseEntity<DeliveryRouteDTO> assignCourier(
@PathVariable Long id,
@RequestParam Long courierId,
@RequestParam String courierName) {
log.info("REST request to assign courier to delivery route with ID: {}, courier ID: {}", id, courierId);
DeliveryRouteDTO result = deliveryRouteService.assignCourier(id, courierId, courierName);
return ResponseEntity.ok(result);
}
/**
* 更新配送路线状态
*
* @param id 配送路线ID
* @param status 状态
* @return 更新后的配送路线DTO
*/
@PutMapping("/{id}/status/{status}")
public ResponseEntity<DeliveryRouteDTO> updateRouteStatus(
@PathVariable Long id,
@PathVariable Integer status) {
log.info("REST request to update delivery route status with ID: {}, status: {}", id, status);
DeliveryRouteDTO result = deliveryRouteService.updateRouteStatus(id, status);
return ResponseEntity.ok(result);
}
/**
* 统计配送路线数量
*
* @return 配送路线数量
*/
@GetMapping("/count")
public ResponseEntity<Map<String, Long>> countDeliveryRoutes() {
log.info("REST request to count delivery routes");
Map<String, Long> result = deliveryRouteService.countDeliveryRoutes(new HashMap<>());
return ResponseEntity.ok(result);
}
}
express-service\src\main\java\com\campus\express\controller\NotificationController.java
package com.campus.express.controller;
import com.campus.express.dto.*;
import com.campus.express.service.NotificationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 通知管理控制器
*/
@RestController
@RequestMapping("/api/notifications")
@RequiredArgsConstructor
@Slf4j
public class NotificationController {
private final NotificationService notificationService;
/**
* 创建通知
*
* @param request 创建通知请求
* @return 通知DTO
*/
@PostMapping
public ResponseEntity<NotificationDTO> createNotification(@Valid @RequestBody NotificationCreateRequest request) {
log.info("Creating notification: {}", request);
NotificationDTO notification = notificationService.createNotification(request);
return new ResponseEntity<>(notification, HttpStatus.CREATED);
}
/**
* 根据ID查询通知
*
* @param id 通知ID
* @return 通知DTO
*/
@GetMapping("/{id}")
public ResponseEntity<NotificationDTO> getNotificationById(@PathVariable Long id) {
log.info("Getting notification by ID: {}", id);
NotificationDTO notification = notificationService.getNotificationById(id);
return ResponseEntity.ok(notification);
}
/**
* 更新通知
*
* @param id 通知ID
* @param request 更新通知请求
* @return 更新后的通知DTO
*/
@PutMapping("/{id}")
public ResponseEntity<NotificationDTO> updateNotification(
@PathVariable Long id, @Valid @RequestBody NotificationUpdateRequest request) {
log.info("Updating notification with ID: {}", id);
NotificationDTO notification = notificationService.updateNotification(id, request);
return ResponseEntity.ok(notification);
}
/**
* 删除通知
*
* @param id 通知ID
* @return 无内容响应
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteNotification(@PathVariable Long id) {
log.info("Deleting notification with ID: {}", id);
notificationService.deleteNotification(id);
return ResponseEntity.noContent().build();
}
/**
* 分页查询通知列表
*
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping
public ResponseEntity<Page<NotificationDTO>> getNotifications(
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications with pagination: {}", pageable);
Page<NotificationDTO> notifications = notificationService.getNotifications(pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据接收者ID和接收者类型分页查询通知列表
*
* @param receiverId 接收者ID
* @param receiverType 接收者类型
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/receiver")
public ResponseEntity<Page<NotificationDTO>> getNotificationsByReceiver(
@RequestParam Long receiverId,
@RequestParam Integer receiverType,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by receiver ID: {} and receiver type: {}", receiverId, receiverType);
Page<NotificationDTO> notifications = notificationService.getNotificationsByReceiver(
receiverId, receiverType, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据接收者ID、接收者类型和已读状态分页查询通知列表
*
* @param receiverId 接收者ID
* @param receiverType 接收者类型
* @param readStatus 已读状态
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/receiver/status")
public ResponseEntity<Page<NotificationDTO>> getNotificationsByReceiverAndReadStatus(
@RequestParam Long receiverId,
@RequestParam Integer receiverType,
@RequestParam Integer readStatus,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by receiver ID: {}, receiver type: {} and read status: {}",
receiverId, receiverType, readStatus);
Page<NotificationDTO> notifications = notificationService.getNotificationsByReceiverAndReadStatus(
receiverId, receiverType, readStatus, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据通知类型分页查询通知列表
*
* @param type 通知类型
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/type/{type}")
public ResponseEntity<Page<NotificationDTO>> getNotificationsByType(
@PathVariable Integer type,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by type: {}", type);
Page<NotificationDTO> notifications = notificationService.getNotificationsByType(type, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据通知渠道分页查询通知列表
*
* @param channel 通知渠道
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/channel/{channel}")
public ResponseEntity<Page<NotificationDTO>> getNotificationsByChannel(
@PathVariable Integer channel,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by channel: {}", channel);
Page<NotificationDTO> notifications = notificationService.getNotificationsByChannel(channel, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据发送状态分页查询通知列表
*
* @param sendStatus 发送状态
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/send-status/{sendStatus}")
public ResponseEntity<Page<NotificationDTO>> getNotificationsBySendStatus(
@PathVariable Integer sendStatus,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by send status: {}", sendStatus);
Page<NotificationDTO> notifications = notificationService.getNotificationsBySendStatus(sendStatus, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据创建时间范围分页查询通知列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 通知DTO分页列表
*/
@GetMapping("/time-range")
public ResponseEntity<Page<NotificationDTO>> getNotificationsByCreatedTimeBetween(
@RequestParam LocalDateTime startTime,
@RequestParam LocalDateTime endTime,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notifications by created time between: {} and {}", startTime, endTime);
Page<NotificationDTO> notifications = notificationService.getNotificationsByCreatedTimeBetween(
startTime, endTime, pageable);
return ResponseEntity.ok(notifications);
}
/**
* 根据关联业务ID和关联业务类型查询通知列表
*
* @param businessId 关联业务ID
* @param businessType 关联业务类型
* @return 通知DTO列表
*/
@GetMapping("/business")
public ResponseEntity<List<NotificationDTO>> getNotificationsByBusiness(
@RequestParam Long businessId, @RequestParam Integer businessType) {
log.info("Getting notifications by business ID: {} and business type: {}", businessId, businessType);
List<NotificationDTO> notifications = notificationService.getNotificationsByBusiness(businessId, businessType);
return ResponseEntity.ok(notifications);
}
/**
* 发送通知
*
* @param request 发送通知请求
* @return 通知DTO列表
*/
@PostMapping("/send")
public ResponseEntity<List<NotificationDTO>> sendNotification(@Valid @RequestBody NotificationSendRequest request) {
log.info("Sending notification: {}", request);
List<NotificationDTO> notifications = notificationService.sendNotification(request);
return new ResponseEntity<>(notifications, HttpStatus.CREATED);
}
/**
* 标记通知为已读
*
* @param id 通知ID
* @return 更新后的通知DTO
*/
@PutMapping("/{id}/read")
public ResponseEntity<NotificationDTO> markAsRead(@PathVariable Long id) {
log.info("Marking notification as read with ID: {}", id);
NotificationDTO notification = notificationService.markAsRead(id);
return ResponseEntity.ok(notification);
}
/**
* 批量标记通知为已读
*
* @param ids 通知ID列表
* @return 更新行数
*/
@PutMapping("/batch-read")
public ResponseEntity<Integer> batchMarkAsRead(@RequestBody List<Long> ids) {
log.info("Batch marking notifications as read with IDs: {}", ids);
int updated = notificationService.batchMarkAsRead(ids);
return ResponseEntity.ok(updated);
}
/**
* 标记接收者的所有通知为已读
*
* @param receiverId 接收者ID
* @param receiverType 接收者类型
* @return 更新行数
*/
@PutMapping("/mark-all-read")
public ResponseEntity<Integer> markAllAsRead(
@RequestParam Long receiverId, @RequestParam Integer receiverType) {
log.info("Marking all notifications as read for receiver ID: {} and receiver type: {}",
receiverId, receiverType);
int updated = notificationService.markAllAsRead(receiverId, receiverType);
return ResponseEntity.ok(updated);
}
/**
* 重试发送失败的通知
*
* @param id 通知ID
* @return 更新后的通知DTO
*/
@PutMapping("/{id}/retry")
public ResponseEntity<NotificationDTO> retrySendNotification(@PathVariable Long id) {
log.info("Retrying to send notification with ID: {}", id);
NotificationDTO notification = notificationService.retrySendNotification(id);
return ResponseEntity.ok(notification);
}
/**
* 统计接收者未读通知数量
*
* @param receiverId 接收者ID
* @param receiverType 接收者类型
* @return 未读通知数量
*/
@GetMapping("/count/unread")
public ResponseEntity<Long> countUnreadNotifications(
@RequestParam Long receiverId, @RequestParam Integer receiverType) {
log.info("Counting unread notifications for receiver ID: {} and receiver type: {}",
receiverId, receiverType);
long count = notificationService.countUnreadNotifications(receiverId, receiverType);
return ResponseEntity.ok(count);
}
/**
* 统计通知数量
*
* @param params 查询参数
* @return 通知数量
*/
@GetMapping("/count")
public ResponseEntity<Map<String, Long>> countNotifications(@RequestParam Map<String, Object> params) {
log.info("Counting notifications with params: {}", params);
Map<String, Long> counts = notificationService.countNotifications(params);
return ResponseEntity.ok(counts);
}
}
express-service\src\main\java\com\campus\express\controller\NotificationTemplateController.java
package com.campus.express.controller;
import com.campus.express.dto.NotificationTemplateCreateRequest;
import com.campus.express.dto.NotificationTemplateDTO;
import com.campus.express.dto.NotificationTemplateUpdateRequest;
import com.campus.express.service.NotificationTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 通知模板管理控制器
*/
@RestController
@RequestMapping("/api/notification-templates")
@RequiredArgsConstructor
@Slf4j
public class NotificationTemplateController {
private final NotificationTemplateService notificationTemplateService;
/**
* 创建通知模板
*
* @param request 创建通知模板请求
* @return 通知模板DTO
*/
@PostMapping
public ResponseEntity<NotificationTemplateDTO> createNotificationTemplate(
@Valid @RequestBody NotificationTemplateCreateRequest request) {
log.info("Creating notification template: {}", request);
NotificationTemplateDTO template = notificationTemplateService.createNotificationTemplate(request);
return new ResponseEntity<>(template, HttpStatus.CREATED);
}
/**
* 根据ID查询通知模板
*
* @param id 通知模板ID
* @return 通知模板DTO
*/
@GetMapping("/{id}")
public ResponseEntity<NotificationTemplateDTO> getNotificationTemplateById(@PathVariable Long id) {
log.info("Getting notification template by ID: {}", id);
NotificationTemplateDTO template = notificationTemplateService.getNotificationTemplateById(id);
return ResponseEntity.ok(template);
}
/**
* 根据模板编码查询通知模板
*
* @param code 模板编码
* @return 通知模板DTO
*/
@GetMapping("/code/{code}")
public ResponseEntity<NotificationTemplateDTO> getNotificationTemplateByCode(@PathVariable String code) {
log.info("Getting notification template by code: {}", code);
NotificationTemplateDTO template = notificationTemplateService.getNotificationTemplateByCode(code);
return ResponseEntity.ok(template);
}
/**
* 更新通知模板
*
* @param id 通知模板ID
* @param request 更新通知模板请求
* @return 更新后的通知模板DTO
*/
@PutMapping("/{id}")
public ResponseEntity<NotificationTemplateDTO> updateNotificationTemplate(
@PathVariable Long id, @Valid @RequestBody NotificationTemplateUpdateRequest request) {
log.info("Updating notification template with ID: {}", id);
NotificationTemplateDTO template = notificationTemplateService.updateNotificationTemplate(id, request);
return ResponseEntity.ok(template);
}
/**
* 删除通知模板
*
* @param id 通知模板ID
* @return 无内容响应
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteNotificationTemplate(@PathVariable Long id) {
log.info("Deleting notification template with ID: {}", id);
notificationTemplateService.deleteNotificationTemplate(id);
return ResponseEntity.noContent().build();
}
/**
* 分页查询通知模板列表
*
* @param pageable 分页参数
* @return 通知模板DTO分页列表
*/
@GetMapping
public ResponseEntity<Page<NotificationTemplateDTO>> getNotificationTemplates(
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notification templates with pagination: {}", pageable);
Page<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplates(pageable);
return ResponseEntity.ok(templates);
}
/**
* 根据模板名称分页查询通知模板列表
*
* @param name 模板名称
* @param pageable 分页参数
* @return 通知模板DTO分页列表
*/
@GetMapping("/name")
public ResponseEntity<Page<NotificationTemplateDTO>> getNotificationTemplatesByName(
@RequestParam String name,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notification templates by name: {}", name);
Page<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByName(name, pageable);
return ResponseEntity.ok(templates);
}
/**
* 根据模板类型分页查询通知模板列表
*
* @param type 模板类型
* @param pageable 分页参数
* @return 通知模板DTO分页列表
*/
@GetMapping("/type/{type}")
public ResponseEntity<Page<NotificationTemplateDTO>> getNotificationTemplatesByType(
@PathVariable Integer type,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notification templates by type: {}", type);
Page<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByType(type, pageable);
return ResponseEntity.ok(templates);
}
/**
* 根据适用渠道分页查询通知模板列表
*
* @param channel 适用渠道
* @param pageable 分页参数
* @return 通知模板DTO分页列表
*/
@GetMapping("/channel/{channel}")
public ResponseEntity<Page<NotificationTemplateDTO>> getNotificationTemplatesByChannel(
@PathVariable Integer channel,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notification templates by channel: {}", channel);
Page<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByChannel(channel, pageable);
return ResponseEntity.ok(templates);
}
/**
* 根据状态分页查询通知模板列表
*
* @param status 状态
* @param pageable 分页参数
* @return 通知模板DTO分页列表
*/
@GetMapping("/status/{status}")
public ResponseEntity<Page<NotificationTemplateDTO>> getNotificationTemplatesByStatus(
@PathVariable Integer status,
@PageableDefault(size = 10, sort = "createdTime,desc") Pageable pageable) {
log.info("Getting notification templates by status: {}", status);
Page<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByStatus(status, pageable);
return ResponseEntity.ok(templates);
}
/**
* 根据模板类型和适用渠道查询通知模板列表
*
* @param type 模板类型
* @param channel 适用渠道
* @return 通知模板DTO列表
*/
@GetMapping("/type/{type}/channel/{channel}")
public ResponseEntity<List<NotificationTemplateDTO>> getNotificationTemplatesByTypeAndChannel(
@PathVariable Integer type, @PathVariable Integer channel) {
log.info("Getting notification templates by type: {} and channel: {}", type, channel);
List<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByTypeAndChannel(type, channel);
return ResponseEntity.ok(templates);
}
/**
* 根据模板类型和状态查询通知模板列表
*
* @param type 模板类型
* @param status 状态
* @return 通知模板DTO列表
*/
@GetMapping("/type/{type}/status/{status}")
public ResponseEntity<List<NotificationTemplateDTO>> getNotificationTemplatesByTypeAndStatus(
@PathVariable Integer type, @PathVariable Integer status) {
log.info("Getting notification templates by type: {} and status: {}", type, status);
List<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByTypeAndStatus(type, status);
return ResponseEntity.ok(templates);
}
/**
* 根据适用渠道和状态查询通知模板列表
*
* @param channel 适用渠道
* @param status 状态
* @return 通知模板DTO列表
*/
@GetMapping("/channel/{channel}/status/{status}")
public ResponseEntity<List<NotificationTemplateDTO>> getNotificationTemplatesByChannelAndStatus(
@PathVariable Integer channel, @PathVariable Integer status) {
log.info("Getting notification templates by channel: {} and status: {}", channel, status);
List<NotificationTemplateDTO> templates = notificationTemplateService.getNotificationTemplatesByChannelAndStatus(channel, status);
return ResponseEntity.ok(templates);
}
/**
* 更新通知模板状态
*
* @param id 通知模板ID
* @param status 状态
* @return 更新后的通知模板DTO
*/
@PutMapping("/{id}/status/{status}")
public ResponseEntity<NotificationTemplateDTO> updateTemplateStatus(
@PathVariable Long id, @PathVariable Integer status) {
log.info("Updating notification template status with ID: {} to status: {}", id, status);
NotificationTemplateDTO template = notificationTemplateService.updateTemplateStatus(id, status);
return ResponseEntity.ok(template);
}
/**
* 检查模板编码是否存在
*
* @param code 模板编码
* @return 是否存在
*/
@GetMapping("/check-code/{code}")
public ResponseEntity<Boolean> isTemplateCodeExists(@PathVariable String code) {
log.info("Checking if template code exists: {}", code);
boolean exists = notificationTemplateService.isTemplateCodeExists(code);
return ResponseEntity.ok(exists);
}
/**
* 渲染模板内容
*
* @param templateCode 模板编码
* @param params 模板参数
* @return 渲染后的内容
*/
@PostMapping("/render/{templateCode}")
public ResponseEntity<Map<String, String>> renderTemplate(
@PathVariable String templateCode, @RequestBody Map<String, Object> params) {
log.info("Rendering template with code: {} and params: {}", templateCode, params);
Map<String, String> renderedContent = notificationTemplateService.renderTemplate(templateCode, params);
return ResponseEntity.ok(renderedContent);
}
/**
* 统计通知模板数量
*
* @param params 查询参数
* @return 通知模板数量
*/
@GetMapping("/count")
public ResponseEntity<Map<String, Long>> countNotificationTemplates(@RequestParam Map<String, Object> params) {
log.info("Counting notification templates with params: {}", params);
Map<String, Long> counts = notificationTemplateService.countNotificationTemplates(params);
return ResponseEntity.ok(counts);
}
}
express-service\src\main\java\com\campus\express\dto\ApiResponse.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* API响应包装类
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private Integer code;
private String message;
private T data;
private LocalDateTime timestamp;
/**
* 创建成功响应
*
* @param data 响应数据
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.code(200)
.message("操作成功")
.data(data)
.timestamp(LocalDateTime.now())
.build();
}
/**
* 创建成功响应(无数据)
*
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> success() {
return ApiResponse.<T>builder()
.code(200)
.message("操作成功")
.timestamp(LocalDateTime.now())
.build();
}
/**
* 创建成功响应(自定义消息)
*
* @param message 响应消息
* @param data 响应数据
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> success(String message, T data) {
return ApiResponse.<T>builder()
.code(200)
.message(message)
.data(data)
.timestamp(LocalDateTime.now())
.build();
}
/**
* 创建错误响应
*
* @param code 错误码
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> error(Integer code, String message) {
return ApiResponse.<T>builder()
.code(code)
.message(message)
.timestamp(LocalDateTime.now())
.build();
}
/**
* 创建错误响应(400 Bad Request)
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> badRequest(String message) {
return error(400, message);
}
/**
* 创建错误响应(401 Unauthorized)
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> unauthorized(String message) {
return error(401, message);
}
/**
* 创建错误响应(403 Forbidden)
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> forbidden(String message) {
return error(403, message);
}
/**
* 创建错误响应(404 Not Found)
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> notFound(String message) {
return error(404, message);
}
/**
* 创建错误响应(500 Internal Server Error)
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应对象
*/
public static <T> ApiResponse<T> serverError(String message) {
return error(500, message);
}
}
express-service\src\main\java\com\campus\express\dto\CabinetCellDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递柜格口数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CabinetCellDTO {
private Long id;
/**
* 柜子ID
*/
@NotNull(message = "柜子ID不能为空")
private Long cabinetId;
/**
* 柜子名称
*/
private String cabinetName;
/**
* 格口编号
*/
@NotBlank(message = "格口编号不能为空")
@Size(max = 20, message = "格口编号长度不能超过20个字符")
private String cellNumber;
/**
* 格口大小:0-小,1-中,2-大
*/
@NotNull(message = "格口大小不能为空")
private Integer size;
/**
* 格口大小描述
*/
private String sizeDesc;
/**
* 格口状态:0-空闲,1-占用,2-故障
*/
@NotNull(message = "格口状态不能为空")
private Integer status;
/**
* 格口状态描述
*/
private String statusDesc;
/**
* 当前存放的快递ID
*/
private Long expressId;
/**
* 当前存放的快递单号
*/
private String trackingNumber;
/**
* 存入时间
*/
private LocalDateTime storageTime;
/**
* 取出时间
*/
private LocalDateTime retrievalTime;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\dto\CabinetCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 创建快递柜请求DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CabinetCreateRequest {
/**
* 柜子编号
*/
@NotBlank(message = "柜子编号不能为空")
@Size(max = 50, message = "柜子编号长度不能超过50个字符")
private String cabinetNumber;
/**
* 柜子名称
*/
@NotBlank(message = "柜子名称不能为空")
@Size(max = 100, message = "柜子名称长度不能超过100个字符")
private String name;
/**
* 柜子位置
*/
@NotBlank(message = "柜子位置不能为空")
@Size(max = 255, message = "柜子位置长度不能超过255个字符")
private String location;
/**
* 柜子状态:0-停用,1-启用
*/
@NotNull(message = "柜子状态不能为空")
private Integer status;
/**
* 总格口数
*/
@NotNull(message = "总格口数不能为空")
private Integer totalCells;
/**
* 小格口数量
*/
private Integer smallCellCount;
/**
* 中格口数量
*/
private Integer mediumCellCount;
/**
* 大格口数量
*/
private Integer largeCellCount;
/**
* 负责人ID
*/
private Long managerId;
/**
* 负责人姓名
*/
@Size(max = 50, message = "负责人姓名长度不能超过50个字符")
private String managerName;
/**
* 负责人电话
*/
@Size(max = 20, message = "负责人电话长度不能超过20个字符")
private String managerPhone;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\CabinetDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递柜数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CabinetDTO {
private Long id;
/**
* 柜子编号
*/
@NotBlank(message = "柜子编号不能为空")
@Size(max = 50, message = "柜子编号长度不能超过50个字符")
private String cabinetNumber;
/**
* 柜子名称
*/
@NotBlank(message = "柜子名称不能为空")
@Size(max = 100, message = "柜子名称长度不能超过100个字符")
private String name;
/**
* 柜子位置
*/
@NotBlank(message = "柜子位置不能为空")
@Size(max = 255, message = "柜子位置长度不能超过255个字符")
private String location;
/**
* 柜子状态:0-停用,1-启用
*/
@NotNull(message = "柜子状态不能为空")
private Integer status;
/**
* 柜子状态描述
*/
private String statusDesc;
/**
* 总格口数
*/
@NotNull(message = "总格口数不能为空")
private Integer totalCells;
/**
* 可用格口数
*/
@NotNull(message = "可用格口数不能为空")
private Integer availableCells;
/**
* 小格口数量
*/
private Integer smallCellCount;
/**
* 中格口数量
*/
private Integer mediumCellCount;
/**
* 大格口数量
*/
private Integer largeCellCount;
/**
* 负责人ID
*/
private Long managerId;
/**
* 负责人姓名
*/
@Size(max = 50, message = "负责人姓名长度不能超过50个字符")
private String managerName;
/**
* 负责人电话
*/
@Size(max = 20, message = "负责人电话长度不能超过20个字符")
private String managerPhone;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\dto\CabinetUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Size;
/**
* 更新快递柜请求DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CabinetUpdateRequest {
/**
* 柜子名称
*/
@Size(max = 100, message = "柜子名称长度不能超过100个字符")
private String name;
/**
* 柜子位置
*/
@Size(max = 255, message = "柜子位置长度不能超过255个字符")
private String location;
/**
* 柜子状态:0-停用,1-启用
*/
private Integer status;
/**
* 负责人ID
*/
private Long managerId;
/**
* 负责人姓名
*/
@Size(max = 50, message = "负责人姓名长度不能超过50个字符")
private String managerName;
/**
* 负责人电话
*/
@Size(max = 20, message = "负责人电话长度不能超过20个字符")
private String managerPhone;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\DeliveryAreaCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 创建配送区域请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryAreaCreateRequest {
/**
* 区域代码
*/
@NotBlank(message = "区域代码不能为空")
private String areaCode;
/**
* 区域名称
*/
@NotBlank(message = "区域名称不能为空")
private String name;
/**
* 父区域ID
*/
private Long parentId;
/**
* 区域级别(1-校区,2-楼栋,3-具体位置)
*/
@NotNull(message = "区域级别不能为空")
private Integer level;
/**
* 区域边界(GeoJSON格式)
*/
private String boundary;
/**
* 中心点坐标(经度)
*/
@NotNull(message = "中心点经度不能为空")
private Double centerLongitude;
/**
* 中心点坐标(纬度)
*/
@NotNull(message = "中心点纬度不能为空")
private Double centerLatitude;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 预计配送时间(分钟)
*/
private Integer estimatedDeliveryTime;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 区域描述
*/
private String description;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\DeliveryAreaDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
/**
* 配送区域数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryAreaDTO {
/**
* 配送区域ID
*/
private Long id;
/**
* 区域代码
*/
private String areaCode;
/**
* 区域名称
*/
private String name;
/**
* 父区域ID
*/
private Long parentId;
/**
* 父区域名称
*/
private String parentName;
/**
* 区域级别(1-校区,2-楼栋,3-具体位置)
*/
private Integer level;
/**
* 区域级别描述
*/
private String levelDesc;
/**
* 区域边界(GeoJSON格式)
*/
private String boundary;
/**
* 中心点坐标(经度)
*/
private Double centerLongitude;
/**
* 中心点坐标(纬度)
*/
private Double centerLatitude;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 预计配送时间(分钟)
*/
private Integer estimatedDeliveryTime;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 状态描述
*/
private String statusDesc;
/**
* 区域描述
*/
private String description;
/**
* 子区域列表
*/
private List<DeliveryAreaDTO> children;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\dto\DeliveryAreaUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 更新配送区域请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryAreaUpdateRequest {
/**
* 区域名称
*/
private String name;
/**
* 父区域ID
*/
private Long parentId;
/**
* 区域级别(1-校区,2-楼栋,3-具体位置)
*/
private Integer level;
/**
* 区域边界(GeoJSON格式)
*/
private String boundary;
/**
* 中心点坐标(经度)
*/
private Double centerLongitude;
/**
* 中心点坐标(纬度)
*/
private Double centerLatitude;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 预计配送时间(分钟)
*/
private Integer estimatedDeliveryTime;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 区域描述
*/
private String description;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\DeliveryCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 创建配送任务请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryCreateRequest {
/**
* 快递ID
*/
@NotNull(message = "快递ID不能为空")
private Long expressId;
/**
* 快递单号
*/
@NotBlank(message = "快递单号不能为空")
private String trackingNumber;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 配送员电话
*/
private String courierPhone;
/**
* 收件人姓名
*/
@NotBlank(message = "收件人姓名不能为空")
private String recipientName;
/**
* 收件人电话
*/
@NotBlank(message = "收件人电话不能为空")
private String recipientPhone;
/**
* 收件人地址
*/
@NotBlank(message = "收件人地址不能为空")
private String recipientAddress;
/**
* 配送区域
*/
@NotBlank(message = "配送区域不能为空")
private String deliveryArea;
/**
* 配送区域代码
*/
private String areaCode;
/**
* 配送路线ID
*/
private Long routeId;
/**
* 计划配送时间
*/
private LocalDateTime plannedDeliveryTime;
/**
* 配送优先级(0-普通,1-优先,2-加急)
*/
private Integer priority;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 配送距离(米)
*/
private Double distance;
/**
* 预计配送时长(分钟)
*/
private Integer estimatedDuration;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\DeliveryDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 配送任务数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryDTO {
/**
* 配送任务ID
*/
private Long id;
/**
* 快递ID
*/
private Long expressId;
/**
* 快递单号
*/
private String trackingNumber;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 配送员电话
*/
private String courierPhone;
/**
* 收件人姓名
*/
private String recipientName;
/**
* 收件人电话
*/
private String recipientPhone;
/**
* 收件人地址
*/
private String recipientAddress;
/**
* 配送区域
*/
private String deliveryArea;
/**
* 配送区域代码
*/
private String areaCode;
/**
* 配送路线ID
*/
private Long routeId;
/**
* 配送路线名称
*/
private String routeName;
/**
* 计划配送时间
*/
private LocalDateTime plannedDeliveryTime;
/**
* 实际配送时间
*/
private LocalDateTime actualDeliveryTime;
/**
* 配送完成时间
*/
private LocalDateTime completedTime;
/**
* 配送验证码
*/
private String deliveryCode;
/**
* 配送状态(0-待分配,1-待配送,2-配送中,3-已送达,4-已完成,5-已取消)
*/
private Integer status;
/**
* 配送状态描述
*/
private String statusDesc;
/**
* 配送优先级(0-普通,1-优先,2-加急)
*/
private Integer priority;
/**
* 配送优先级描述
*/
private String priorityDesc;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 配送距离(米)
*/
private Double distance;
/**
* 预计配送时长(分钟)
*/
private Integer estimatedDuration;
/**
* 实际配送时长(分钟)
*/
private Integer actualDuration;
/**
* 取消原因
*/
private String cancelReason;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\dto\DeliveryRouteCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 创建配送路线请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryRouteCreateRequest {
/**
* 路线编号
*/
@NotBlank(message = "路线编号不能为空")
private String routeNumber;
/**
* 路线名称
*/
@NotBlank(message = "路线名称不能为空")
private String name;
/**
* 起点
*/
@NotBlank(message = "起点不能为空")
private String startPoint;
/**
* 起点坐标(经度)
*/
@NotNull(message = "起点经度不能为空")
private Double startLongitude;
/**
* 起点坐标(纬度)
*/
@NotNull(message = "起点纬度不能为空")
private Double startLatitude;
/**
* 终点
*/
@NotBlank(message = "终点不能为空")
private String endPoint;
/**
* 终点坐标(经度)
*/
@NotNull(message = "终点经度不能为空")
private Double endLongitude;
/**
* 终点坐标(纬度)
*/
@NotNull(message = "终点纬度不能为空")
private Double endLatitude;
/**
* 途经点列表
*/
private List<WaypointDTO> waypoints;
/**
* 配送区域
*/
@NotBlank(message = "配送区域不能为空")
private String area;
/**
* 区域代码
*/
private String areaCode;
/**
* 路线距离(米)
*/
private Double distance;
/**
* 预计时长(分钟)
*/
private Integer estimatedDuration;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 路线描述
*/
private String description;
/**
* 路线类型(0-步行,1-自行车,2-电动车,3-汽车)
*/
private Integer routeType;
/**
* 备注
*/
private String remark;
/**
* 途经点数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class WaypointDTO {
/**
* 途经点名称
*/
@NotBlank(message = "途经点名称不能为空")
private String name;
/**
* 途经点坐标(经度)
*/
@NotNull(message = "途经点经度不能为空")
private Double longitude;
/**
* 途经点坐标(纬度)
*/
@NotNull(message = "途经点纬度不能为空")
private Double latitude;
/**
* 途经点顺序
*/
@NotNull(message = "途经点顺序不能为空")
private Integer sequence;
}
}
express-service\src\main\java\com\campus\express\dto\DeliveryRouteDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
/**
* 配送路线数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryRouteDTO {
/**
* 配送路线ID
*/
private Long id;
/**
* 路线编号
*/
private String routeNumber;
/**
* 路线名称
*/
private String name;
/**
* 起点
*/
private String startPoint;
/**
* 起点坐标(经度)
*/
private Double startLongitude;
/**
* 起点坐标(纬度)
*/
private Double startLatitude;
/**
* 终点
*/
private String endPoint;
/**
* 终点坐标(经度)
*/
private Double endLongitude;
/**
* 终点坐标(纬度)
*/
private Double endLatitude;
/**
* 途经点列表
*/
private List<WaypointDTO> waypoints;
/**
* 配送区域
*/
private String area;
/**
* 区域代码
*/
private String areaCode;
/**
* 路线距离(米)
*/
private Double distance;
/**
* 预计时长(分钟)
*/
private Integer estimatedDuration;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 状态描述
*/
private String statusDesc;
/**
* 路线描述
*/
private String description;
/**
* 路线类型(0-步行,1-自行车,2-电动车,3-汽车)
*/
private Integer routeType;
/**
* 路线类型描述
*/
private String routeTypeDesc;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
/**
* 途经点数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class WaypointDTO {
/**
* 途经点名称
*/
private String name;
/**
* 途经点坐标(经度)
*/
private Double longitude;
/**
* 途经点坐标(纬度)
*/
private Double latitude;
/**
* 途经点顺序
*/
private Integer sequence;
}
}
express-service\src\main\java\com\campus\express\dto\DeliveryRouteUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 更新配送路线请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryRouteUpdateRequest {
/**
* 路线名称
*/
private String name;
/**
* 起点
*/
private String startPoint;
/**
* 起点坐标(经度)
*/
private Double startLongitude;
/**
* 起点坐标(纬度)
*/
private Double startLatitude;
/**
* 终点
*/
private String endPoint;
/**
* 终点坐标(经度)
*/
private Double endLongitude;
/**
* 终点坐标(纬度)
*/
private Double endLatitude;
/**
* 途经点列表
*/
private List<DeliveryRouteCreateRequest.WaypointDTO> waypoints;
/**
* 配送区域
*/
private String area;
/**
* 区域代码
*/
private String areaCode;
/**
* 路线距离(米)
*/
private Double distance;
/**
* 预计时长(分钟)
*/
private Integer estimatedDuration;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 路线描述
*/
private String description;
/**
* 路线类型(0-步行,1-自行车,2-电动车,3-汽车)
*/
private Integer routeType;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\DeliveryUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 更新配送任务请求
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryUpdateRequest {
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 配送员电话
*/
private String courierPhone;
/**
* 收件人姓名
*/
private String recipientName;
/**
* 收件人电话
*/
private String recipientPhone;
/**
* 收件人地址
*/
private String recipientAddress;
/**
* 配送区域
*/
private String deliveryArea;
/**
* 配送区域代码
*/
private String areaCode;
/**
* 配送路线ID
*/
private Long routeId;
/**
* 配送路线名称
*/
private String routeName;
/**
* 计划配送时间
*/
private LocalDateTime plannedDeliveryTime;
/**
* 实际配送时间
*/
private LocalDateTime actualDeliveryTime;
/**
* 配送完成时间
*/
private LocalDateTime completedTime;
/**
* 配送验证码
*/
private String deliveryCode;
/**
* 配送状态(0-待分配,1-待配送,2-配送中,3-已送达,4-已完成,5-已取消)
*/
private Integer status;
/**
* 配送优先级(0-普通,1-优先,2-加急)
*/
private Integer priority;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 配送距离(米)
*/
private Double distance;
/**
* 预计配送时长(分钟)
*/
private Integer estimatedDuration;
/**
* 实际配送时长(分钟)
*/
private Integer actualDuration;
/**
* 取消原因
*/
private String cancelReason;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\ExpressCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 创建快递请求DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExpressCreateRequest {
/**
* 快递单号
*/
@NotBlank(message = "快递单号不能为空")
@Size(max = 50, message = "快递单号长度不能超过50个字符")
private String trackingNumber;
/**
* 快递公司
*/
@NotBlank(message = "快递公司不能为空")
@Size(max = 50, message = "快递公司长度不能超过50个字符")
private String company;
/**
* 收件人姓名
*/
@NotBlank(message = "收件人姓名不能为空")
@Size(max = 50, message = "收件人姓名长度不能超过50个字符")
private String recipientName;
/**
* 收件人电话
*/
@NotBlank(message = "收件人电话不能为空")
@Size(max = 20, message = "收件人电话长度不能超过20个字符")
private String recipientPhone;
/**
* 收件人地址(宿舍楼栋)
*/
@NotBlank(message = "收件人地址不能为空")
@Size(max = 255, message = "收件人地址长度不能超过255个字符")
private String recipientAddress;
/**
* 快递描述
*/
@Size(max = 255, message = "快递描述长度不能超过255个字符")
private String description;
/**
* 快递重量(克)
*/
private Integer weight;
/**
* 快递员ID
*/
private Long courierId;
/**
* 快递员姓名
*/
private String courierName;
/**
* 快递员电话
*/
private String courierPhone;
/**
* 用户ID(收件人)
*/
private Long userId;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\ExpressDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExpressDTO {
private Long id;
/**
* 快递单号
*/
@NotBlank(message = "快递单号不能为空")
@Size(max = 50, message = "快递单号长度不能超过50个字符")
private String trackingNumber;
/**
* 快递公司
*/
@NotBlank(message = "快递公司不能为空")
@Size(max = 50, message = "快递公司长度不能超过50个字符")
private String company;
/**
* 收件人姓名
*/
@NotBlank(message = "收件人姓名不能为空")
@Size(max = 50, message = "收件人姓名长度不能超过50个字符")
private String recipientName;
/**
* 收件人电话
*/
@NotBlank(message = "收件人电话不能为空")
@Size(max = 20, message = "收件人电话长度不能超过20个字符")
private String recipientPhone;
/**
* 收件人地址(宿舍楼栋)
*/
@NotBlank(message = "收件人地址不能为空")
@Size(max = 255, message = "收件人地址长度不能超过255个字符")
private String recipientAddress;
/**
* 快递描述
*/
@Size(max = 255, message = "快递描述长度不能超过255个字符")
private String description;
/**
* 快递重量(克)
*/
private Integer weight;
/**
* 快递状态:0-待揽收,1-已揽收,2-配送中,3-已送达,4-已签收,5-异常
*/
@NotNull(message = "快递状态不能为空")
private Integer status;
/**
* 快递状态描述
*/
private String statusDesc;
/**
* 快递员ID
*/
private Long courierId;
/**
* 快递员姓名
*/
private String courierName;
/**
* 快递员电话
*/
private String courierPhone;
/**
* 用户ID(收件人)
*/
private Long userId;
/**
* 柜子ID
*/
private Long cabinetId;
/**
* 柜子名称
*/
private String cabinetName;
/**
* 柜子位置
*/
private String cabinetLocation;
/**
* 柜子格口号
*/
private String cabinetCell;
/**
* 取件码
*/
private String pickupCode;
/**
* 揽收时间
*/
private LocalDateTime collectionTime;
/**
* 送达时间
*/
private LocalDateTime deliveryTime;
/**
* 签收时间
*/
private LocalDateTime signTime;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\dto\ExpressTrackingDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递跟踪记录数据传输对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExpressTrackingDTO {
private Long id;
/**
* 快递ID
*/
@NotNull(message = "快递ID不能为空")
private Long expressId;
/**
* 快递单号
*/
@NotBlank(message = "快递单号不能为空")
@Size(max = 50, message = "快递单号长度不能超过50个字符")
private String trackingNumber;
/**
* 操作类型:0-创建,1-揽收,2-配送中,3-送达,4-签收,5-异常
*/
@NotNull(message = "操作类型不能为空")
private Integer operationType;
/**
* 操作类型描述
*/
private String operationTypeDesc;
/**
* 操作描述
*/
@NotBlank(message = "操作描述不能为空")
@Size(max = 255, message = "操作描述长度不能超过255个字符")
private String description;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人类型:0-系统,1-快递员,2-用户
*/
@NotNull(message = "操作人类型不能为空")
private Integer operatorType;
/**
* 操作人类型描述
*/
private String operatorTypeDesc;
/**
* 操作人姓名
*/
@Size(max = 50, message = "操作人姓名长度不能超过50个字符")
private String operatorName;
/**
* 操作地点
*/
@Size(max = 255, message = "操作地点长度不能超过255个字符")
private String location;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
/**
* 创建时间(操作时间)
*/
private LocalDateTime createdTime;
}
express-service\src\main\java\com\campus\express\dto\ExpressUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Size;
/**
* 更新快递请求DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExpressUpdateRequest {
/**
* 快递公司
*/
@Size(max = 50, message = "快递公司长度不能超过50个字符")
private String company;
/**
* 收件人姓名
*/
@Size(max = 50, message = "收件人姓名长度不能超过50个字符")
private String recipientName;
/**
* 收件人电话
*/
@Size(max = 20, message = "收件人电话长度不能超过20个字符")
private String recipientPhone;
/**
* 收件人地址(宿舍楼栋)
*/
@Size(max = 255, message = "收件人地址长度不能超过255个字符")
private String recipientAddress;
/**
* 快递描述
*/
@Size(max = 255, message = "快递描述长度不能超过255个字符")
private String description;
/**
* 快递重量(克)
*/
private Integer weight;
/**
* 快递状态:0-待揽收,1-已揽收,2-配送中,3-已送达,4-已签收,5-异常
*/
private Integer status;
/**
* 快递员ID
*/
private Long courierId;
/**
* 快递员姓名
*/
private String courierName;
/**
* 快递员电话
*/
private String courierPhone;
/**
* 用户ID(收件人)
*/
private Long userId;
/**
* 柜子ID
*/
private Long cabinetId;
/**
* 柜子格口号
*/
private String cabinetCell;
/**
* 取件码
*/
private String pickupCode;
/**
* 备注
*/
@Size(max = 255, message = "备注长度不能超过255个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 创建通知请求
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationCreateRequest {
/**
* 通知标题
*/
@NotBlank(message = "通知标题不能为空")
@Size(max = 100, message = "通知标题长度不能超过100个字符")
private String title;
/**
* 通知内容
*/
@NotBlank(message = "通知内容不能为空")
@Size(max = 500, message = "通知内容长度不能超过500个字符")
private String content;
/**
* 通知类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
@NotNull(message = "通知类型不能为空")
private Integer type;
/**
* 通知渠道:1-站内信,2-短信,3-邮件,4-推送
*/
@NotNull(message = "通知渠道不能为空")
private Integer channel;
/**
* 接收者ID
*/
@NotNull(message = "接收者ID不能为空")
private Long receiverId;
/**
* 接收者类型:1-用户,2-配送员,3-管理员
*/
@NotNull(message = "接收者类型不能为空")
private Integer receiverType;
/**
* 发送者ID
*/
private Long senderId;
/**
* 发送者类型:1-系统,2-用户,3-配送员,4-管理员
*/
private Integer senderType = 1; // 默认为系统发送
/**
* 关联业务ID
*/
private Long businessId;
/**
* 关联业务类型:1-快递,2-配送,3-活动
*/
private Integer businessType;
/**
* 备注
*/
@Size(max = 200, message = "备注长度不能超过200个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 通知DTO
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationDTO {
/**
* 通知ID
*/
private Long id;
/**
* 通知标题
*/
private String title;
/**
* 通知内容
*/
private String content;
/**
* 通知类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
private Integer type;
/**
* 通知类型描述
*/
private String typeDesc;
/**
* 通知渠道:1-站内信,2-短信,3-邮件,4-推送
*/
private Integer channel;
/**
* 通知渠道描述
*/
private String channelDesc;
/**
* 接收者ID
*/
private Long receiverId;
/**
* 接收者类型:1-用户,2-配送员,3-管理员
*/
private Integer receiverType;
/**
* 接收者类型描述
*/
private String receiverTypeDesc;
/**
* 发送者ID
*/
private Long senderId;
/**
* 发送者类型:1-系统,2-用户,3-配送员,4-管理员
*/
private Integer senderType;
/**
* 发送者类型描述
*/
private String senderTypeDesc;
/**
* 关联业务ID
*/
private Long businessId;
/**
* 关联业务类型:1-快递,2-配送,3-活动
*/
private Integer businessType;
/**
* 关联业务类型描述
*/
private String businessTypeDesc;
/**
* 是否已读:0-未读,1-已读
*/
private Integer readStatus;
/**
* 是否已读描述
*/
private String readStatusDesc;
/**
* 是否发送成功:0-失败,1-成功
*/
private Integer sendStatus;
/**
* 是否发送成功描述
*/
private String sendStatusDesc;
/**
* 失败原因
*/
private String failReason;
/**
* 重试次数
*/
private Integer retryCount;
/**
* 下次重试时间
*/
private LocalDateTime nextRetryTime;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationSendRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
import java.util.Map;
/**
* 发送通知请求
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationSendRequest {
/**
* 通知标题(如果不使用模板,则必填)
*/
@Size(max = 100, message = "通知标题长度不能超过100个字符")
private String title;
/**
* 通知内容(如果不使用模板,则必填)
*/
@Size(max = 500, message = "通知内容长度不能超过500个字符")
private String content;
/**
* 模板编码(如果使用模板,则必填)
*/
private String templateCode;
/**
* 模板参数(如果使用模板,则必填)
*/
private Map<String, Object> templateParams;
/**
* 通知类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
@NotNull(message = "通知类型不能为空")
private Integer type;
/**
* 通知渠道:1-站内信,2-短信,3-邮件,4-推送
*/
@NotNull(message = "通知渠道不能为空")
private Integer channel;
/**
* 接收者ID列表
*/
@NotEmpty(message = "接收者ID列表不能为空")
private List<Long> receiverIds;
/**
* 接收者类型:1-用户,2-配送员,3-管理员
*/
@NotNull(message = "接收者类型不能为空")
private Integer receiverType;
/**
* 发送者ID
*/
private Long senderId;
/**
* 发送者类型:1-系统,2-用户,3-配送员,4-管理员
*/
private Integer senderType = 1; // 默认为系统发送
/**
* 关联业务ID
*/
private Long businessId;
/**
* 关联业务类型:1-快递,2-配送,3-活动
*/
private Integer businessType;
/**
* 是否立即发送:true-是,false-否(加入队列)
*/
private Boolean sendImmediately = true;
/**
* 备注
*/
@Size(max = 200, message = "备注长度不能超过200个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationTemplateCreateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* 创建通知模板请求
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationTemplateCreateRequest {
/**
* 模板编码
*/
@NotBlank(message = "模板编码不能为空")
@Size(max = 50, message = "模板编码长度不能超过50个字符")
@Pattern(regexp = "^[A-Z][A-Z0-9_]*$", message = "模板编码必须以大写字母开头,只能包含大写字母、数字和下划线")
private String code;
/**
* 模板名称
*/
@NotBlank(message = "模板名称不能为空")
@Size(max = 100, message = "模板名称长度不能超过100个字符")
private String name;
/**
* 模板标题
*/
@NotBlank(message = "模板标题不能为空")
@Size(max = 100, message = "模板标题长度不能超过100个字符")
private String title;
/**
* 模板内容
*/
@NotBlank(message = "模板内容不能为空")
@Size(max = 1000, message = "模板内容长度不能超过1000个字符")
private String content;
/**
* 模板类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
@NotNull(message = "模板类型不能为空")
private Integer type;
/**
* 适用渠道:1-站内信,2-短信,3-邮件,4-推送
*/
@NotNull(message = "适用渠道不能为空")
private Integer channel;
/**
* 状态:0-停用,1-启用
*/
@NotNull(message = "状态不能为空")
private Integer status;
/**
* 备注
*/
@Size(max = 200, message = "备注长度不能超过200个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationTemplateDTO.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 通知模板DTO
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationTemplateDTO {
/**
* 模板ID
*/
private Long id;
/**
* 模板编码
*/
private String code;
/**
* 模板名称
*/
private String name;
/**
* 模板标题
*/
private String title;
/**
* 模板内容
*/
private String content;
/**
* 模板类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
private Integer type;
/**
* 模板类型描述
*/
private String typeDesc;
/**
* 适用渠道:1-站内信,2-短信,3-邮件,4-推送
*/
private Integer channel;
/**
* 适用渠道描述
*/
private String channelDesc;
/**
* 状态:0-停用,1-启用
*/
private Integer status;
/**
* 状态描述
*/
private String statusDesc;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
/**
* 备注
*/
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationTemplateUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Size;
/**
* 更新通知模板请求
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationTemplateUpdateRequest {
/**
* 模板名称
*/
@Size(max = 100, message = "模板名称长度不能超过100个字符")
private String name;
/**
* 模板标题
*/
@Size(max = 100, message = "模板标题长度不能超过100个字符")
private String title;
/**
* 模板内容
*/
@Size(max = 1000, message = "模板内容长度不能超过1000个字符")
private String content;
/**
* 模板类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
private Integer type;
/**
* 适用渠道:1-站内信,2-短信,3-邮件,4-推送
*/
private Integer channel;
/**
* 状态:0-停用,1-启用
*/
private Integer status;
/**
* 备注
*/
@Size(max = 200, message = "备注长度不能超过200个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\dto\NotificationUpdateRequest.java
package com.campus.express.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Size;
/**
* 更新通知请求
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationUpdateRequest {
/**
* 通知标题
*/
@Size(max = 100, message = "通知标题长度不能超过100个字符")
private String title;
/**
* 通知内容
*/
@Size(max = 500, message = "通知内容长度不能超过500个字符")
private String content;
/**
* 通知类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
private Integer type;
/**
* 通知渠道:1-站内信,2-短信,3-邮件,4-推送
*/
private Integer channel;
/**
* 是否已读:0-未读,1-已读
*/
private Integer readStatus;
/**
* 是否发送成功:0-失败,1-成功
*/
private Integer sendStatus;
/**
* 失败原因
*/
@Size(max = 200, message = "失败原因长度不能超过200个字符")
private String failReason;
/**
* 重试次数
*/
private Integer retryCount;
/**
* 备注
*/
@Size(max = 200, message = "备注长度不能超过200个字符")
private String remark;
}
express-service\src\main\java\com\campus\express\exception\BusinessException.java
package com.campus.express.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 业务异常
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
}
express-service\src\main\java\com\campus\express\exception\ErrorResponse.java
package com.campus.express.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 错误响应类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
/**
* HTTP 状态码
*/
private int status;
/**
* 错误消息
*/
private String message;
/**
* 请求路径
*/
private String path;
/**
* 时间戳
*/
private LocalDateTime timestamp;
}
express-service\src\main\java\com\campus\express\exception\GlobalExceptionHandler.java
package com.campus.express.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 全局异常处理器
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 处理资源未找到异常
*/
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(
ResourceNotFoundException ex, WebRequest request) {
log.error("Resource not found exception: {}", ex.getMessage());
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
/**
* 处理业务异常
*/
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(
BusinessException ex, WebRequest request) {
log.error("Business exception: {}", ex.getMessage());
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
/**
* 处理参数校验异常 (Bean Validation)
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(
MethodArgumentNotValidException ex, WebRequest request) {
log.error("Validation exception: {}", ex.getMessage());
BindingResult bindingResult = ex.getBindingResult();
Map<String, String> errors = new HashMap<>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errors.put(fieldError.getField(), fieldError.getDefaultMessage());
}
String errorMessage = errors.entrySet().stream()
.map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining(", "));
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
"Validation failed: " + errorMessage,
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
/**
* 处理约束违反异常
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleConstraintViolationException(
ConstraintViolationException ex, WebRequest request) {
log.error("Constraint violation exception: {}", ex.getMessage());
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
String errorMessage = violations.stream()
.map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
.collect(Collectors.joining(", "));
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
"Validation failed: " + errorMessage,
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
/**
* 处理数据完整性违反异常
*/
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<ErrorResponse> handleDataIntegrityViolationException(
DataIntegrityViolationException ex, WebRequest request) {
log.error("Data integrity violation exception: {}", ex.getMessage());
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.CONFLICT.value(),
"Database error: " + ex.getMostSpecificCause().getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.CONFLICT);
}
/**
* 处理所有其他异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(
Exception ex, WebRequest request) {
log.error("Global exception: {}", ex.getMessage(), ex);
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"An unexpected error occurred: " + ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
express-service\src\main\java\com\campus\express\exception\ResourceNotFoundException.java
package com.campus.express.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 资源未找到异常
*/
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
express-service\src\main\java\com\campus\express\model\Cabinet.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递柜实体类
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "cabinet")
public class Cabinet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 柜子编号
*/
@NotBlank
@Size(max = 50)
@Column(unique = true, nullable = false)
private String cabinetNumber;
/**
* 柜子名称
*/
@NotBlank
@Size(max = 100)
@Column(nullable = false)
private String name;
/**
* 柜子位置
*/
@NotBlank
@Size(max = 255)
@Column(nullable = false)
private String location;
/**
* 柜子状态:0-停用,1-启用
*/
@NotNull
@Column(nullable = false)
private Integer status;
/**
* 总格口数
*/
@NotNull
@Column(nullable = false)
private Integer totalCells;
/**
* 可用格口数
*/
@NotNull
@Column(nullable = false)
private Integer availableCells;
/**
* 负责人ID
*/
private Long managerId;
/**
* 负责人姓名
*/
@Size(max = 50)
private String managerName;
/**
* 负责人电话
*/
@Size(max = 20)
private String managerPhone;
/**
* 备注
*/
@Size(max = 255)
private String remark;
/**
* 创建时间
*/
@CreationTimestamp
@Column(nullable = false, updatable = false)
private LocalDateTime createdTime;
/**
* 更新时间
*/
@UpdateTimestamp
@Column(nullable = false)
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\CabinetCell.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递柜格口实体类
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "cabinet_cell")
public class CabinetCell {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 柜子ID
*/
@NotNull
@Column(nullable = false)
private Long cabinetId;
/**
* 格口编号
*/
@NotBlank
@Size(max = 20)
@Column(nullable = false)
private String cellNumber;
/**
* 格口大小:0-小,1-中,2-大
*/
@NotNull
@Column(nullable = false)
private Integer size;
/**
* 格口状态:0-空闲,1-占用,2-故障
*/
@NotNull
@Column(nullable = false)
private Integer status;
/**
* 当前存放的快递ID
*/
private Long expressId;
/**
* 存入时间
*/
private LocalDateTime storageTime;
/**
* 取出时间
*/
private LocalDateTime retrievalTime;
/**
* 备注
*/
@Size(max = 255)
private String remark;
/**
* 创建时间
*/
@CreationTimestamp
@Column(nullable = false, updatable = false)
private LocalDateTime createdTime;
/**
* 更新时间
*/
@UpdateTimestamp
@Column(nullable = false)
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\Delivery.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 配送任务实体类
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Delivery {
/**
* 配送任务ID
*/
private Long id;
/**
* 快递ID
*/
private Long expressId;
/**
* 快递单号
*/
private String trackingNumber;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 配送员电话
*/
private String courierPhone;
/**
* 收件人姓名
*/
private String recipientName;
/**
* 收件人电话
*/
private String recipientPhone;
/**
* 收件人地址
*/
private String recipientAddress;
/**
* 配送区域
*/
private String deliveryArea;
/**
* 配送区域代码
*/
private String areaCode;
/**
* 配送路线ID
*/
private Long routeId;
/**
* 配送路线名称
*/
private String routeName;
/**
* 计划配送时间
*/
private LocalDateTime plannedDeliveryTime;
/**
* 实际配送时间
*/
private LocalDateTime actualDeliveryTime;
/**
* 配送完成时间
*/
private LocalDateTime completedTime;
/**
* 配送验证码
*/
private String deliveryCode;
/**
* 配送状态(0-待分配,1-待配送,2-配送中,3-已送达,4-已完成,5-已取消)
*/
private Integer status;
/**
* 配送优先级(0-普通,1-优先,2-加急)
*/
private Integer priority;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 配送距离(米)
*/
private Double distance;
/**
* 预计配送时长(分钟)
*/
private Integer estimatedDuration;
/**
* 实际配送时长(分钟)
*/
private Integer actualDuration;
/**
* 取消原因
*/
private String cancelReason;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\DeliveryArea.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 配送区域实体类
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryArea {
/**
* 配送区域ID
*/
private Long id;
/**
* 区域代码
*/
private String areaCode;
/**
* 区域名称
*/
private String name;
/**
* 父区域ID
*/
private Long parentId;
/**
* 区域级别(1-校区,2-楼栋,3-具体位置)
*/
private Integer level;
/**
* 区域边界(GeoJSON格式存储)
*/
private String boundary;
/**
* 中心点坐标(经度)
*/
private Double centerLongitude;
/**
* 中心点坐标(纬度)
*/
private Double centerLatitude;
/**
* 配送费用
*/
private Double deliveryFee;
/**
* 预计配送时间(分钟)
*/
private Integer estimatedDeliveryTime;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 区域描述
*/
private String description;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\DeliveryRoute.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 配送路线实体类
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeliveryRoute {
/**
* 配送路线ID
*/
private Long id;
/**
* 路线编号
*/
private String routeNumber;
/**
* 路线名称
*/
private String name;
/**
* 起点
*/
private String startPoint;
/**
* 起点坐标(经度)
*/
private Double startLongitude;
/**
* 起点坐标(纬度)
*/
private Double startLatitude;
/**
* 终点
*/
private String endPoint;
/**
* 终点坐标(经度)
*/
private Double endLongitude;
/**
* 终点坐标(纬度)
*/
private Double endLatitude;
/**
* 途经点(JSON格式存储)
*/
private String waypoints;
/**
* 配送区域
*/
private String area;
/**
* 区域代码
*/
private String areaCode;
/**
* 路线距离(米)
*/
private Double distance;
/**
* 预计时长(分钟)
*/
private Integer estimatedDuration;
/**
* 配送员ID
*/
private Long courierId;
/**
* 配送员姓名
*/
private String courierName;
/**
* 状态(0-停用,1-启用)
*/
private Integer status;
/**
* 路线描述
*/
private String description;
/**
* 路线类型(0-步行,1-自行车,2-电动车,3-汽车)
*/
private Integer routeType;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\Express.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递实体类
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "express")
public class Express {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 快递单号
*/
@NotBlank
@Size(max = 50)
@Column(unique = true, nullable = false)
private String trackingNumber;
/**
* 快递公司
*/
@NotBlank
@Size(max = 50)
@Column(nullable = false)
private String company;
/**
* 收件人姓名
*/
@NotBlank
@Size(max = 50)
@Column(nullable = false)
private String recipientName;
/**
* 收件人电话
*/
@NotBlank
@Size(max = 20)
@Column(nullable = false)
private String recipientPhone;
/**
* 收件人地址(宿舍楼栋)
*/
@NotBlank
@Size(max = 255)
@Column(nullable = false)
private String recipientAddress;
/**
* 快递描述
*/
@Size(max = 255)
private String description;
/**
* 快递重量(克)
*/
private Integer weight;
/**
* 快递状态:0-待揽收,1-已揽收,2-配送中,3-已送达,4-已签收,5-异常
*/
@NotNull
@Column(nullable = false)
private Integer status;
/**
* 快递员ID
*/
private Long courierId;
/**
* 用户ID(收件人)
*/
private Long userId;
/**
* 柜子ID
*/
private Long cabinetId;
/**
* 柜子格口号
*/
private String cabinetCell;
/**
* 取件码
*/
@Size(max = 10)
private String pickupCode;
/**
* 揽收时间
*/
private LocalDateTime collectionTime;
/**
* 送达时间
*/
private LocalDateTime deliveryTime;
/**
* 签收时间
*/
private LocalDateTime signTime;
/**
* 备注
*/
@Size(max = 255)
private String remark;
/**
* 创建时间
*/
@CreationTimestamp
@Column(nullable = false, updatable = false)
private LocalDateTime createdTime;
/**
* 更新时间
*/
@UpdateTimestamp
@Column(nullable = false)
private LocalDateTime updatedTime;
}
express-service\src\main\java\com\campus\express\model\ExpressTracking.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 快递跟踪记录实体类
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "express_tracking")
public class ExpressTracking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 快递ID
*/
@NotNull
@Column(nullable = false)
private Long expressId;
/**
* 快递单号
*/
@NotBlank
@Size(max = 50)
@Column(nullable = false)
private String trackingNumber;
/**
* 操作类型:0-创建,1-揽收,2-配送中,3-送达,4-签收,5-异常
*/
@NotNull
@Column(nullable = false)
private Integer operationType;
/**
* 操作描述
*/
@NotBlank
@Size(max = 255)
@Column(nullable = false)
private String description;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人类型:0-系统,1-快递员,2-用户
*/
@NotNull
@Column(nullable = false)
private Integer operatorType;
/**
* 操作人姓名
*/
@Size(max = 50)
private String operatorName;
/**
* 操作地点
*/
@Size(max = 255)
private String location;
/**
* 备注
*/
@Size(max = 255)
private String remark;
/**
* 创建时间(操作时间)
*/
@CreationTimestamp
@Column(nullable = false, updatable = false)
private LocalDateTime createdTime;
}
express-service\src\main\java\com\campus\express\model\Notification.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 通知实体类
*/
@Entity
@Table(name = "notification")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Notification {
/**
* 通知ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 通知标题
*/
@Column(nullable = false, length = 100)
private String title;
/**
* 通知内容
*/
@Column(nullable = false, length = 500)
private String content;
/**
* 通知类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
@Column(nullable = false)
private Integer type;
/**
* 通知渠道:1-站内信,2-短信,3-邮件,4-推送
*/
@Column(nullable = false)
private Integer channel;
/**
* 接收者ID
*/
@Column(nullable = false)
private Long receiverId;
/**
* 接收者类型:1-用户,2-配送员,3-管理员
*/
@Column(nullable = false)
private Integer receiverType;
/**
* 发送者ID
*/
private Long senderId;
/**
* 发送者类型:1-系统,2-用户,3-配送员,4-管理员
*/
private Integer senderType;
/**
* 关联业务ID
*/
private Long businessId;
/**
* 关联业务类型:1-快递,2-配送,3-活动
*/
private Integer businessType;
/**
* 是否已读:0-未读,1-已读
*/
@Column(nullable = false)
private Integer readStatus;
/**
* 是否发送成功:0-失败,1-成功
*/
@Column(nullable = false)
private Integer sendStatus;
/**
* 失败原因
*/
@Column(length = 200)
private String failReason;
/**
* 重试次数
*/
private Integer retryCount;
/**
* 下次重试时间
*/
private LocalDateTime nextRetryTime;
/**
* 创建时间
*/
@Column(nullable = false)
private LocalDateTime createdTime;
/**
* 更新时间
*/
@Column(nullable = false)
private LocalDateTime updatedTime;
/**
* 备注
*/
@Column(length = 200)
private String remark;
}
express-service\src\main\java\com\campus\express\model\NotificationTemplate.java
package com.campus.express.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 通知模板实体类
*/
@Entity
@Table(name = "notification_template")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationTemplate {
/**
* 模板ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 模板编码
*/
@Column(nullable = false, unique = true, length = 50)
private String code;
/**
* 模板名称
*/
@Column(nullable = false, length = 100)
private String name;
/**
* 模板标题
*/
@Column(nullable = false, length = 100)
private String title;
/**
* 模板内容
*/
@Column(nullable = false, length = 1000)
private String content;
/**
* 模板类型:1-系统通知,2-快递通知,3-配送通知,4-活动通知
*/
@Column(nullable = false)
private Integer type;
/**
* 适用渠道:1-站内信,2-短信,3-邮件,4-推送
*/
@Column(nullable = false)
private Integer channel;
/**
* 状态:0-停用,1-启用
*/
@Column(nullable = false)
private Integer status;
/**
* 创建时间
*/
@Column(nullable = false)
private LocalDateTime createdTime;
/**
* 更新时间
*/
@Column(nullable = false)
private LocalDateTime updatedTime;
/**
* 备注
*/
@Column(length = 200)
private String remark;
}
express-service\src\main\java\com\campus\express\repository\CabinetCellRepository.java
package com.campus.express.repository;
import com.campus.express.model.CabinetCell;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 快递柜格口数据访问接口
*/
@Repository
public interface CabinetCellRepository extends JpaRepository<CabinetCell, Long>, JpaSpecificationExecutor<CabinetCell> {
/**
* 根据柜子ID和格口编号查询格口
*
* @param cabinetId 柜子ID
* @param cellNumber 格口编号
* @return 格口信息
*/
Optional<CabinetCell> findByCabinetIdAndCellNumber(Long cabinetId, String cellNumber);
/**
* 根据柜子ID查询格口列表
*
* @param cabinetId 柜子ID
* @return 格口列表
*/
List<CabinetCell> findByCabinetId(Long cabinetId);
/**
* 根据柜子ID和状态查询格口列表
*
* @param cabinetId 柜子ID
* @param status 状态
* @return 格口列表
*/
List<CabinetCell> findByCabinetIdAndStatus(Long cabinetId, Integer status);
/**
* 根据快递ID查询格口
*
* @param expressId 快递ID
* @return 格口信息
*/
Optional<CabinetCell> findByExpressId(Long expressId);
/**
* 根据柜子ID分页查询格口列表
*
* @param cabinetId 柜子ID
* @param pageable 分页参数
* @return 格口分页列表
*/
Page<CabinetCell> findByCabinetId(Long cabinetId, Pageable pageable);
/**
* 根据柜子ID和格口大小查询空闲格口列表
*
* @param cabinetId 柜子ID
* @param size 格口大小
* @param status 格口状态(0-空闲)
* @return 格口列表
*/
List<CabinetCell> findByCabinetIdAndSizeAndStatus(Long cabinetId, Integer size, Integer status);
/**
* 统计柜子中指定状态的格口数量
*
* @param cabinetId 柜子ID
* @param status 状态
* @return 格口数量
*/
long countByCabinetIdAndStatus(Long cabinetId, Integer status);
/**
* 统计柜子中指定大小的格口数量
*
* @param cabinetId 柜子ID
* @param size 格口大小
* @return 格口数量
*/
long countByCabinetIdAndSize(Long cabinetId, Integer size);
/**
* 查询指定柜子中的空闲格口数量
*
* @param cabinetId 柜子ID
* @param status 状态(0-空闲)
* @return 空闲格口数量
*/
@Query("SELECT COUNT(c) FROM CabinetCell c WHERE c.cabinetId = :cabinetId AND c.status = :status")
long countAvailableCells(@Param("cabinetId") Long cabinetId, @Param("status") Integer status);
}
express-service\src\main\java\com\campus\express\repository\CabinetRepository.java
package com.campus.express.repository;
import com.campus.express.model.Cabinet;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 快递柜数据访问接口
*/
@Repository
public interface CabinetRepository extends JpaRepository<Cabinet, Long>, JpaSpecificationExecutor<Cabinet> {
/**
* 根据柜子编号查询柜子
*
* @param cabinetNumber 柜子编号
* @return 柜子信息
*/
Optional<Cabinet> findByCabinetNumber(String cabinetNumber);
/**
* 根据柜子名称或位置模糊查询柜子列表
*
* @param keyword 关键字
* @param pageable 分页参数
* @return 柜子分页列表
*/
@Query("SELECT c FROM Cabinet c WHERE c.name LIKE %:keyword% OR c.location LIKE %:keyword%")
Page<Cabinet> findByNameOrLocationContaining(@Param("keyword") String keyword, Pageable pageable);
/**
* 根据状态查询柜子列表
*
* @param status 状态
* @param pageable 分页参数
* @return 柜子分页列表
*/
Page<Cabinet> findByStatus(Integer status, Pageable pageable);
/**
* 根据负责人ID查询柜子列表
*
* @param managerId 负责人ID
* @return 柜子列表
*/
List<Cabinet> findByManagerId(Long managerId);
/**
* 查询可用格口数大于0的柜子列表
*
* @param pageable 分页参数
* @return 柜子分页列表
*/
Page<Cabinet> findByAvailableCellsGreaterThan(Integer availableCells, Pageable pageable);
/**
* 查询指定位置的柜子列表
*
* @param location 位置
* @param pageable 分页参数
* @return 柜子分页列表
*/
Page<Cabinet> findByLocationContaining(String location, Pageable pageable);
/**
* 统计指定状态的柜子数量
*
* @param status 状态
* @return 柜子数量
*/
long countByStatus(Integer status);
/**
* 统计指定负责人的柜子数量
*
* @param managerId 负责人ID
* @return 柜子数量
*/
long countByManagerId(Long managerId);
}
express-service\src\main\java\com\campus\express\repository\DeliveryAreaRepository.java
package com.campus.express.repository;
import com.campus.express.model.DeliveryArea;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 配送区域数据访问接口
*/
@Repository
public interface DeliveryAreaRepository extends JpaRepository<DeliveryArea, Long> {
/**
* 根据区域代码查询配送区域
*
* @param areaCode 区域代码
* @return 配送区域
*/
Optional<DeliveryArea> findByAreaCode(String areaCode);
/**
* 根据区域名称模糊查询配送区域分页列表
*
* @param name 区域名称关键字
* @param pageable 分页参数
* @return 配送区域分页列表
*/
Page<DeliveryArea> findByNameContaining(String name, Pageable pageable);
/**
* 根据状态查询配送区域分页列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送区域分页列表
*/
Page<DeliveryArea> findByStatus(Integer status, Pageable pageable);
/**
* 根据区域级别查询配送区域列表
*
* @param level 区域级别
* @return 配送区域列表
*/
List<DeliveryArea> findByLevel(Integer level);
/**
* 根据父区域ID查询子区域列表
*
* @param parentId 父区域ID
* @return 子区域列表
*/
List<DeliveryArea> findByParentId(Long parentId);
/**
* 根据父区域ID和状态查询子区域列表
*
* @param parentId 父区域ID
* @param status 状态
* @return 子区域列表
*/
List<DeliveryArea> findByParentIdAndStatus(Long parentId, Integer status);
/**
* 统计指定状态的配送区域数量
*
* @param status 状态
* @return 配送区域数量
*/
long countByStatus(Integer status);
/**
* 统计指定级别的配送区域数量
*
* @param level 区域级别
* @return 配送区域数量
*/
long countByLevel(Integer level);
/**
* 统计指定父区域的子区域数量
*
* @param parentId 父区域ID
* @return 子区域数量
*/
long countByParentId(Long parentId);
}
express-service\src\main\java\com\campus\express\repository\DeliveryRepository.java
package com.campus.express.repository;
import com.campus.express.model.Delivery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.Optional;
/**
* 配送任务数据访问接口
*/
@Repository
public interface DeliveryRepository extends JpaRepository<Delivery, Long> {
/**
* 根据快递ID查询配送任务
*
* @param expressId 快递ID
* @return 配送任务
*/
Optional<Delivery> findByExpressId(Long expressId);
/**
* 根据配送员ID分页查询配送任务列表
*
* @param courierId 配送员ID
* @param pageable 分页参数
* @return 配送任务分页列表
*/
Page<Delivery> findByCourierId(Long courierId, Pageable pageable);
/**
* 根据状态分页查询配送任务列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送任务分页列表
*/
Page<Delivery> findByStatus(Integer status, Pageable pageable);
/**
* 根据配送区域分页查询配送任务列表
*
* @param area 配送区域
* @param pageable 分页参数
* @return 配送任务分页列表
*/
Page<Delivery> findByDeliveryAreaContaining(String area, Pageable pageable);
/**
* 根据创建时间范围分页查询配送任务列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 配送任务分页列表
*/
Page<Delivery> findByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 根据计划配送时间范围分页查询配送任务列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 配送任务分页列表
*/
Page<Delivery> findByPlannedDeliveryTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 统计配送员的配送任务数量
*
* @param courierId 配送员ID
* @return 配送任务数量
*/
long countByCourierId(Long courierId);
/**
* 统计指定状态的配送任务数量
*
* @param status 状态
* @return 配送任务数量
*/
long countByStatus(Integer status);
/**
* 统计指定区域的配送任务数量
*
* @param area 配送区域
* @return 配送任务数量
*/
long countByDeliveryAreaContaining(String area);
/**
* 统计指定时间范围内的配送任务数量
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 配送任务数量
*/
long countByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
}
express-service\src\main\java\com\campus\express\repository\DeliveryRouteRepository.java
package com.campus.express.repository;
import com.campus.express.model.DeliveryRoute;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 配送路线数据访问接口
*/
@Repository
public interface DeliveryRouteRepository extends JpaRepository<DeliveryRoute, Long> {
/**
* 根据路线编号查询配送路线
*
* @param routeNumber 路线编号
* @return 配送路线
*/
Optional<DeliveryRoute> findByRouteNumber(String routeNumber);
/**
* 根据名称模糊查询配送路线分页列表
*
* @param name 名称关键字
* @param pageable 分页参数
* @return 配送路线分页列表
*/
Page<DeliveryRoute> findByNameContaining(String name, Pageable pageable);
/**
* 根据状态查询配送路线分页列表
*
* @param status 状态
* @param pageable 分页参数
* @return 配送路线分页列表
*/
Page<DeliveryRoute> findByStatus(Integer status, Pageable pageable);
/**
* 根据区域查询配送路线列表
*
* @param area 区域
* @return 配送路线列表
*/
List<DeliveryRoute> findByArea(String area);
/**
* 根据配送员ID查询配送路线列表
*
* @param courierId 配送员ID
* @return 配送路线列表
*/
List<DeliveryRoute> findByCourierId(Long courierId);
/**
* 根据区域和状态查询配送路线列表
*
* @param area 区域
* @param status 状态
* @return 配送路线列表
*/
List<DeliveryRoute> findByAreaAndStatus(String area, Integer status);
/**
* 统计指定状态的配送路线数量
*
* @param status 状态
* @return 配送路线数量
*/
long countByStatus(Integer status);
/**
* 统计指定区域的配送路线数量
*
* @param area 区域
* @return 配送路线数量
*/
long countByArea(String area);
/**
* 统计指定配送员的配送路线数量
*
* @param courierId 配送员ID
* @return 配送路线数量
*/
long countByCourierId(Long courierId);
}
express-service\src\main\java\com\campus\express\repository\ExpressRepository.java
package com.campus.express.repository;
import com.campus.express.model.Express;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 快递数据访问接口
*/
@Repository
public interface ExpressRepository extends JpaRepository<Express, Long>, JpaSpecificationExecutor<Express> {
/**
* 根据快递单号查询快递
*
* @param trackingNumber 快递单号
* @return 快递信息
*/
Optional<Express> findByTrackingNumber(String trackingNumber);
/**
* 根据用户ID查询快递列表
*
* @param userId 用户ID
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByUserId(Long userId, Pageable pageable);
/**
* 根据快递员ID查询快递列表
*
* @param courierId 快递员ID
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCourierId(Long courierId, Pageable pageable);
/**
* 根据柜子ID查询快递列表
*
* @param cabinetId 柜子ID
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCabinetId(Long cabinetId, Pageable pageable);
/**
* 根据状态查询快递列表
*
* @param status 状态
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByStatus(Integer status, Pageable pageable);
/**
* 根据收件人姓名或电话模糊查询快递列表
*
* @param keyword 关键字
* @param pageable 分页参数
* @return 快递分页列表
*/
@Query("SELECT e FROM Express e WHERE e.recipientName LIKE %:keyword% OR e.recipientPhone LIKE %:keyword%")
Page<Express> findByRecipientNameOrPhoneContaining(@Param("keyword") String keyword, Pageable pageable);
/**
* 根据快递公司查询快递列表
*
* @param company 快递公司
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCompany(String company, Pageable pageable);
/**
* 统计用户的快递数量
*
* @param userId 用户ID
* @return 快递数量
*/
long countByUserId(Long userId);
/**
* 统计快递员的快递数量
*
* @param courierId 快递员ID
* @return 快递数量
*/
long countByCourierId(Long courierId);
/**
* 统计指定状态的快递数量
*
* @param status 状态
* @return 快递数量
*/
long countByStatus(Integer status);
/**
* 查询指定时间范围内创建的快递列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 查询指定时间范围内送达的快递列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByDeliveryTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 查询指定时间范围内签收的快递列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findBySignTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 查询未分配快递员的快递列表
*
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCourierIdIsNull(Pageable pageable);
/**
* 查询未分配柜子的快递列表
*
* @param pageable 分页参数
* @return 快递分页列表
*/
Page<Express> findByCabinetIdIsNull(Pageable pageable);
}
express-service\src\main\java\com\campus\express\repository\ExpressTrackingRepository.java
package com.campus.express.repository;
import com.campus.express.model.ExpressTracking;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
/**
* 快递跟踪记录数据访问接口
*/
@Repository
public interface ExpressTrackingRepository extends JpaRepository<ExpressTracking, Long>, JpaSpecificationExecutor<ExpressTracking> {
/**
* 根据快递ID查询跟踪记录列表
*
* @param expressId 快递ID
* @return 跟踪记录列表
*/
List<ExpressTracking> findByExpressIdOrderByCreatedTimeDesc(Long expressId);
/**
* 根据快递单号查询跟踪记录列表
*
* @param trackingNumber 快递单号
* @return 跟踪记录列表
*/
List<ExpressTracking> findByTrackingNumberOrderByCreatedTimeDesc(String trackingNumber);
/**
* 根据操作类型查询跟踪记录列表
*
* @param operationType 操作类型
* @param pageable 分页参数
* @return 跟踪记录分页列表
*/
Page<ExpressTracking> findByOperationType(Integer operationType, Pageable pageable);
/**
* 根据操作人ID查询跟踪记录列表
*
* @param operatorId 操作人ID
* @param pageable 分页参数
* @return 跟踪记录分页列表
*/
Page<ExpressTracking> findByOperatorId(Long operatorId, Pageable pageable);
/**
* 根据操作人类型查询跟踪记录列表
*
* @param operatorType 操作人类型
* @param pageable 分页参数
* @return 跟踪记录分页列表
*/
Page<ExpressTracking> findByOperatorType(Integer operatorType, Pageable pageable);
/**
* 查询指定时间范围内的跟踪记录列表
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param pageable 分页参数
* @return 跟踪记录分页列表
*/
Page<ExpressTracking> findByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
/**
* 根据快递ID和操作类型查询跟踪记录
*
* @param expressId 快递ID
* @param operationType 操作类型
* @return 跟踪记录列表
*/
List<ExpressTracking> findByExpressIdAndOperationType(Long expressId, Integer operationType);
/**
* 统计指定快递的跟踪记录数量
*
* @param expressId 快递ID
* @return 跟踪记录数量
*/
long countByExpressId(Long expressId);
/**
* 统计指定操作类型的跟踪记录数量
*
* @param operationType 操作类型
* @return 跟踪记录数量
*/
long countByOperationType(Integer operationType);
}