
随着远程协作的普及,任务管理系统成为团队高效协作的核心工具。本项目将采用2024-2025年主流的Java技术栈,开发一个功能完善的在线任务管理系统,包含任务创建、分配、跟踪、统计等核心功能。
技术栈选择:
选择理由:Spring Boot 3.2.x充分利用了Java 21的虚拟线程特性,能显著提升系统吞吐量;PostgreSQL相比MySQL提供了更丰富的数据类型和更强大的查询能力;React 18的并发渲染特性提升了前端交互体验。
采用分层架构设计,具体如下:
核心模块划分:
首先使用Spring Initializr创建项目,添加必要依赖:
<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-security</artifactId>
</dependency>
<!-- 数据访问 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- JWT支持 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- API文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
<!-- 缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>配置文件(application.yml):
spring:
datasource:
url: jdbc:postgresql://localhost:5432/task_management
username: postgres
password: password
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
data:
redis:
host: localhost
port: 6379
# JWT配置
jwt:
secret: your-secret-key-with-at-least-256-bits-length
expiration: 86400000 # 24小时
# 服务器配置
server:
port: 8080
tomcat:
threads:
virtual:
enabled: true # 启用虚拟线程以任务(Task)实体为例,使用JPA注解定义:
@Entity
@Table(name = "tasks")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(length = 1000)
private String description;
@Enumerated(EnumType.STRING)
private TaskStatus status;
@Column(name = "due_date")
private LocalDateTime dueDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assignee_id")
private User assignee;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id")
private Project project;
@Column(name = "priority")
@Enumerated(EnumType.STRING)
private Priority priority;
@Column(name = "created_at")
@CreationTimestamp
private LocalDateTime createdAt;
@Column(name = "updated_at")
@UpdateTimestamp
private LocalDateTime updatedAt;
// 任务标签,使用PostgreSQL的数组类型
@Column(name = "tags", columnDefinition = "text[]")
private String[] tags;
}
// 任务状态枚举
public enum TaskStatus {
TODO, IN_PROGRESS, REVIEW, COMPLETED, CANCELLED
}
// 优先级枚举
public enum Priority {
LOW, MEDIUM, HIGH, URGENT
}上述代码定义了任务的基本属性,包括标题、描述、状态、截止日期等。特别注意:
创建任务DTO用于数据传输:
@Data
public class TaskDTO {
private Long id;
private String title;
private String description;
private TaskStatus status;
private LocalDateTime dueDate;
private Long assigneeId;
private String assigneeName;
private Long projectId;
private Priority priority;
private String[] tags;
private LocalDateTime createdAt;
}任务仓库接口:
public interface TaskRepository extends JpaRepository<Task, Long> {
// 查找指定项目的任务
List<Task> findByProjectId(Long projectId, Pageable pageable);
// 查找指定负责人的任务
List<Task> findByAssigneeId(Long userId, Pageable pageable);
// 根据状态查找任务
List<Task> findByStatus(TaskStatus status, Pageable pageable);
// 全文搜索(使用PostgreSQL的全文搜索功能)
@Query(value = "SELECT * FROM tasks WHERE to_tsvector('english', title || ' ' || description) @@ plainto_tsquery('english', :query)", nativeQuery = true)
List<Task> fullTextSearch(@Param("query") String query, Pageable pageable);
}任务服务实现:
@Service
@RequiredArgsConstructor
@Transactional
public class TaskServiceImpl implements TaskService {
private final TaskRepository taskRepository;
private final UserRepository userRepository;
private final ProjectRepository projectRepository;
private final ModelMapper modelMapper;
@Override
public TaskDTO createTask(TaskCreateRequest request, Long creatorId) {
// 验证负责人是否存在
User assignee = userRepository.findById(request.getAssigneeId())
.orElseThrow(() -> new ResourceNotFoundException("Assignee not found"));
// 验证项目是否存在
Project project = projectRepository.findById(request.getProjectId())
.orElseThrow(() -> new ResourceNotFoundException("Project not found"));
// 构建任务实体
Task task = Task.builder()
.title(request.getTitle())
.description(request.getDescription())
.status(TaskStatus.TODO)
.dueDate(request.getDueDate())
.assignee(assignee)
.project(project)
.priority(request.getPriority())
.tags(request.getTags())
.build();
// 保存任务
Task savedTask = taskRepository.save(task);
// 转换为DTO并返回
return modelMapper.map(savedTask, TaskDTO.class);
}
@Override
@Transactional(readOnly = true)
public Page<TaskDTO> getTasksByProject(Long projectId, int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("dueDate").ascending());
Page<Task> tasks = taskRepository.findByProjectId(projectId, pageable);
return tasks.map(task -> {
TaskDTO dto = modelMapper.map(task, TaskDTO.class);
dto.setAssigneeName(task.getAssignee().getName());
return dto;
});
}
@Override
public TaskDTO updateTaskStatus(Long taskId, TaskStatus status) {
Task task = taskRepository.findById(taskId)
.orElseThrow(() -> new ResourceNotFoundException("Task not found"));
task.setStatus(status);
Task updatedTask = taskRepository.save(task);
return modelMapper.map(updatedTask, TaskDTO.class);
}
// 其他方法实现...
}上述服务实现了任务的创建、查询和状态更新等核心功能。特别注意:
任务控制器:
@RestController
@RequestMapping("/api/v1/tasks")
@RequiredArgsConstructor
@Tag(name = "Task Management", description = "APIs for task management")
public class TaskController {
private final TaskService taskService;
@PostMapping
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
@Operation(summary = "Create new task")
public ResponseEntity<TaskDTO> createTask(
@RequestBody @Valid TaskCreateRequest request,
Authentication authentication) {
Long userId = ((UserDetailsImpl) authentication.getPrincipal()).getId();
TaskDTO taskDTO = taskService.createTask(request, userId);
return new ResponseEntity<>(taskDTO, HttpStatus.CREATED);
}
@GetMapping("/project/{projectId}")
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
@Operation(summary = "Get tasks by project ID")
public ResponseEntity<Page<TaskDTO>> getTasksByProject(
@PathVariable Long projectId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page<TaskDTO> tasks = taskService.getTasksByProject(projectId, page, size);
return ResponseEntity.ok(tasks);
}
@PatchMapping("/{taskId}/status")
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
@Operation(summary = "Update task status")
public ResponseEntity<TaskDTO> updateTaskStatus(
@PathVariable Long taskId,
@RequestBody @Valid TaskStatusUpdateRequest request) {
TaskDTO taskDTO = taskService.updateTaskStatus(taskId, request.getStatus());
return ResponseEntity.ok(taskDTO);
}
// 其他端点...
}控制器层特点:
为提高系统性能,对频繁访问的数据实施缓存:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
// 默认缓存配置
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 默认过期时间10分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
// 针对不同缓存设置不同的过期时间
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
cacheConfigurations.put("tasks", defaultCacheConfig.entryTtl(Duration.ofMinutes(5)));
cacheConfigurations.put("projects", defaultCacheConfig.entryTtl(Duration.ofHours(1)));
cacheConfigurations.put("users", defaultCacheConfig.entryTtl(Duration.ofHours(2)));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(cacheConfigurations)
.build();
}
}在服务方法中使用缓存:
@Override
@Cacheable(value = "tasks", key = "#taskId")
@Transactional(readOnly = true)
public TaskDTO getTaskById(Long taskId) {
Task task = taskRepository.findById(taskId)
.orElseThrow(() -> new ResourceNotFoundException("Task not found"));
TaskDTO dto = modelMapper.map(task, TaskDTO.class);
dto.setAssigneeName(task.getAssignee().getName());
return dto;
}
@Override
@CacheEvict(value = "tasks", key = "#taskId")
public void deleteTask(Long taskId) {
if (!taskRepository.existsById(taskId)) {
throw new ResourceNotFoundException("Task not found");
}
taskRepository.deleteById(taskId);
}
@Override
@Caching(
evict = @CacheEvict(value = "tasks", key = "#taskId"),
put = @CachePut(value = "tasks", key = "#result.id")
)
public TaskDTO updateTask(Long taskId, TaskUpdateRequest request) {
// 更新任务逻辑...
}缓存策略说明:
// taskApi.ts
import axios from 'axios';
import { Task, TaskCreateRequest, TaskStatus } from '../types/task';
const API_BASE_URL = 'http://localhost:8080/api/v1';
// 创建任务
export const createTask = async (taskData: TaskCreateRequest): Promise<Task> => {
const response = await axios.post<Task>(`${API_BASE_URL}/tasks`, taskData, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
return response.data;
};
// 获取项目任务列表
export const getTasksByProject = async (projectId: number, page: number = 0, size: number = 10) => {
const response = await axios.get(`${API_BASE_URL}/tasks/project/${projectId}`, {
params: { page, size },
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
return response.data;
};
// 更新任务状态
export const updateTaskStatus = async (taskId: number, status: TaskStatus): Promise<Task> => {
const response = await axios.patch<Task>(`${API_BASE_URL}/tasks/${taskId}/status`,
{ status },
{
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
}
);
return response.data;
};Dockerfile:
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/task-management-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
# 使用虚拟线程
ENTRYPOINT ["java", "--enable-preview", "-jar", "app.jar"]docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
- redis
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/task_management
- SPRING_DATASOURCE_USERNAME=postgres
- SPRING_DATASOURCE_PASSWORD=password
- SPRING_REDIS_HOST=redis
- SPRING_REDIS_PORT=6379
restart: always
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_DB=task_management
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres-data:/var/lib/postgresql/data
restart: always
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: always
volumes:
postgres-data:
redis-data:本项目基于最新的Java技术栈实现了一个功能完善的在线任务管理系统,涵盖了从项目初始化、数据模型设计到核心功能实现、缓存策略、前端集成和部署的完整流程。通过本项目的实践,读者可以掌握:
实际开发中,还需要根据具体业务需求进行功能扩展和性能优化,同时注重代码质量和安全性。希望本教程能为读者的Java项目开发提供有价值的参考。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。