以下是结合Java最新技术的实操内容,以"学生成绩管理系统"为例,展示如何运用Java 17+特性与现代开发实践:
技术栈:
特性亮点:
使用Record类替代传统的POJO,自动生成构造器、getter和equals()方法:
// 学生实体
public record Student(
@Id UUID id, // 使用UUID作为主键
String name,
Integer age,
Grade grade, // 枚举类型:LOW/MEDIUM/HIGH
List<CourseScore> scores // 嵌套记录
) {}
// 课程成绩记录
public record CourseScore(
String courseName,
Double score
) {}
// 成绩统计结果
public record ScoreSummary(
String studentName,
Double averageScore,
Grade finalGrade
) {}
使用非阻塞数据库驱动实现异步数据访问:
// StudentRepository.java
public interface StudentRepository extends ReactiveCrudRepository<Student, UUID> {
// 使用方法名自动生成查询
Flux<Student> findByGrade(Grade grade);
// 使用R2DBC原生SQL
@Query("SELECT * FROM students WHERE average_score > :threshold")
Flux<Student> findHighPerformers(double threshold);
}
// StudentService.java
@Service
public class StudentService {
private final StudentRepository repository;
public Mono<ScoreSummary> calculateSummary(UUID studentId) {
return repository.findById(studentId)
.flatMap(student -> {
double avgScore = student.scores().stream()
.mapToDouble(CourseScore::score)
.average()
.orElse(0.0);
Grade finalGrade = switch ((int) (avgScore / 10)) {
case 9, 10 -> Grade.HIGH;
case 7, 8 -> Grade.MEDIUM;
default -> Grade.LOW;
};
return Mono.just(new ScoreSummary(
student.name(), avgScore, finalGrade
));
});
}
}
构建响应式API端点,支持高并发请求:
// StudentController.java
@RestController
@RequestMapping("/api/students")
public class StudentController {
private final StudentService service;
@GetMapping
public Flux<Student> getAllStudents() {
return service.getAllStudents();
}
@GetMapping("/{id}/summary")
public Mono<ResponseEntity<ScoreSummary>> getSummary(@PathVariable UUID id) {
return service.calculateSummary(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<Student> createStudent(@RequestBody Student student) {
return service.createStudent(student);
}
}
优化异常处理与类型转换:
public String formatScore(Object score) {
return switch (score) {
case null -> "N/A";
case Double d -> String.format("%.2f", d);
case Integer i -> i.toString();
case CourseScore cs -> cs.courseName() + ": " + cs.score();
default -> score.toString();
};
}
// 多异常处理
try {
// 业务逻辑
} catch (Exception e) {
if (e instanceof IllegalArgumentException | e instanceof IllegalStateException) {
log.error("业务异常: {}", e.getMessage());
} else if (e instanceof DataAccessException dae) {
log.error("数据库异常: {}", dae.getRootCause().getMessage());
}
}
批量处理学生数据:
public List<ScoreSummary> analyzeClassPerformance(List<Student> students) {
return students.stream()
.map(student -> {
double avg = student.scores().stream()
.mapToDouble(CourseScore::score)
.average()
.orElse(0.0);
return new ScoreSummary(student.name(), avg,
avg >= 80 ? Grade.HIGH : avg >= 60 ? Grade.MEDIUM : Grade.LOW);
})
.sorted(Comparator.comparingDouble(ScoreSummary::averageScore).reversed())
.toList();
}
使用WebClient消费第三方API(如成绩分析服务):
public Mono<AnalysisReport> fetchExternalAnalysis(UUID studentId) {
WebClient client = WebClient.create("https://api.example.com/analysis");
return client.get()
.uri(uriBuilder -> uriBuilder
.path("/students/{id}/report")
.queryParam("format", "detailed")
.build(studentId))
.retrieve()
.bodyToMono(AnalysisReport.class)
.timeout(Duration.ofSeconds(5))
.retry(3)
.onErrorResume(WebClientResponseException.class, e ->
Mono.just(new AnalysisReport(studentId, "ANALYSIS_FAILED", Collections.emptyMap()))
);
}
# 使用官方Java 17基础镜像
FROM openjdk:17-jdk-slim
# 设置工作目录
WORKDIR /app
# 复制Maven构建产物
COPY target/student-management-0.0.1-SNAPSHOT.jar app.jar
# 暴露应用端口
EXPOSE 8080
# 启动应用
CMD ["java", "-jar", "app.jar"]
version: '3.8'
services:
student-service:
build: .
ports:
- "8080:8080"
depends_on:
- postgres
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/student_db
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: password
SPRING_R2DBC_URL: r2dbc:postgresql://postgres:5432/student_db
postgres:
image: postgres:14-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
environment:
POSTGRES_DB: student_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
postgres-data:
@SpringBootTest
class StudentServiceTest {
@MockBean
private StudentRepository repository;
@Autowired
private StudentService service;
@Test
void calculateSummary_ValidStudent_ReturnsSummary() {
// 准备测试数据
UUID studentId = UUID.randomUUID();
Student mockStudent = new Student(
studentId, "张三", 20, Grade.MEDIUM,
List.of(new CourseScore("数学", 85.0), new CourseScore("英语", 90.0))
);
// 设置模拟行为
when(repository.findById(studentId)).thenReturn(Mono.just(mockStudent));
// 执行测试
Mono<ScoreSummary> result = service.calculateSummary(studentId);
// 验证结果
StepVerifier.create(result)
.expectNextMatches(summary ->
summary.studentName().equals("张三") &&
summary.averageScore() == 87.5 &&
summary.finalGrade() == Grade.HIGH
)
.verifyComplete();
}
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
class StudentControllerIntegrationTest {
@Container
static PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:14-alpine")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void registerDataSourceProperties(DynamicPropertyRegistry registry) {
registry.add("spring.r2dbc.url", () ->
"r2dbc:postgresql://" + postgresContainer.getHost() +
":" + postgresContainer.getFirstMappedPort() +
"/" + postgresContainer.getDatabaseName()
);
registry.add("spring.r2dbc.username", postgresContainer::getUsername);
registry.add("spring.r2dbc.password", postgresContainer::getPassword);
}
// 测试代码...
}
使用@Async
注解实现方法异步执行:
@Service
public class ReportService {
@Async("reportExecutor")
public CompletableFuture<byte[]> generateDetailedReport(UUID studentId) {
// 耗时操作:生成PDF报告
return CompletableFuture.completedFuture(generatePdf(studentId));
}
@Bean(name = "reportExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("report-");
executor.initialize();
return executor;
}
}
使用Spring Cache提升数据访问速度:
@Service
public class StudentService {
@Cacheable("students")
public Mono<Student> getStudentById(UUID id) {
return repository.findById(id);
}
@CacheEvict(value = "students", key = "#student.id")
public Mono<Student> updateStudent(Student student) {
return repository.save(student);
}
}
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
}
}
使用Jakarta Bean Validation注解:
public record NewStudentRequest(
@NotBlank(message = "姓名不能为空")
String name,
@Min(value = 1, message = "年龄不能小于1")
@Max(value = 100, message = "年龄不能大于100")
Integer age,
@NotEmpty(message = "至少需要一门课程成绩")
List<CourseScore> scores
) {}
通过这个完整的"学生成绩管理系统"实例,我们实践了Java 17+的核心特性,包括Record类、模式匹配、响应式编程等。同时展示了如何结合Spring Boot生态构建现代化应用,涵盖数据访问、REST API设计、容器化部署、测试与监控等全流程。这些技术代表了Java生态的最新发展方向,能够显著提升开发效率与系统性能。
Java 17,Java 17 特性,现代开发实践,Java 新版本特性,Java 开发指南,Java 17 及以上版本,Java 开发实践,Java 应用技巧,Java 编程特性,Java 17 实践指南,现代 Java 开发,Java 版本特性,Java 开发技巧,Java 17 应用,Java 实践教程
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。