## 5. 基于Spring框架的后端应用开发 ### 5.1 Java基础增强(掌握) #### 5.1.1 Java异常处理 > `异常`是在程序执行过程中发生的任何非正常情况或问题。它们打断了正常的程序流程,需要特别处理来确保程序的健壮性和可靠性。 **java异常类的继承关系**: ![](./resources/exception-hierarchy.png) `Throwable`类是所有异常的超类,它不能被实例化。`Throwable`有两个重要的子类:`Exception`和`Error`。 - Throwable: 所有错误和异常的超类。 - Error: 表示合理的应用不应该试图捕获的严重问题。例如,内存溢出等。 - Exception: 表示合理的应用可能想要捕获的条件。异常通常由编程错误之外的情况引发。 **非检查异常 (Unchecked Exceptions)** - 包括Error和RuntimeException及其子类。 - 这些异常通常是由编程错误引起的,如数组索引越界或空指针引用。 - 编译器不会强制要求处理这些异常,因此称为“非检查”。 **检查异常 (Checked Exceptions)** - 除了Error和RuntimeException之外的所有其他异常。 - 这些异常是程序应该能够预料到并需要处理的,如文件未找到异常。 - 编译器要求要么在调用方法时处理这些异常(使用try-catch块),要么在方法声明中声明它们可能会抛出这些异常(使用throws关键字)。 **Java异常使用** **关键词:** * try: 用于标记可能抛出异常的代码块。 * catch: 用于捕获并处理try块中抛出的异常。 * finally: 不管是否有异常发生,finally块中的代码总会被执行。 * throw: 用于抛出一个新的异常实例。 * throws: 用于声明一个方法可能会抛出的异常类型。 **自定义异常类** 创建自定义异常类时,可以根据是否需要强制性地进行异常处理来选择继承Exception还是RuntimeException。 - 继承Exception(检查异常): 如果希望强制用户处理这个异常,可以选择继承Exception。 - 继承RuntimeException(非检查异常): 如果异常是由于编程错误引起的,或者不需要强制处理,可以继承RuntimeException。 ### 5.1.2 注解(掌握) > 注解 (Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 > > ——摘自百度百科 > 元数据: 说明数据的数据 #### 注解定义的语法 ```java public @interface 注解名称 { // 属性列表; } ``` #### 类型 - **元注解**:用于注解其他注解的注解,如 `@Retention` 和 `@Target`。 - **内置注解**:Java 平台提供的注解,如 `@Override`、`@Deprecated`、`@SuppressWarnings` 等。 - **自定义注解**:我们自己编写的注解。很多第三方框架通过提供自定义注解来简化实现,例如 Spring 框架提供了 `@Autowired`、`@RequestMapping` 等。 #### 使用场景 - **为框架提供元数据**:例如 Spring 框架使用注解来标记组件。 - **用于代码生成**:例如 Lombok 库使用注解来自动生成模板化的代码。 - **用于编译时处理**:例如通过注解来检查代码中的潜在错误。 如果说注释是写给人看的,那么注解就是写给程序看的。它更像一个标签,贴在一个类、一个方法或者字段上。它的目的是为当前读取该注解的程序提供判断依据及少量附加信息。 #### 使用位置 在实际开发中,注解可以出现在类、方法、成员变量、方法参数等多个位置。 #### 级别 注解与类、接口、枚举处于同一级别。注解的本质类似于 `@interface`,与 `interface` 相似,但用于提供元数据。 #### 注解三角 - **定义注解**:创建注解。 - **使用注解**:在代码中应用注解。 - **读取注解**:通过反射或其他机制读取并处理注解。 #### 示例 以下是一些具体的示例来展示如何定义和使用注解: ##### 定义注解 ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // 注解的保留策略 @Target(ElementType.METHOD) // 注解的目标类型 public @interface MyCustomAnnotation { String value() default ""; // 默认属性值 } ``` ##### 使用注解 ```java public class MyClass { @MyCustomAnnotation(value = "Hello, World!") public void myMethod() { System.out.println("Executing myMethod..."); } } ``` ##### 读取注解 ```java import java.lang.reflect.Method; public class AnnotationReader { public static void main(String[] args) throws Exception { Method method = MyClass.class.getMethod("myMethod"); MyCustomAnnotation annotation = method.getAnnotation(MyCustomAnnotation.class); if (annotation != null) { System.out.println("Found annotation with value: " + annotation.value()); } } } ``` #### 5.1.3 `Lambda`表达式(掌握) Lambda 表达式是 Java 8 引入的一个重要特性,它允许你以简洁的语法编写匿名函数。Lambda 表达式主要用于实现单个抽象方法的接口,这些接口通常被称为函数式接口(Functional Interface)。以下是 Java 中 Lambda 表达式的简单教程: ##### 函数式接口(Functional Interface) 函数式接口只有一个抽象方法的接口。为了声明一个函数式接口,你可以使用 `@FunctionalInterface` 注解,这样可以确保接口只有一个抽象方法。 ```java @FunctionalInterface public interface SimpleFunctionalInterface { void doSomething(); } ``` ##### Lambda 表达式的基本语法 Lambda 表达式的一般语法是: ```java (parameters) -> expression 或者 (parameters) -> { statements; } ``` - `parameters`:这是参数列表,可以是一个或多个参数,参数类型可以省略。 - `->`:这是 Lambda 操作符,将参数部分与 Lambda 体分开。 - `expression` 或 `statements`:这是 Lambda 体,可以是一个表达式或一个代码块。 ##### 使用 Lambda 表达式 ###### 无参数和无返回值 ```java SimpleFunctionalInterface sfi = () -> System.out.println("Hello Lambda!"); sfi.doSomething(); // 输出 "Hello Lambda!" ``` ###### 一个参数和无返回值 ```java @FunctionalInterface interface Greeting { void greet(String name); } Greeting greet = (String name) -> System.out.println("Hello, " + name); greet.greet("Kimi"); // 输出 "Hello, Kimi" ``` ###### 一个参数和有返回值 ```java @FunctionalInterface interface Converter { String convert(String from, String to); } Converter converter = (from, to) -> from.toUpperCase() + to.toLowerCase(); System.out.println(converter.convert("Java", "Python")); // 输出 "JAVApython" ``` ###### 多个参数和有返回值 ```java @FunctionalInterface interface Calculator { int calculate(int a, int b); } Calculator add = (a, b) -> a + b; System.out.println(add.calculate(5, 10)); // 输出 15 ``` ##### Lambda 表达式与方法引用 如果 Lambda 表达式实现的是一个已有的方法,你可以使用方法引用来简化代码。 ###### 静态方法引用 ```java Converter concat = String::concat; System.out.println(concat.convert("Hello, ", "Kimi")); // 输出 "Hello, KimiHello, " ``` ###### 实例方法引用 ```java Converter append = StringBuilder::append; System.out.println(append.convert("Hello, ", "Kimi")); // 输出 "Hello, Kimi" ``` ###### 构造函数引用 ```java Converter toStringBuilder = StringBuilder::new; System.out.println(toStringBuilder.convert("Hello, ", "Kimi")); // 输出 "Hello, Kimi" ``` ##### Lambda 表达式与 Stream API Lambda 表达式在处理集合时非常有用,特别是与 Java 8 引入的 Stream API 结合使用。 ```java List names = Arrays.asList("Kimi", "Alice", "Bob", "Charlie"); names.stream() .filter(name -> name.startsWith("A")) .forEach(System.out::println); // 输出 "Alice" ``` #### 5.1.4 `Optional` 的介绍和使用(掌握) #### 定义 `Optional` 是 Java 8 引入的一个容器类,用于封装可能为 `null` 的值。它的主要目的是帮助开发者避免空指针异常,并提供一种更优雅的方式来处理可能不存在的值。 #### 用途 - **封装可能为 `null` 的对象**: `Optional` 提供了一种安全的方式来处理可能为 `null` 的对象,从而避免了空指针异常。 - **提供链式操作**: `Optional` 支持方法链式调用,使得代码更加简洁和可读。 #### 主要方法 - **`Optional.of(T value)`**: 如果 `value` 不为 `null`,则创建一个包含该值的 `Optional` 对象;如果 `value` 为 `null`,则抛出 `NullPointerException`。 - **`Optional.ofNullable(T value)`**: 如果 `value` 不为 `null`,则创建一个包含该值的 `Optional` 对象;如果 `value` 为 `null`,则返回一个空的 `Optional` 对象。 - **`Optional.empty()`**: 返回一个空的 `Optional` 对象。 - **`Optional.ifPresent(Consumer action)`**: 如果 `Optional` 包含值,则执行 `action`;否则不执行任何操作。 - **`Optional.isPresent()`**: 判断 `Optional` 是否包含值。 - **`Optional.orElse(T other)`**: 如果 `Optional` 包含值,则返回该值;否则返回 `other`。 - **`Optional.orElseGet(Supplier other)`**: 如果 `Optional` 包含值,则返回该值;否则返回由 `Supplier` 提供的值。 - **`Optional.orElseThrow(Supplier exceptionSupplier)`**: 如果 `Optional` 包含值,则返回该值;否则抛出由 `exceptionSupplier` 生成的异常。 #### 示例 ```java import java.util.Optional; import java.util.Random; /** * OptionalExample 类演示了 Java Optional 类的多种用法 */ public class OptionalExample { /** * 获取一个随机名字的 Optional 对象 * 有 50% 的概率返回包含 "John Doe" 的 Optional 对象,否则返回空的 Optional 对象 * * @return Optional 包含名字的 Optional 对象或空的 Optional 对象 */ private static Optional getName() { if (new Random().nextBoolean()) { return Optional.of("John Doe"); } else { return Optional.empty(); } } public static void main(String[] args) { // 获取可能为空的名字,用Optional包装以安全地处理空值 Optional optional = getName(); // 使用 ifPresent 方法处理 Optional 中的值 optional.ifPresent(System.out::println); optional.ifPresent(name -> System.out.println("Name: " + name.toLowerCase())); // 使用 orElse 处理 Optional 为空的情况 String name = optional.orElse("Default Name"); System.out.println("Name: " + name); // 使用 orElseGet 处理 Optional 为空的情况 name = optional.orElseGet(() -> "Computed Name"); System.out.println("Computed Name: " + name); // 使用 orElseThrow 处理 Optional 为空的情况 try { name = optional.orElseThrow(() -> new Exception("Name is missing")); System.out.println("Name: " + name); } catch (Exception e) { System.out.println(e.getMessage()); } } } ``` #### 小结 - **避免空指针异常**: 使用 `Optional` 可以有效地避免空指针异常,并提供一种更优雅的方式来处理可能为 `null` 的值。 - **链式操作**: `Optional` 支持方法链式调用,使得处理逻辑更加简洁明了。 - **提供多种处理方式**: `Optional` 提供了多种方法来处理可能为空的情况,如 `ifPresent`、`orElse`、`orElseGet` 和 `orElseThrow` 等。 通过使用 `Optional`,开发者可以写出更加健壮和易于维护的代码。 #### 5.1.5 Stream API 的介绍和使用(了解) #### 定义 Stream API 是 Java 8 引入的新特性,用于处理集合数据。它提供了一种声明式的、函数式风格的数据处理方式,使得处理集合数据变得更加简洁和高效。 #### 用途 - **数据流处理**: Stream API 提供了一种声明式的处理集合数据的方式,使得开发者可以更专注于描述“做什么”而不是“怎么做”。 - **并行处理**: Stream API 支持并行流处理,可以自动利用多核处理器的优势,提高数据处理的性能。 #### 主要概念 - **源(Source)**: 数据的来源,通常是集合(如 `List`, `Set`)、数组或 `InputStream` 等。 - **中间操作(Intermediate Operations)**: 这些操作返回一个新的流,可以链接在一起形成流水线。常见的中间操作包括 `filter`, `map`, `flatMap`, `sorted`, `peek` 等。 - **终止操作(Terminal Operations)**: 这些操作产生结果或副作用,如计算总和、平均值、查找最大值或最小值等。常见的终止操作包括 `forEach`, `reduce`, `collect`, `count`, `max`, `min`, `anyMatch`, `allMatch`, `noneMatch`, `findFirst`, `findAny` 等。 #### 示例 以下是一个使用 Stream API 处理集合数据的示例: ```java import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamExample { public static void main(String[] args) { // 创建一个整数列表 List numbers = Arrays.asList(1, 2, 3, 4, 5); // 计算偶数之和 int sum = numbers.stream() .filter(n -> n % 2 == 0) .mapToInt(Integer::intValue) .sum(); System.out.println("Sum of even numbers: " + sum); // 输出 6 // 打印偶数 System.out.println("Even numbers:"); numbers.stream() .filter(n -> n % 2 == 0) .forEach(System.out::println); // 输出 2 和 4 // 获取偶数的平方列表 List squaresOfEvens = numbers.stream() .filter(n -> n % 2 == 0) .map(n -> n * n) .collect(Collectors.toList()); System.out.println("Squares of even numbers: " + squaresOfEvens); // 输出 [4, 16] // 计算偶数的最大值 Integer maxEven = numbers.stream() .filter(n -> n % 2 == 0) .max(Integer::compare) .orElse(null); System.out.println("Maximum even number: " + maxEven); // 输出 4 // 并行处理 long parallelSum = numbers.parallelStream() .filter(n -> n % 2 == 0) .mapToInt(Integer::intValue) .sum(); System.out.println("Parallel sum of even numbers: " + parallelSum); // 输出 6 } } ``` #### 小结 - **声明式编程**: Stream API 采用声明式的编程风格,使得代码更加简洁易懂。 - **函数式风格**: Stream API 支持函数式编程特性,可以方便地组合多个操作。 - **并行处理**: Stream API 支持并行处理,可以充分利用多核处理器的优势来加速数据处理。 - **链式操作**: Stream API 支持链式调用,使得多个操作可以串联起来形成数据处理流水线。 通过使用 Stream API,开发者可以写出更加高效、简洁且易于维护的代码。这对于处理大量数据集尤其有用,同时也提高了代码的可读性和可维护性。 #### 5.1.6 泛型(了解) #### 什么是泛型? Java 中的泛型是一种通用的编程技术,它允许我们在编写代码时更加灵活、安全和高效。泛型的主要目的是解决 Java 中类型安全的问题。在 Java 的早期版本中,所有的集合类都是基于 `Object` 类型实现的,这意味着可以将任意类型的对象添加到集合中。然而,在取出元素时需要进行显式类型转换,如果转换错误,就会抛出 `ClassCastException` 异常。通过使用泛型,可以在编译阶段检查类型,从而避免这类异常的发生。 #### 泛型的优点 - **类型安全性**: 泛型允许在编译时检查类型,避免了运行时出现类型转换异常等问题。 - **代码重用性**: 泛型可以让开发者编写通用的代码,提高代码的可重用性和可维护性。 - **性能优化**: 泛型可以避免不必要的类型转换,提高程序的运行效率。 #### 泛型的语法 泛型主要包括三个部分:泛型类、泛型接口和泛型方法。 ##### 泛型类和泛型接口 泛型类和泛型接口是最常见的泛型形式。我们可以通过在类或接口名后面添加一对尖括号来声明一个或多个类型参数。 ```java public class MyClass { private T data; public MyClass(T data) { this.data = data; } public T getData() { return data; } } public interface MyInterface { void add(K key, V value); } ``` 当我们使用泛型类或泛型接口时,可以使用具体的类型来替换类型参数。 ```java MyClass myClass = new MyClass<>("Hello, World!"); MyInterface myInterface = new MyInterface() { @Override public void add(Integer key, String value) { // 实现逻辑 } }; ``` ##### 泛型方法 除了类和接口之外,我们还可以定义泛型方法,这些方法在方法签名前加上一对尖括号,表示该方法有一个或多个类型参数。 ```java public class MyUtils { public static T getLast(List list) { if (list.isEmpty()) { return null; } return list.get(list.size() - 1); } } ``` 当我们使用泛型方法时,可以显式或隐式地为类型参数传入具体的类型。 ```java List names = List.of("Alice", "Bob", "Charlie"); String last = MyUtils.getLast(names); // 隐式类型推断 String lastExplicit = MyUtils.getLast(names); // 显式指定类型 ``` #### 泛型的应用 泛型是一种非常通用的编程技术,可以用它来编写各种各样的通用数据结构和工具类。 ##### List 和 Map Java 内置的 `List` 和 `Map` 类型都支持泛型,可以用来存储任意类型的对象。 ```java List numbers = new ArrayList<>(); numbers.add(1); numbers.add(2); numbers.add(3); Map scoreMap = new HashMap<>(); scoreMap.put("Alice", 90); scoreMap.put("Bob", 80); scoreMap.put("Charlie", 70); ``` #### 小结 - **类型安全**: 泛型可以确保类型在编译时得到验证,避免运行时的类型转换错误。 - **代码重用**: 泛型允许编写通用的代码,提高代码的可重用性。 - **性能提升**: 泛型可以减少不必要的类型转换,提高程序的运行效率。 通过使用泛型,开发者可以写出更加健壮、可读性强和易于维护的代码。 ### 5.2 Spring框架简介(了解) #### 5.2.1 Spring框架的历史和发展 - **起源**: Spring framework最初由Rod Johnson在2003年开始编写,并于2004年发布了第一个版本1.0。 - **目标**: 创立Spring framework的主要目的是解决企业级Java应用中的复杂问题,特别是解决依赖管理和面向切面编程(AOP)的问题。 - **版本演进**: - **1.x**: 初期版本主要关注于依赖注入和面向切面编程。 - **2.x**: 添加了对Web应用程序的支持,包括Spring MVC框架。 - **3.x**: 引入了对Java 5特性的支持,如注解和泛型,并且增强了对RESTful Web服务的支持。 - **4.x**: 增强了对Java 8的支持,包括Lambda表达式和Stream API。 - **5.x**: 重点改进了对反应式编程模型的支持,引入了Spring WebFlux框架。 - **最新版本**: 截至2024年,Spring框架的最新版本为5.x系列,持续增加了对现代Web开发趋势的支持,如微服务架构、云原生应用等。 #### 5.2.2 Spring框架的核心特性 - **依赖注入 (DI)**: - **定义**: 是一种设计模式,用于实现对象之间的解耦,让对象不需要直接创建依赖对象,而是由容器负责创建并注入。 - **好处**: 降低了组件之间的耦合度,提高了代码的可测试性和可维护性。 - **面向切面编程 (AOP)**: - **定义**: 一种编程范式,用于将横切关注点(如日志记录、事务管理)从业务逻辑中分离出来。 - **好处**: 通过切面编程,可以在不修改业务逻辑代码的情况下添加或修改功能。 - **模块化**: Spring框架被设计成高度模块化的,用户可以根据需要选择使用不同的模块。 - **可扩展性**: Spring框架提供了许多扩展点,允许开发者根据需要自定义行为。 - **广泛的应用场景**: 从简单的Web应用到复杂的企业级应用,Spring都能提供解决方案。 #### 5.2.3 Spring的家族框架 - **Spring Boot**: 提供了一个快速搭建Spring应用的方式,通过自动化配置、依赖管理和启动器简化了开发过程。 - **Spring Cloud**: 用于构建分布式系统和服务网格,提供了一系列工具和服务,如服务注册与发现、配置中心、熔断器等。 - **Spring Data**: 提供了一套数据访问抽象层,简化了数据访问层的开发工作,支持各种数据库技术。 - **Spring Security**: 为Spring应用提供了全面的安全保护,包括认证、授权等功能。 - **Spring Integration**: 提供了基于消息驱动的企业集成模式的支持,适用于构建复杂的集成系统。 - **Spring Batch**: 用于批量处理任务,支持大规模数据处理作业。 - **Spring WebFlux**: 用于构建非阻塞的、事件驱动的Web应用和服务器端应用,支持反应式编程模型。 - **Spring Web**: 提供了构建Web应用程序所需的支持,包括HTTP消息处理、多部分文件上传等功能,以及与Spring MVC的紧密集成。 #### 5.2.4 Spring的应用场景和优势 - **应用场景**: - **Web应用**: Spring MVC框架为构建高性能的Web应用提供了基础。 - **企业级应用**: Spring框架适合构建复杂的企业级应用,包括业务流程管理、数据处理等。 - **微服务**: Spring Boot和Spring Cloud为构建微服务架构提供了便利。 - **移动应用后端**: Spring框架可以作为移动应用后端的服务端框架。 - **优势**: - **松耦合**: 通过依赖注入实现了组件之间的松耦合。 - **易于测试**: Spring框架的设计使得单元测试变得简单。 - **广泛的社区支持**: 拥有庞大的开发者社区和丰富的文档资源。 - **丰富的生态**: Spring框架有一整套家族产品,几乎覆盖了企业级应用的所有方面。 - **灵活性**: Spring框架非常灵活,可以很容易地与其他技术栈集成。 - **性能**: Spring框架经过优化,能够高效地运行大规模应用。 - **社区活跃**: Spring框架有一个活跃的社区,不断更新以适应新的技术和标准。 #### 5.2.5 Spring Web - **概述**: Spring Web 是 Spring Framework 的一部分,它为构建Web应用程序提供了必要的支持。Spring Web 包含了多个子模块,旨在提供一套完整的Web开发解决方案。 - **子模块**: - **Spring Web**: 为Web开发提供了一些基本的支持,比如HTTP消息转换、多部分文件上传、Web应用上下文等。 - **Spring Web MVC**: 一个基于Model-View-Controller (MVC) 模式的Web框架,用于构建动态Web应用程序。 - **Spring Web Flows**: 一个用于构建复杂的Web应用程序的工作流框架。 - **Spring WebSocket**: 提供了WebSocket的支持,用于实现全双工通信。 - **Spring Web Services**: 提供了构建和消费Web服务的支持。 - **关键特性**: - **HTTP Message Converters**: 提供了HTTP消息转换器,用于序列化和反序列化HTTP请求和响应。 - **MultiPart File Upload**: 支持多部分文件上传功能。 - **Web Application Context**: 提供了Web应用程序上下文的支持,包括初始化监听器等。 - **MVC Framework**: Spring MVC 提供了一个基于MVC模式的Web框架,用于构建动态Web应用程序。 - **File Upload Support**: 支持多部分文件上传,用于处理文件上传请求。 - **Web Services Support**: 支持构建和消费Web服务,包括SOAP和RESTful服务。 - **WebSocket Support**: 提供了WebSocket的支持,用于实现实时双向通信。 ### 5.3 Spring IoC(掌握) #### 5.3.1 Spring Bean的定义和生命周期 - **定义**: Spring Bean是Spring容器管理的对象。 - **生命周期**: - **初始化**: 包括默认初始化、自定义初始化等。 - **销毁**: 包括默认销毁、自定义销毁等。 - **示例**: ```java @Component public class MyBean { public MyBean() { System.out.println("MyBean created."); } @PostConstruct public void init() { System.out.println("MyBean initialized."); } @PreDestroy public void destroy() { System.out.println("MyBean destroyed."); } } ``` #### 5.3.2 XML和注解方式的Bean配置 - **XML配置**: - **定义Bean**: ``元素定义一个Bean。 - **依赖注入**: 使用``元素注入依赖。 - **注解配置**: - **组件扫描**: 使用`@ComponentScan`注解来自动发现和配置组件。 - **依赖注入**: 使用`@Autowired`、`@Qualifier`等注解来注入依赖。 - **示例**: ```java @Service public class MyService { private final MyRepository repository; @Autowired public MyService(MyRepository repository) { this.repository = repository; } public void doSomething() { // 使用repository } } ``` #### 5.3.3 Bean的作用域和装配方式 - **作用域**: - **Singleton**: 单例模式,每个Spring容器中只有一个实例。 - **Prototype**: 原型模式,每次请求都会创建一个新的实例。 - **Request**: 每次HTTP请求都会创建一个新的实例。 - **Session**: 每个HTTP Session都会创建一个新的实例。 - **装配方式**: - **构造器注入**: 通过构造器参数注入依赖。 - **setter注入**: 通过setter方法注入依赖。 - **属性注入**: 通过属性直接注入依赖。 #### 5.3.4 使用Spring管理依赖关系 - **定义**: Spring通过依赖注入来管理对象之间的依赖关系。 - **目的**: 降低组件之间的耦合度,提高代码的可测试性和可维护性。 - **示例**: ```java @Service public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User findUserById(Long id) { return userRepository.findById(id).orElse(null); } } ``` ### 5.4 Spring MVC(掌握) #### 5.4.1 Spring MVC概述 - **定义**: Spring MVC是Spring web框架的一部分,基于Model-View-Controller (MVC) 模式,用于构建Web应用。 - **特点**: - **请求处理**: 通过@Controller注解来定义控制器。 - **视图解析**: 通过ViewResolver来解析视图。 #### 5.4.2 使用@Controller定义控制器 - **定义**: 使用`@Controller`注解定义控制器类。 - **示例**: ```java @Controller public class HelloController { @RequestMapping("/hello") public String hello(Model model) { model.addAttribute("message", "Hello, Spring MVC!"); return "hello"; } } ``` #### 5.4.3 使用@RequestMapping处理请求 - **定义**: 使用`@RequestMapping`注解来映射请求路径。 - **示例**: ```java @Controller public class HelloController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(@RequestParam String name, Model model) { model.addAttribute("message", "Hello, " + name + "!"); return "hello"; } } ``` #### 5.4.4 使用@ResponseBody返回JSON响应 - **定义**: 使用`@ResponseBody`注解来直接返回JSON响应。 - **示例**: ```java @Controller public class HelloController { @RequestMapping(value = "/hello-json", method = RequestMethod.GET) @ResponseBody public Map helloJson(@RequestParam String name) { Map response = new HashMap<>(); response.put("message", "Hello, " + name + "!"); return response; } } ``` #### 5.4.5 使用Spring Data JPA进行数据访问 - **定义**: Spring Data JPA是Spring Data项目的一部分,用于简化JPA的数据访问。 - **示例**: ```java @Repository public interface UserRepository extends JpaRepository { User findByUsername(String username); } ``` ### 5.5 Spring AOP(了解) #### 5.5.1 AOP的基本概念 - **定义**: AOP是一种编程范式,用于将横切关注点从业务逻辑中分离出来。 - **用途**: - **日志记录**: 在方法执行前后记录日志。 - **事务管理**: 管理方法的事务边界。 - **安全控制**: 控制方法的访问权限。 - **术语** - **切点 (Pointcut)**: 定义了哪些连接点将被执行通知。 - **连接点 (Joinpoint)**: 程序执行的某个特定点,如方法调用。 - **通知 (Advice)**: 在连接点处执行的动作,如前置通知、后置通知等。 - **切面 (Aspect)**: 包含切点和通知的组合。 #### 5.5.2 使用AspectJ进行切面编程 - **定义**: AspectJ是一种常用的AOP框架,提供了强大的切面编程能力。 - **示例**: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Executing: " + joinPoint.getSignature()); } } ``` ### 5.6 Spring事务管理(了解) #### 5.6.1 事务管理的基本概念 - **定义**: 事务是一组操作的集合,要么全部成功,要么全部失败。 - **ACID属性**: - **原子性 (Atomicity)**: 事务中的所有操作要么全部完成,要么一个也不完成。 - **一致性 (Consistency)**: 事务的执行不会破坏数据的一致性。 - **隔离性 (Isolation)**: 事务之间是隔离的,不会相互影响。 - **持久性 (Durability)**: 一旦事务提交,它的效果是持久的。 #### 5.6.2 Spring事务管理器 - **定义**: Spring提供了多种事务管理器,如`DataSourceTransactionManager`。 - **示例**: ```java @Configuration @EnableTransactionManagement public class AppConfig { @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` #### 5.6.3 使用@Transactional进行声明式事务管理 - **定义**: 使用`@Transactional`注解来声明式地管理事务。 - **示例**: ```java @Service @Transactional public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public void createUser(User user) { userRepository.save(user); } } ``` #### 5.6.4 使用编程式事务管理 - **定义**: 通过编程的方式显式地管理事务。 - **示例**: ```java @Service public class UserService { private final UserRepository userRepository; private final PlatformTransactionManager transactionManager; @Autowired public UserService(UserRepository userRepository, PlatformTransactionManager transactionManager) { this.userRepository = userRepository; this.transactionManager = transactionManager; } public void createUser(User user) { TransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { userRepository.save(user); transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); throw e; } } } ``` ### 5.7 构建工具 构建工具(Build Tools)是软件开发过程中用于自动化构建、测试和打包软件应用程序的工具。它们通常用于编译源代码、运行测试、生成文档、打包应用程序以及执行其他与构建过程相关的任务。 java项目常用的构建工具有: **Apache Ant** - 是一个基于 Java 的构建工具,使用 XML 文件(build.xml)来描述构建过程。 - 支持跨平台构建,常用于 Java 项目。 **Maven** - 是一个项目管理和构建自动化工具,主要针对 Java 项目。 - 使用 POM(Project Object Model)文件来描述项目结构和配置。 - 提供了依赖管理和项目生命周期管理。 **Gradle** - 是一个现代的构建自动化系统,适用于 JVM 语言。 - 支持 Groovy 和 Kotlin 脚本,可以替代 Ant 和 Maven。 - 提供了丰富的插件生态系统。 好的,以下是针对 Maven 和 Gradle 的具体使用方法的介绍,以完成你的文档的 5.7.1 和 5.7.2 部分。 #### 5.7.1 Maven ##### 5.7.1.1 独立Maven ##### 安装 Maven 1. **下载 Maven**: 访问 [Maven 官方网站](https://maven.apache.org/download.cgi),下载适合您操作系统的二进制包。 2. **解压缩**: 将下载的文件解压缩到一个合适的目录。 3. **设置环境变量**: - Windows 用户需要设置 `MAVEN_HOME` 环境变量指向 Maven 的安装目录,并将 `%MAVEN_HOME%\\bin` 加入到 `PATH` 环境变量中。 - Linux/macOS 用户可以编辑 `.bashrc` 或 `.zshrc` 文件,添加 `export MAVEN_HOME=path/to/maven` 并将 `$MAVEN_HOME/bin` 添加到 `PATH` 中。 ##### 创建 Maven 项目 1. **初始化项目**: 使用 Maven 命令行工具创建一个新的项目。例如,使用一个简单的 webapp 模板: ```shell mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false ``` 2. **编辑 pom.xml**: 修改 `pom.xml` 文件以包含项目的依赖和其他配置信息。 ##### 常用 Maven 命令 - **编译项目**: `mvn compile` - **运行测试**: `mvn test` - **打包项目**: `mvn package` - **安装到本地仓库**: `mvn install` - **清理项目**: `mvn clean` - **生成站点文档**: `mvn site` ##### 示例 假设你有一个 Maven 项目,并且希望编译和打包它: ```shell cd path/to/your/project mvn clean package mvn package ``` ##### 5.7.1.2 在IDEA使用Maven **导入 Maven 项目** * 打开 IntelliJ IDEA * 新建或打开项目:选择 “Open” 或 “Import Project”,浏览到包含 pom.xml 文件的目录,并选择它。 * 导入项目:IDEA 会检测到这是一个 Maven 项目,并提示你导入该项目。 **创建新的 Maven 项目** * 创建项目:选择 “File” > “New” > “Project”。 * 选择 Maven:在新窗口中选择 “Maven” 作为项目类型。 * 配置项目:填写必要的信息,如 Group Id、Artifact Id 等,并选择一个模板或空项目。 **使用 Maven 插件** IntelliJ IDEA 自带 Maven 插件,可以使用 Maven 插件来运行测试、打包项目、生成站点等。 > **访问 Maven 工具窗口:** 在 IntelliJ IDEA 的右侧栏中找到 “Maven” 工具窗口。 如果没有显示,可以通过 “View” > “Tool Windows” > “Maven” 打开。 #### 5.7.2 Gradle ##### 5.7.2.1 单独 Gradle ##### 安装 Gradle 1. **下载 Gradle**: 访问 [Gradle 官方网站](https://gradle.org/releases/),下载适合您操作系统的二进制包。 2. **解压缩**: 将下载的文件解压缩到一个合适的目录。 3. **设置环境变量**: - Windows 用户需要设置 `GRADLE_HOME` 环境变量指向 Gradle 的安装目录,并将 `%GRADLE_HOME%\\bin` 加入到 `PATH` 环境变量中。 - Linux/macOS 用户可以编辑 `.bashrc` 或 `.zshrc` 文件,添加 `export GRADLE_HOME=path/to/gradle` 并将 `$GRADLE_HOME/bin` 添加到 `PATH` 中。 ##### 创建 Gradle 项目 1. **初始化项目**: 使用 Gradle 命令行工具创建一个新的项目。首先,创建一个项目目录,并在其中创建 `build.gradle` 文件。 2. **编辑 build.gradle**: 在 `build.gradle` 文件中定义项目的构建逻辑。例如,定义依赖关系和插件: ```groovy plugins { id 'java' id 'application' } repositories { mavenCentral() } dependencies { implementation 'org.jetbrains:annotations:23.0.1' testImplementation 'junit:junit:4.12' } application { mainClass = 'com.example.MainApp' } ``` ##### 常用 Gradle 命令 - **编译项目**: `./gradlew build` (Linux/macOS) - `gradlew.bat build` (Windows) - **运行测试**: `./gradlew test` (Linux/macOS) - `gradlew.bat test` (Windows) - **打包项目**: `./gradlew jar` (Linux/macOS) - `gradlew.bat jar` (Windows) - **清理项目**: `./gradlew clean` (Linux/macOS) - `gradlew.bat clean` (Windows) ##### 5.7.2.2 IDEA中使用Gradle 在 IntelliJ IDEA 中使用 Gradle 同样可以提高开发效率,因为 IDEA 提供了对 Gradle 的深度集成支持。以下是详细的步骤说明如何在 IntelliJ IDEA 中使用 Gradle: ##### 5.7.2.3 在 IntelliJ IDEA 中使用 Gradle #### 创建新的 Gradle 项目 - **启动 IntelliJ IDEA**:打开 IntelliJ IDEA。 - **创建新项目**:选择 “File” > “New” > “Project”。 - **选择 Gradle**:在新窗口中选择 “Gradle” 作为项目类型。 - **配置项目**:填写必要的信息,如项目名称、位置、Gradle 版本等。如果需要,可以指定一个模板或空项目。 - **完成创建**:点击 “Finish” 来创建 Gradle 项目。 #### 导入现有的 Gradle 项目 - **打开 IntelliJ IDEA**:启动 IntelliJ IDEA 应用程序。 - **打开项目**:选择 “Open” 或 “Import Project”,浏览到包含 `build.gradle` 文件的目录,并选择它。 - **导入项目**:IDEA 会检测到这是一个 Gradle 项目,并提示你导入该项目。选择 “Import project from external model” 并点击 “OK”。 #### 使用 IDEA的gradle插件 IDEA 内置了对 Gradle 的支持,使得开发者可以直接从 IDE 内部执行 Gradle 任务,监控构建过程,并管理项目的构建配置。 > **访问 Gradle 工具窗口:** 在 IntelliJ IDEA 的右侧栏中找到 “Gradle” 工具窗口。 如果没有显示,可以通过 “View” > “Tool Windows” > “Gradle” 打开。