Javaweb05-请求响应

  • Servlet:Servlet是一种Java技术,用于扩展Web服务器或应用服务器的能力,以便能够处理客户端(通常是浏览器)发送来的请求,并返回响应。Servlet运行于服务器端。
  • Tomcat:Tomcat是一个开源的Web服务器和Servlet容器,它支持Java Servlet和JavaServer Pages (JSP) 技术。Tomcat可以作为独立的Web服务器运行,也可以与其他Web服务器集成。
  • Spring Boot:Spring Boot是一个基于Spring框架的快速开发工具,旨在简化新Spring应用程序的初始设置和配置。它允许开发者快速搭建新的项目,而无需过多关注配置细节。

请求流程详解

  1. 客户端发起请求:当你在浏览器中输入一个URL并访问时,这个请求首先会被发送到Web服务器(比如Tomcat)。
  2. 请求解析:Web服务器接收到请求后,会解析请求信息,这包括请求的方法类型(GET, POST等)、请求路径Params、请求头Headers、请求体Body等信息。
  3. 请求转发给Servlet:Web服务器将解析好的请求封装成HttpServletRequest对象,并创建一个HttpServletResponse对象准备存放响应信息。这两个对象一起被传递给匹配的Servlet(在Spring Boot中通常是DispatcherServlet)。
  4. 请求处理DispatcherServlet接收到请求后,会查找与请求URL匹配的Controller方法。这一步涉及到多个组件,例如HandlerMapping用于确定哪个Controller方法应该处理请求,HandlerAdapter负责调用该方法。
  5. 视图解析与响应生成:Controller方法处理完请求后,可能会返回一个ModelAndView对象或者直接返回一个字符串标识视图名。DispatcherServlet会使用ViewResolver解析视图名,找到相应的视图实现,并通过这个视图生成最终要返回给客户端的HTML页面或者其他形式的数据。
  6. 响应发送回客户端:生成的响应数据会被写入到HttpServletResponse对象中,然后由Web服务器发送回客户端。

请求

各类请求参数的接收及封装

Postman

简单参数

只需要保证请求的参数名与control方法的形参名称保持一致,则接收成功

//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age){
    System.out.println(name+":"+age);
    return "OK";
}

post请求是在请求体中设置参数

@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。

简单参数只能传递少量参数,多的话可以用实体参数包装

实体参数

@RequestMapping("/simplePojo")
public String simplePojo(User user){
    System.out.println(user);
    return "OK";
}

 

实体对象参数

规则:请求参数名与形参对象属性名相同,即可直接通过POJO接收

先封装一个实体对象,嵌套的话就一个属性一个属性封装

先定义一个实体类Address,快速生成get、set方法以及toString方法即标准JavaBean

如果是一个复杂实体对象,只需要按照层次结构对应起来就可以了

服务端请求参数的接收方式有两种:数组、集合

数组集合参数

只需要在形参当中,声明一个数组,数组的名字需要和上面的请求参数名保持一致

@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
    System.out.println(arrays.toString(hobby));
    return "OK";
}

要在形参的list集合前面加上一个注解@RequestParam 绑定参数关系,因为在默认情况下,这多个值会封装在数组当中

@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
    System.out.println(hobby);
    return "OK";
}

使用数组以及集合的形式来接收前端传递过来的多个请求参数值

日期参数

@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
    System.out.println(updateTime);
    return "OK";
}

主要是通过在形参前面加一个注解@DateTimeFormat来指定传递的参数格式

接口请求的常用方式两种GET/POST
GET与POST的区别
① 长度。GET有长度限制,POST没有长度限制。
② 安全性。GET通常是将参数显示在URL地址中,可以被看见,不是那么安全;

                   POST是将参数写入body中,不能被看见,更安全。
③ 作用。 GET通常作用于从数据库中读取数据;

                POST则是将数据提交/更新于数据库中。

Json参数

Json格式的参数在前后端异步交互的时候使用的非常多

1.在postman发送请求的时候,如何传递json格式的参数

要想发送一个请求,并且传递json格式的请求数据,我们需要将请求方式设置为host,因为Json格式的请求数据是需要放在请求当中携带到服务器的

要选择的是raw

JSON当中所有的key都必须使用双引号将其引起来

2.在服务端control当中,怎么来接收json格式的请求参数

一般会通过实体对象来接收,通过user来接收传递过来的JSON格式的数据

@RequestBody这个注解就可以将json格式的请求数据封装到一个实体对象当中

@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
    System.out.println(user);
    return "OK";
}

路径参数

在前面的学习里面 都加了一个注解@RequestMApping,用来指定方法的请求路径

参数已经成为了url的一部分

同时也是我们给服务端所传递的请求参数

重点学习:在服务端control的方法当中,怎么样来获取路径参数

接收路径参数同样也需要定一个方法,也需要加上@RequestMapping

动态设置路径

@PathVariable用来指定要获取的路径参数,并且把路径参数的id绑定给我们的方法形参id

路径参数id需要与方法形参名称id保持一致

@RequestMapping("/path/{id}")
public String pathParam(@PathVarible Integer id){
    System.out.println(id);
    return "OK";
}

@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVarible Integer id,@PathVarible String name){
    System.out.println(id);
    System.out.println(name);
    return "OK";
}

响应

control程序的核心职责就是接收请求,然后设置响应

@ResponseBody

元注解是注解的注解,用于修饰自定义注解的行为。

我们在controller当中定义的每一个对外暴露的方法 都称之为功能接口

上面的路径就是接口的访问路径

项目开发中需要的开发文档就是描述功能接口,它的请求路径是什么、请求参数是什么、以及它响应的数据是什么

在Java中,Object类是所有类的超类(即基类)。每个类都直接或间接地继承自Object类。这意味着所有对象都具有Object类中定义的方法。以下是Object类的一些重要方法和概念:

Object 类的主要方法

  1. toString()

    • 返回对象的字符串表示形式。默认实现返回对象的类名和哈希码,但通常会被子类重写以提供更有意义的字符串表示。
    • 示例:
      public String toString() {
          return getClass().getName() + "@" + Integer.toHexString(hashCode());
      }
  2. hashCode()

    • 返回对象的哈希码,这是一个整数。哈希码用于哈希表(如HashMap)中快速查找对象。
    • 示例:
      public int hashCode() {
          return System.identityHashCode(this);
      }
  3. equals(Object obj)

    • 判断当前对象是否等于指定的对象。默认实现是基于对象的引用比较(即是否是同一个对象),但通常会被子类重写以提供基于内容的比较。
    • 示例:
      public boolean equals(Object obj) {
          return (this == obj);
      }
  4. getClass()

    • 返回对象的运行时类。
    • 示例:
      public final native Class<?> getClass();
  5. finalize()

    • 当垃圾回收器确定没有对该对象的更多引用时,将调用此方法。此方法主要用于释放系统资源或执行清理工作。注意,从Java 9开始,finalize() 方法被标记为已弃用。
    • 示例:
      protected void finalize() throws Throwable {
          // 清理工作
      }
  6. clone()

    • 创建并返回当前对象的一个副本。要使对象可克隆,类必须实现Cloneable接口,并重写clone()方法。
    • 示例:
      protected Object clone() throws CloneNotSupportedException {
          return super.clone();
      }
  7. wait()notify()notifyAll()

    • 这些方法用于线程间的通信。它们必须在同步块中调用。
    • wait():使当前线程等待,直到其他线程调用notify()notifyAll()方法。
    • notify():唤醒在此对象监视器上等待的单个线程。
    • notifyAll():唤醒在此对象监视器上等待的所有线程。
    • 示例:
      public final void wait() throws InterruptedException {
          // 等待
      }
      
      public final void notify() {
          // 唤醒一个线程
      }
      
      public final void notifyAll() {
          // 唤醒所有线程
      }

Object 类的重要概念

  1. 多态性

    • 由于所有类都继承自Object类,因此可以使用Object类型的引用指向任何对象。这种特性称为多态性。
    • 示例:
      Object obj = new String("Hello");
  2. 类型转换

    • 可以使用类型转换将Object类型的引用转换回具体的子类类型。
    • 示例:
      Object obj = new String("Hello");
      String str = (String) obj;
  3. 对象比较

    • 使用equals()方法进行内容比较,而不是使用==进行引用比较。
    • 示例:
      String str1 = new String("Hello");
      String str2 = new String("Hello");
      System.out.println(str1.equals(str2));  // true
      System.out.println(str1 == str2);       // false

Object类是Java中所有类的根类,提供了许多基本方法,这些方法在对象的生命周期管理和多态性中起着重要作用。理解Object类的方法和概念对于编写高效、健壮的Java程序非常重要。

一个案例

resource这个目录存放的是一些其他的资源文件

对于String boot项目来讲,是可以添加前端页面的,但其存储目录是有规范的

classpath指的是类路径,对maven项目来说,resource目录就是一个类路径

@RestController 注解是 Spring 框架提供的一个组合注解,它结合了 @Controller@ResponseBody 注解的功能。使用 @RestController 注解的类通常用于创建 RESTful Web 服务,这些服务直接返回 JSON 或 XML 数据,而不是视图页面。

何时使用 @RestController 注解

  1. 创建 RESTful API

    • 当你需要创建一个 RESTful Web 服务时,通常会使用 @RestController 注解。这种服务通常用于提供数据接口,客户端(如浏览器、移动应用等)通过 HTTP 请求获取数据。
    • 示例:
      @RestController
      public class UserController {
          
          @GetMapping("/users")
          public List<User> getAllUsers() {
              // 返回用户列表
              return userService.getAllUsers();
          }
          
          @PostMapping("/users")
          public User createUser(@RequestBody User user) {
              // 创建用户
              return userService.createUser(user);
          }
      }
  2. 直接返回数据而不是视图

    • 如果你的控制器方法需要直接返回数据(如 JSON 或 XML),而不是跳转到视图页面,那么使用 @RestController 是最合适的选择。
    • 示例:
      @RestController
      public class ProductController {
          
          @GetMapping("/products/{id}")
          public Product getProductById(@PathVariable Long id) {
              // 返回指定ID的产品
              return productService.getProductById(id);
          }
      }
  3. 简化开发

    • 使用 @RestController 可以简化开发过程,因为你不需要在每个方法上单独添加 @ResponseBody 注解。所有的方法默认都会返回数据而不是视图。
    • 示例:
      @RestController
      public class OrderController {
          
          @GetMapping("/orders")
          public List<Order> getAllOrders() {
              // 返回订单列表
              return orderService.getAllOrders();
          }
          
          @GetMapping("/orders/{id}")
          public Order getOrderById(@PathVariable Long id) {
              // 返回指定ID的订单
              return orderService.getOrderById(id);
          }
      }

不使用 @RestController 的场景

  1. 返回视图页面

    • 如果你的控制器方法需要返回视图页面(如 JSP、Thymeleaf 模板等),则应该使用 @Controller 注解,而不是 @RestController
    • 示例:
      @Controller
      public class HomeController {
          
          @GetMapping("/")
          public String home() {
              // 返回首页视图
              return "home";
          }
      }
  2. 混合使用

    • 如果你在同一个控制器中既有返回数据的方法,也有返回视图的方法,可以使用 @Controller 注解,并在需要返回数据的方法上单独添加 @ResponseBody 注解。
    • 示例:
      @Controller
      public class MixedController {
          
          @GetMapping("/api/data")
          @ResponseBody
          public Data getData() {
              // 返回数据
              return dataService.getData();
          }
          
          @GetMapping("/view")
          public String getView() {
              // 返回视图
              return "view";
          }
      }
  • 使用 @RestController:当你需要创建 RESTful API,直接返回数据而不是视图页面时。
  • 使用 @Controller:当你需要返回视图页面,或者在一个控制器中混合使用返回数据和视图的方法时。

getClassLoader() 方法是 Java 中 Class 类提供的一个方法,用于获取当前类的类加载器。类加载器(ClassLoader)是 Java 虚拟机(JVM)的一部分,负责将类文件加载到内存中,并对类进行初始化。了解类加载器的工作原理和使用 getClassLoader() 方法可以帮助你更好地管理类的加载和资源的访问。

getClassLoader() 方法详解

方法签名
public ClassLoader getClassLoader()
返回值
  • 返回当前类的类加载器。如果当前类是由引导类加载器(Bootstrap ClassLoader)加载的,则返回 null
作用
  • 获取当前类的类加载器,以便于进行类加载、资源文件的加载等操作。

类加载器层次结构

Java 的类加载器分为以下几个层次:

  1. 引导类加载器(Bootstrap ClassLoader)

    • 负责加载核心的 Java 类库(如 rt.jar),这些类库位于 $JAVA_HOME/jre/lib 目录下。
    • 引导类加载器不是由 Java 编写的,而是由原生代码实现的。
    • 无法通过 getClassLoader() 方法获取到引导类加载器,返回值为 null
  2. 扩展类加载器(Extension ClassLoader)

    • 负责加载 $JAVA_HOME/jre/lib/ext 目录下的扩展类库。
    • 扩展类加载器是 sun.misc.Launcher$ExtClassLoader 的实例。
  3. 系统类加载器(Application ClassLoader)

    • 负责加载应用程序类路径(classpath)下的类。
    • 系统类加载器是 sun.misc.Launcher$AppClassLoader 的实例。

示例代码

获取当前类的类加载器
public class ClassLoaderExample {
    public static void main(String[] args) {
        // 获取当前类的类加载器
        ClassLoader classLoader = ClassLoaderExample.class.getClassLoader();
        System.out.println("Current class loader: " + classLoader);

        // 获取系统的类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("System class loader: " + systemClassLoader);

        // 获取引导类加载器加载的类的类加载器
        ClassLoader stringClassLoader = String.class.getClassLoader();
        System.out.println("String class loader: " + stringClassLoader); // 输出 null
    }
}
加载资源文件
public class ResourceLoaderExample {
    public static void main(String[] args) {
        // 获取当前类的类加载器
        ClassLoader classLoader = ResourceLoaderExample.class.getClassLoader();

        // 加载资源文件
        InputStream resourceAsStream = classLoader.getResourceAsStream("config.properties");
        if (resourceAsStream != null) {
            Properties properties = new Properties();
            try {
                properties.load(resourceAsStream);
                System.out.println("Property: " + properties.getProperty("name"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Resource not found");
        }
    }
}

注意事项

  1. 类加载器的委托模型

    • Java 类加载器采用了委托模型。当一个类加载器收到类加载请求时,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,因此所有的类加载请求最终都应该传送到最顶层的引导类加载器中,只有当父类加载器反馈自己无法加载这个类时,子类加载器才会尝试自己去加载。
  2. 类加载器的作用域

    • 每个类加载器都有自己的作用域,只能加载其类路径下的类。例如,系统类加载器只能加载应用程序类路径下的类,而扩展类加载器只能加载扩展类路径下的类。
  3. 类加载器的唯一性

    • 同一个类加载器加载的类被认为是相同的,即使类的字节码来自不同的文件。因此,类加载器在类的唯一性判断中起到了关键作用。

通过理解和使用 getClassLoader() 方法,你可以更好地控制类的加载过程和资源的访问,这对于开发复杂的 Java 应用程序非常有用。

String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();详解这行代码

这行代码的作用是从类路径中加载一个名为 emp.xml 的资源文件,并将其路径转换为一个字符串。让我们逐步解析这行代码的各个部分:

代码解析

String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
  1. this.getClass()

    • 这是一个 Java 关键字,表示当前对象的引用。
    • getClass() 方法返回当前对象的 Class 对象,该对象代表了当前对象所属的类。
  2. getClass().getClassLoader()

    • getClassLoader() 方法返回当前类的类加载器。
    • 类加载器负责将类文件加载到 JVM 中。对于大多数应用程序类,这通常是系统类加载器(AppClassLoader)。
  3. getClassLoader().getResource("emp.xml")

    • getResource(String name) 方法从类路径中查找并返回一个 URL 对象,表示指定名称的资源文件。
    • 参数 "emp.xml" 是资源文件的名称。类加载器会在类路径中搜索这个文件。类路径通常包括项目的 src/main/resources 目录(对于 Maven 项目)或 resources 目录(对于其他构建工具)。
  4. getResource("emp.xml").getFile()

    • getResource("emp.xml") 返回一个 URL 对象。
    • getFile() 方法从 URL 对象中提取文件路径部分,返回一个字符串。
    • 返回的路径可能是一个绝对路径,也可能是一个带有 %20 等编码的路径(因为 URL 中的空格和其他特殊字符会被编码)。

empList.stream().forEach(emp->{});详解这行代码

这行代码使用了 Java 8 中的流(Stream)API 和 Lambda 表达式来遍历一个 List 集合中的所有元素,并对每个元素执行某些操作。让我们详细解析这行代码的各个部分:

代码解析

empList.stream().forEach(emp -> {});
  1. empList

    • 这是一个 List 集合,假设它存储了多个 Employee 对象。
  2. stream()

    • stream() 方法是 Collection 接口的一个默认方法,它返回一个流对象(Stream)。流是处理集合的一种方式,提供了许多用于过滤、映射、排序等操作的方法。
    • 流对象允许你以声明式的方式处理数据,而不需要显式地编写循环和临时变量。
  3. forEach(emp -> {})

    • forEach 方法是 Stream 接口的一个终端操作,用于遍历流中的每个元素,并对每个元素执行给定的操作。
    • emp -> {} 是一个 Lambda 表达式,表示一个函数式接口的实现。在这个例子中,forEach 方法接受一个 Consumer 函数式接口的实例,该接口定义了一个 void accept(T t) 方法。
    • emp 是 Lambda 表达式的参数,表示当前遍历到的元素。
    • {} 是 Lambda 表达式的主体部分,表示对 emp 执行的操作。在这个例子中,主体部分为空,即没有任何操作。

完整示例

假设我们有一个 Employee 类和一个包含多个 Employee 对象的 List 集合:

import java.util.Arrays;
import java.util.List;

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', age=" + age + "}";
    }
}

public class StreamExample {
    public static void main(String[] args) {
        List<Employee> empList = Arrays.asList(
            new Employee("Alice", 30),
            new Employee("Bob", 25),
            new Employee("Charlie", 35)
        );

        // 使用流和 forEach 方法遍历 empList
        empList.stream().forEach(emp -> {
            // 在这里可以对每个 emp 执行操作
            System.out.println(emp);
        });
    }
}

解释

  1. 创建 Employee

    • Employee 类有两个属性:name 和 age,以及相应的构造方法和 getter 方法。
  2. 创建 empList 集合

    • 使用 Arrays.asList 方法创建一个包含多个 Employee 对象的 List 集合。
  3. 使用流和 forEach 方法遍历 empList

    • empList.stream() 将 empList 转换为一个流对象。
    • forEach(emp -> { System.out.println(emp); }) 遍历流中的每个 Employee 对象,并调用 System.out.println(emp) 方法打印每个对象的信息。

注意事项

  1. Lambda 表达式的主体部分

    • 如果主体部分只有一条语句,可以省略大括号 {}
      empList.stream().forEach(emp -> System.out.println(emp));
  2. 方法引用

    • 如果 Lambda 表达式只是调用一个已有的方法,可以使用方法引用:
      empList.stream().forEach(System.out::println);
  3. 副作用

    • 在 forEach 方法中执行的操作可能会有副作用,例如修改共享状态。为了避免并发问题,尽量避免在流操作中修改外部状态。

通过这种方式,你可以简洁高效地遍历集合并执行所需的操作。

Lambda表达式的介绍

Lambda 表达式是 Java 8 引入的一项重要特性,它允许你以更简洁的方式编写函数式接口的实现。Lambda 表达式使得代码更加简洁、易读,并且支持函数式编程风格。下面是对 Lambda 表达式的详细介绍:

什么是 Lambda 表达式?

Lambda 表达式是一种匿名函数,它可以没有名称,但有参数列表、函数主体、返回类型,同时它也支持类型推断。Lambda 表达式的主要用途是实现函数式接口(即只有一个抽象方法的接口)。

Lambda 表达式的语法

Lambda 表达式的语法如下:

(parameters) -> expression
(parameters) -> { statements; }
组件解释
  1. 参数列表

    • 参数列表放在圆括号 ( ) 中,参数类型可以省略,因为编译器可以自动推断。
    • 如果只有一个参数,圆括号可以省略。
    • 如果没有参数,需要使用空的圆括号 ()
  2. 箭头符号

    • -> 是箭头符号,用于分隔参数列表和函数主体。
  3. 函数主体

    • 函数主体可以是一个表达式或一个代码块。
    • 如果函数主体是一个表达式,可以直接写表达式,不需要大括号 { }
    • 如果函数主体是一个代码块,需要用大括号 { } 包围,并且可以包含多条语句。

示例

示例 1:简单的 Lambda 表达式
// 定义一个函数式接口
@FunctionalInterface
interface MyFunction {
    int apply(int x);
}

public class LambdaExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现 MyFunction 接口
        MyFunction square = (x) -> x * x;

        // 调用 apply 方法
        int result = square.apply(5);
        System.out.println("Square of 5 is: " + result); // 输出: Square of 5 is: 25
    }
}
示例 2:带多个参数的 Lambda 表达式
// 定义一个函数式接口
@FunctionalInterface
interface MyBinaryOperator {
    int apply(int x, int y);
}

public class LambdaExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现 MyBinaryOperator 接口
        MyBinaryOperator add = (x, y) -> x + y;

        // 调用 apply 方法
        int result = add.apply(3, 4);
        System.out.println("Sum of 3 and 4 is: " + result); // 输出: Sum of 3 and 4 is: 7
    }
}
示例 3:带无参的 Lambda 表达式
// 定义一个函数式接口
@FunctionalInterface
interface MySupplier {
    String get();
}

public class LambdaExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现 MySupplier 接口
        MySupplier greeting = () -> "Hello, World!";

        // 调用 get 方法
        String message = greeting.get();
        System.out.println(message); // 输出: Hello, World!
    }
}
示例 4:带代码块的 Lambda 表达式
// 定义一个函数式接口
@FunctionalInterface
interface MyConsumer {
    void accept(String message);
}

public class LambdaExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式实现 MyConsumer 接口
        MyConsumer printMessage = (message) -> {
            System.out.println("Processing message: " + message);
            System.out.println("Message processed.");
        };

        // 调用 accept 方法
        printMessage.accept("Hello, Lambda!");
        // 输出:
        // Processing message: Hello, Lambda!
        // Message processed.
    }
}

常见的函数式接口

Java 8 提供了一些常用的函数式接口,它们位于 java.util.function 包中:

  • Function<T, R>:接受一个参数,返回一个结果。

    Function<String, Integer> lengthFunction = String::length;
    int length = lengthFunction.apply("Hello");
  • Predicate<T>:接受一个参数,返回一个布尔值。

    Predicate<String> isEmpty = String::isEmpty;
    boolean result = isEmpty.test("");
  • Consumer<T>:接受一个参数,不返回结果。

    Consumer<String> printMessage = System.out::println;
    printMessage.accept("Hello, World!");
  • Supplier<T>:不接受参数,返回一个结果。

    Supplier<String> greeting = () -> "Hello, World!";
    String message = greeting.get();
  • BiFunction<T, U, R>:接受两个参数,返回一个结果。

    BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
    int sum = add.apply(3, 4);

优点

  1. 简洁性
    • Lambda 表达式使代码更加简洁、易读。
  2. 函数式编程支持
    • 支持函数式编程风格,使得代码更加模块化和灵活。
  3. 并行处理
    • 结合流(Stream)API,可以轻松实现并行处理,提高性能。

通过使用 Lambda 表达式,你可以更高效地编写和维护代码,特别是在处理集合和并行任务时。

前端代码在页面加载的时候,通过vue的钩子方法发起了一个异步请求来加载数据,在成功的回调函数当中,先是判定了一下响应回来的code的值

分层解耦

三层架构

在进行软件设计以及软件开发时,需要尽量让每个接口类或者是方法只做一件事情,职责单一,即单一职责原则,优点会使接口类以及方法的复杂度更低、可读性更强、拓展性更好,更利于后期的维护

Dao层要想灵活的去获取数据,可以通过面向接口的方式进行编程

分层解耦

仅仅存放与员工相关的逻辑处理即为高内聚

对象怎么样交给容器来管理

容器怎么样为我们的程序提供它所依赖的资源

这个容器我们叫spring容器,或者ioc容器

IOC & DI入门

(1)加上注解@Component //将当前类交给IOC容器管理,成为IOC容器中的bean

(2)在成员变量上加上注解@Autowired//运行时,IOC容器会提供该类型的bean对象,并赋值给该变量  此过程也称为依赖注入

@Component是干什么的

@Component 是 Spring 框架中的一个注解,用于标记一个 Java 类为 Spring 管理的 Bean。Spring 容器会自动检测这些类,并将它们注册为 Bean,从而可以在应用程序中通过依赖注入(Dependency Injection, DI)来使用这些 Bean。

主要用途

  1. 标记为 Spring Bean

    • @Component 注解告诉 Spring 容器这是一个组件,需要被管理和注入。
    • 这个注解可以应用于任何普通的 Java 类。
  2. 自动扫描和注册

    • 当你使用 @Component 注解标记一个类后,Spring 容器会在启动时自动扫描这些类,并将它们注册为 Bean。
    • 这通常需要配合 @ComponentScan 注解来指定扫描的包路径。

示例

示例 1:基本用法

假设我们有一个简单的服务类 MyService,我们希望 Spring 容器管理它:

import org.springframework.stereotype.Component;

@Component
public class MyService {
    public void doSomething() {
        System.out.println("Doing something...");
    }
}
示例 2:配合 @ComponentScan 使用

在 Spring Boot 应用程序的主类中,通常会使用 @SpringBootApplication 注解,它包含了 @ComponentScan 注解,会自动扫描主类所在包及其子包中的所有 @Component 注解的类。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

    @Autowired
    private MyService myService;

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    public void run() {
        myService.doSomething(); // 调用 MyService 的方法
    }
}

其他相关注解

除了 @Component,Spring 还提供了几个专门用于标记不同类型的 Bean 的注解:

  1. @Service

    • 用于标记业务逻辑层的类。
    • 示例:
      @Service
      public class UserService {
          // 业务逻辑方法
      }
  2. @Repository

    • 用于标记数据访问层的类,通常用于 DAO(Data Access Object)。
    • 示例:
      @Repository
      public class UserRepository {
          // 数据访问方法
      }
  3. @Controller

    • 用于标记控制层的类,通常用于处理 HTTP 请求的控制器。
    • 示例:
      @Controller
      public class UserController {
          // 控制器方法
      }

注意事项

  1. 包扫描路径

    • 确保 @ComponentScan 注解指定了正确的包路径,以便 Spring 容器能够找到并注册所有标记为 @Component 的类。
    • 如果没有指定路径,默认会扫描主类所在的包及其子包。
  2. Bean 名称

    • 默认情况下,Spring 容器会根据类名生成 Bean 的名称,首字母小写。例如,MyService 类的 Bean 名称为 myService
    • 也可以通过 @Component("customName") 显式指定 Bean 的名称。
  3. 依赖注入

    • 通过 @Autowired 注解可以将 Spring 管理的 Bean 注入到其他 Bean 中。
    • 示例:
      @Component
      public class AnotherService {
          @Autowired
          private MyService myService;
      
          public void performAction() {
              myService.doSomething();
          }
      }

通过使用 @Component 注解,你可以方便地将普通 Java 类转换为 Spring 管理的 Bean,从而充分利用 Spring 框架提供的依赖注入、生命周期管理和事务管理等功能。

@Autowired是干什么的

@Autowired 是 Spring 框架中的一个注解,用于自动装配(自动注入)依赖关系。它可以让 Spring 容器自动将所需的依赖对象注入到目标 Bean 中,从而减少手动设置依赖的工作量,提高代码的可读性和可维护性。

主要用途

  1. 自动装配依赖

    • @Autowired 注解可以标注在类的成员变量、方法或构造函数上,指示 Spring 容器自动查找并注入匹配的依赖对象。
    • 如果没有匹配的 Bean,Spring 容器会抛出异常。
  2. 减少配置

    • 使用 @Autowired 可以减少 XML 配置文件中的 <property> 和 <constructor-arg> 标签,使配置更加简洁。

常见用法

1. 成员变量注入
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void addUser(User user) {
        userRepository.save(user);
    }
}
2. 构造函数注入
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void addUser(User user) {
        userRepository.save(user);
    }
}
3. Setter 方法注入
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void addUser(User user) {
        userRepository.save(user);
    }
}

高级用法

1. 按类型装配

@Autowired 默认按类型(byType)装配依赖对象。如果容器中有多个相同类型的 Bean,Spring 会抛出异常。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 如果有多个 UserRepository 实现,Spring 会抛出异常
}
2. 按名称装配

如果需要按名称(byName)装配依赖对象,可以结合 @Qualifier 注解使用。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    @Qualifier("userRepositoryImpl1")
    private UserRepository userRepository;

    public void addUser(User user) {
        userRepository.save(user);
    }
}
3. 可选注入

如果某个依赖对象是可选的,可以使用 @Autowired(required = false) 注解。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired(required = false)
    private UserRepository userRepository;

    public void addUser(User user) {
        if (userRepository != null) {
            userRepository.save(user);
        }
    }
}

注意事项

  1. 依赖对象存在性

    • 确保被注入的依赖对象已经在 Spring 容器中注册。可以通过 @Component@Service@Repository@Controller 等注解或 XML 配置来注册 Bean。
  2. 循环依赖

    • 避免在构造函数注入中出现循环依赖。Spring 容器会尝试解决循环依赖问题,但在某些情况下可能会失败。
  3. 类型冲突

    • 如果容器中有多个相同类型的 Bean,可以使用 @Qualifier 注解来指定具体的 Bean。
  4. 构造函数注入 vs. 字段注入

    • 构造函数注入提供了更好的不可变性和清晰的依赖关系,推荐在可能的情况下使用构造函数注入。
    • 字段注入虽然简洁,但不利于单元测试和代码的可读性。

通过使用 @Autowired 注解,你可以更方便地管理依赖关系,使代码更加简洁、易读和可维护。

IOC控制反转详解

指的就是将对象的控制权交给IOC容器,由IOC容器来创建及管理这些对象,IOC容器当中的这些对象也称为bean对象

component注解使用时间:

在项目开发当中,某一个类不能归到这三层里面,还想将这个类交给IOC容器管理,就可以使用component注解,最典型的就是一些工具类,其他推荐使用那三个衍生的

没有用value属性指明bean的名字的话,默认名字是类名首字母小写

@Repository("daoA"),一般直接采用默认值就好

直接都丢一个包下,省嘚配置环境

@Repository注解以后很少用,后面学习了mybatis框架之后,会通过另外一个注解来替代

DI依赖注入详解

指的是IOC容器要为应用程序提供运行时所依赖的资源

历时了不知道多久大概一个月吧 太慢了赶紧赶赶进度了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值