前端学JAVA

一:Java语法

1.1、注解

注解困扰了我很长时间,看了一堆概念。要理解注解,首先得理解两个概念元数据反射机制

元数据是关于数据的数据。它提供了关于其他数据的信息或描述。例如,在数据库中,记录的结构(字段类型、字段名称等)就算是元数据。

反射机制是一种功能,使得程序能够在运行时获取类的信息(例如类名、方法、属性等),并可以动态调用这些类的方法或访问其属性。

注解可以看作是特殊形式的元数据,常与反射结合使用,允许根据注解的信息动态处理代码逻辑。

如下是标准概念:

Java 注解是一种特殊的语法,用于向代码添加元数据。简单来说,注解就像是给代码加上标签,提供额外的信息。这些信息可以在编译时、运行时或通过工具处理时被利用,但注解本身不会直接影响代码的执行。

1.1.1、@RequestMapping

@RequestMapping 注解用于定义一个可以被 HTTP 请求访问的控制器方法。当 JavaScript 向 /sys/gtVal 发送 POST 请求时,Spring 框架会根据请求的路径和方法将其映射到 login 方法上,并执行该方法。

@RequestMapping(value = "/sys/gtVal", method = RequestMethod.POST)
public V login() {
    ...
}

该注解还分类级、方法级别

  • 类级别的@RequestMapping用于定义一个基础路径,所有在该类中的方法都将基于这个路径展开。
  • 方法级别的@RequestMapping则用于细化具体的路径及请求方式。

@RequestMapping("/miniapp")
public class MiniappSqykzController {
    @RequestMapping(value = "/miniList", method = RequestMethod.GET)
    public List miniList(@RequestParam("type") String type) {
        ...
    }
}

 上面代码,它的完整URL就是/miniapp/miniList

1.1.1.1、Post/GetMapping
  • @PostMapping 与 @GetMapping 是 @RequestMapping 的特化用法,更简洁易读。
  • @PostMapping 用于处理 HTTP POST 请求, @GetMapping用于处理 HTTP GET 请求。
1.1.1.2、发起与接收请求
  • @GetMapping 、 @PostMapping及@RequestMapping  一般都是用来接收请求的。
  • 当与 HTTP 客户端库(如 Feign)配合时,是用来发起请求的。
@FeignClient(value = "service-provider")
public interface ApiProviderFeign {
    @PostMapping("/api/service/provider/getUserInfo")// 此处发起请求
    Map<String, String> getUserInfo(@RequestParam("username") String username);
}

1.1.2、@Override

@Override 注解是 Java 中的一个标记注解,用于指示一个方法正在重写父类中的方法。它可以帮助编译器检查是否正确地重写了方法,并使代码更具可读性。使用 @Override 注解的优点包括:

  1. 编译时检查:如果方法名或参数不匹配,编译器会报错,帮助避免潜在的错误。

  2. 代码可读性:明确表明该方法是重写的,有助于其他开发者理解代码。

  3. 维护性:在将来的代码更改中,确保方法的重写关系不被意外破坏。

常见用法示例:

class Parent {
    void display() {
        System.out.println("Display from Parent");
    }
}

class Child extends Parent {
    @Override
    void display() {
        System.out.println("Display from Child");
    }
}

在上面的例子中,Child 类重写了 Parent 类的 display 方法。在重写时使用 @Override 注解是一个良好的编程习惯。

1.1.3、@FeignClient

@FeignClient 是 Spring Cloud Feign 模块中的一个注解,用于声明一个 Feign 客户端。Feign 是一个声明式的 Web 服务客户端,可以帮助简化 HTTP API 的调用。使用 @FeignClient 注解,开发者能够通过接口定义与其他服务的 RESTful API 的交互,以下是关键点:

  1. 声明式 HTTP 客户端:通过接口定义 API 方法,Feign 会为这些方法自动生成 HTTP 请求。你只需关注接口的设计,而无需处理底层的 HTTP 细节。

  2. 简化的配置:可以通过使用注解,如 @GetMapping@PostMapping 等,指定 HTTP 方法和路径。Feign 会自动实现这些方法。

  3. 服务发现:与 Spring Cloud Eureka 集成时,可以在 @FeignClient 中指定服务名,Feign 会根据服务名称动态解析其具体地址

  4. 负载均衡:结合 Ribbon 等负载均衡组件,Feign 支持自动负载均衡。

  5. 集成其他特性:可以与 Spring Cloud 的其他功能(如 Hystrix、熔断器)集成,以增强服务调用的可靠性。

示例:

@FeignClient(name = "user-service")
public interface UserServiceClient {
    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);
}

在这个例子中,UserServiceClient 接口通过 @FeignClient 注解定义与名为 user-service 的服务的交互,并使用 @GetMapping 指定具体的 API 路径。

  1. @FeignClient 注解:用于定义一个 Feign 客户端,以便在服务之间进行 HTTP 调用。Feign 客户端允许你通过接口的形式来调用其他微服务的 RESTful API。

  2. name 属性name 属性指定了 Feign 客户端的名称。在这里,user-service 通常代表另一个微服务的名称,这个名称通常是在服务注册中心(例如 Eureka)中注册的服务ID。通过这个名称,Feign 可以找到并与对应的服务进行通信

1.1.4、@RequestBody

@RequestBody 是 Spring 框架中用于处理 HTTP 请求体的一个注解。它通常用于将 HTTP 请求的正文内容绑定到控制器方法的参数上。这个注解可以应用在方法的参数上,也可以应用在整个类上,以指示 Spring MVC 如何处理该参数或整个请求体。

以下是 @RequestBody 的一些常见用法和示例:

假设你有一个控制器方法需要从请求体中接收 JSON 数据并将其转换为 Java 对象,你可以使用 @RequestBody 来实现这一点:

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class MyController {

    @PostMapping("/user")
    public User createUser(@RequestBody User user) {
        // 处理用户数据
        return user;
    }
}

在这个示例中,当客户端发送一个包含 JSON 数据的 POST 请求到 /api/user 时,Spring 会自动将 JSON 数据反序列化为 User 对象,并传递给 createUser 方法。

1.1.5、@ResponseBody

@ResponseBody是Spring MVC框架中的一个核心注解用于指示方法的返回值应该直接写入HTTP响应体中

在Spring框架中,@ResponseBody注解的使用非常关键,它允许开发者轻松地将方法的返回值直接写入HTTP响应体中。这对于构建RESTful Web服务尤其重要,因为它允许以一种声明式的方式处理JSON、XML等格式的数据。通过使用@ResponseBody注解,开发者可以简化开发过程,专注于业务逻辑的实现,而无需关心数据的序列化和传输细节

此外,当使用@RestController注解时,所有方法都隐式地具有@ResponseBody效果,但在非@RestController类中需要显式添加此注解。这意味着在@RestController类中,即使没有明确标注@ResponseBody,方法的返回值也会被自动序列化为JSON或XML格式,并写入HTTP响应体中。而在其他类型的控制器类中,则需要在方法上明确标注@ResponseBody以实现相同的效果。

1.1.6、@SysLog

@SysLog("banner列表")

1.2、反射

反射是指java在运行时允许查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用,例如Spring框架的依赖注入。

这个“运行时”是指Java虚拟机(JVM)执行字节码后的阶段,也就是当程序已经被编译成.class文件,并在JVM中运行时。

java代码在计算机中经历的三个阶段

Java中的反射概念允许程序在运行时获取类的信息和操作对象。而在JavaScript中,虽然没有严格意义上的“反射”,但可以通过一些内置对象和方法实现类似的功能。

在JavaScript中,常用的相关概念包括:

  1. typeof:获取变量的数据类型。
  2. instanceof:检查对象是否是某个构造函数的实例。
  3. Object.keys()Object.values()、和Object.entries():获取对象的键、值或键值对。
  4. Reflect:ES6引入的Reflect对象,提供了很多与对象操作相关的静态方法,支持一些类似反射的功能。

通过这些特性,JavaScript能够在运行时动态访问和操作对象的属性和方法。JS中感觉正常到都忽略了其存在的用法,在java中竟然被提升到一个专门的语法概念来讲了。

 反射优秀博文:JAVA反射机制_java的反射机制-优快云博客

1.3、HashMap

HashMap就是键值对,与es6中Map类似。

添加元素使用put()方法,获取元素使用get()方法,删除元素使用remove()方法,遍历元素可以使用增强的for循环或迭代器。

1.4、函数

在 Java 中,不同的函数声明有不同的目的和使用场景。

  1. public static void main(String[] args):

    • 这是 Java 应用程序的入口点。main 方法是程序启动时执行的特殊方法。
    • public:表示该方法可以被任何其他类访问。
    • static:意味着该方法属于类本身,而不是类的实例,可以直接通过类名调用。
    • void:表示该方法不返回任何值。
    • String[] args:用于接收命令行参数的字符串数组。
  2. public R pwdLogin(String[] args):

    • 这是一个普通的实例方法(如果没有 static 关键字)。它执行特定的功能,例如用户登录。
    • R 是该方法的返回类型,表示该方法将返回一个 R 类型的对象。
    • 方法中包含若干参数,用于接收用户名、密码、动作名称以及 HTTP 请求和响应对象。

总结:

  • main 方法是程序的入口点,而其他方法(如 pwdLogin)用于实现特定功能。
  • 返回类型(如 void 或 R)决定了该方法是否返回结果以及返回的结果类型。
  • 参数数量和类型根据方法的需要而变化。

1.5、文件类型

1.5.1、properties文件

在Java编程中,pro.properties文件通常是一个属性文件,用于存储应用程序的配置信息。这种文件格式简单易读,每行包含一个键值对,以等号(=)分隔,如key=value。属性文件广泛应用于各种场景,如数据库连接配置、系统设置、国际化资源等。

1.6、package

java文件首行中package语句是不是可有可无?该语句只是为了便于阅读代码?

在Java中,package语句并不是可有可无的。它用于声明一个类所属的包(package)。包是Java中的一种命名空间机制,用于组织类和接口,避免命名冲突。

作用

  1. 组织代码:通过包可以将相关的类和接口组织在一起,使项目结构更加清晰。
  2. 命名空间管理:不同包中的类可以有相同的名字,而不会冲突。例如,两个不同的包中都可以有一个名为MyClass的类。
  3. 访问控制:包还可以用于控制类的访问权限。默认情况下,只有同一个包内的类才能互相访问,除非使用特定的访问修饰符(如publicprotected)。

总结

  • 必须性package语句不是可有可无的,它是Java语言的一部分,用于定义类的包。
  • 功能:它不仅有助于代码的组织和管理,还提供了一种有效的命名空间管理方式。
  • 可读性:虽然package语句本身并不直接影响代码的运行,但它提高了代码的可读性和可维护性。

一个包(package)可以定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。

同一个package下的类之间互相调用时,不需要使用import语句。这是因为在同一个包内,所有的类都是可见的,可以直接通过类名进行访问。js中没有包的概念,java的包真好用!

import com.runoob.mypackage.*;

这样,你可以导入 com.runoob.mypackage 包中的所有类,从而在当前源文件中使用该包中的任何类的方法、变量或常量。注意,使用通配符 * 导入整个包时,只会导入包中的类,而不会导入包中的子包

1.7、接口Interface

让我们来看一个例子,这个例子创建了一个叫做animals的包。通常使用小写的字母来命名避免与类、接口名字的冲突。

在 animals 包中加入一个接口(interface):

Animal.java 文件代码:

/* 文件名: Animal.java */
package animals;
 
interface Animal {
   public void eat();
   public void travel();
}

接下来,在同一个包中加入该接口的实现:

MammalInt.java 文件代码:

package animals;
 
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

然后,编译这两个文件,并把他们放在一个叫做animals的子目录中。 就是包和接口的实践了

1.8、数据类型

1.8.1、数组

java中数组的声明方式跟js中有啥区别?

1. 声明方式

Java:

int[] numbers = new int[5]; // 声明一个整型数组,长度为5
String[] names = {"Alice", "Bob", "Charlie"}; // 使用初始化列表

 JavaScript:

let numbers = new Array(5); // 声明一个数组,长度为5
let names = ["Alice", "Bob", "Charlie"]; // 使用初始化列表

2. 类型

  • Java:强类型语言,数组必须指定类型,如 int[]String[] 等。

  • JavaScript:动态类型语言,数组可以包含多种类型的数据。

3. 长度

  • Java:数组长度在创建时固定,不能动态改变。

  • JavaScript:数组的长度是动态的,可以随时添加或减少元素。

4. 方法和属性

  • Java:数组是对象,但更像基本数据结构,没有太多内置方法。
  • JavaScript:数组是对象,拥有丰富的内置方法(例如 push()pop()map()filter()

5.返回值

Java中返回空数据不像JS中return [],这么随意。如下

if (whiteArr == null) {
    return new String[0];
}else {
    return whiteArr;
}

1.8.2、字符串

1.8.2.1、char和String的区别?

Java中String跟JS区别较大,JS中较粗暴String可以是任意长度的,也统一。java则区分较细,如下

字符:char

使用单引号,长度为1的单个字符。操作方法很少

字符串:String

使用双引号,包含多个字符。操作方法较多

 1.8.3、数据结构

数组(Array):

int[] array = new int[5];
  • 特点: 固定大小,存储相同类型的元素。
  • 优点: 随机访问元素效率高。
  • 缺点: 大小固定,插入和删除元素相对较慢。

列表(List): 

List<String> sites = new ArrayList<String>();
sites.add("Google");
sites.get(0);  // 访问第1个元素
  • 特点: 动态数组,可变大小。
  • 优点: 高效的随机访问和快速尾部插入。
  • 缺点: 中间插入和删除相对较慢。

Array与List的区别在于一个固定大小,一个动态数组

映射(Map):

js中的对象,对应java中的map(键值对) 

Map<String, Integer> hashMap = new HashMap<>();
Map<String, Integer> treeMap = new TreeMap<>();

hashMap.put("one", "Google");
hashMap.put("two", "Runoob");
hashMap.get('one'); // "Google"

...详情参考:Java 数据结构 | 菜鸟教程

1.9、interface

接口本身并不能被调用,必须通过实现它的类或代理对象来进行调用。

二:Idea

2.1、项目启动

从git获取到项目代码后,用idea打开。

  1. 安装依赖
  2. 完成Marven/JDK等配置
  3. 检查数据库配置
  4. 启动相关服务

安装依赖

如果个别依赖从私服下载不了,可以去maven官网下载补充。

如果run时提示程序包xx不存在,在项目目录右键Marven->ReLoad Project,重新下载依赖。

数据库配置

数据库连接如果异常,可在idea服务器连接工具完成测试工作。

启动相关服务

无服务架构的项目,一般需要多个服务来支持应用。注意别忘了注册中心,比如zookeeper或Eureka

2.2、启动报错汇总

2.1.1 compiler error

这个错是我在第一次导入团队代码后,run services时发生的,完整报错内容为

java: Compilation failed: internal java compiler error

报错信息翻译下就是编译异常,个人觉得以上报错主要原因可能是sdk不一致,或者是build时分配的内存太小。定位起来较繁琐,我花了一上午折腾。

解决办法:

1、查看项目的 jdk(Ctrl+Alt+shift+S)

File ->Project Structure->Project Settings ->Project

2、查看工程的 jdk(Ctrl+Alt+shift+S)

File ->Project Structure->Project Settings -> Modules -> (需要修改的工程名称) -> Sources ->

3、查看 idea 中 Java 配置

File ->Setting ->Build,Execution,Deployment -> Compiler -> Java Compiler

上面三步做完还是失败的话

清除 IDEA 缓存 重启 IDEA

File->Invalidate Caches/Restart

还有一种情况是因项目过大,需要修改这个堆的大小

解决方法如下:

在 setting-->Build,Execution,Deployment-->Compiler 中找到 build process heap size(Mbytes):700 改为 1024(视情况而定)

(我就是这个原因造成的,改了一下堆大小就好了)

2.1.2 Unable start Tomcat

Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat

考虑是否数据库连接失败,可在本地测试,确保正常连接后重启服务。有的数据库有网络要求,需要代理文件 。

数据库参数一般在application.properties文件中,datasource.slave.username配置中。

2.1.3 部分服务没有端口号

删除缓存后,重启服务可解决。File->Invalidate Caches,打开后全选所有选项,可彻底删除缓存。

2.3、搜索

"Find in Files"和双击Shift键(Search Everywhere)都是IntelliJ IDEA中强大的搜索工具,但它们的使用场景和目的有所不同。"Find in Files"更适合于在项目中查找特定的文本或代码片段,而双击Shift键(Search Everywhere)则提供了一种更广泛的搜索方式,可以帮助你快速找到几乎所有类型的元素。

Find in Files快捷键Ctrl shift F,如果无效,找Edit->find->find in files

2.4、自动补全 

controller中直接调用某个类中没有的方法test,该方法会飘红。鼠标悬停在方法名称上会有Create method ’test‘提示,点击该提示会自动在该类中创建此方法。

interface中添加一个函数,实现类文件名称会飘红。在该文件中使用快捷键ctrl + i, 然后Enter即可。注意自动生成的函数没有@RequestBody,需要手动添加。

2.5、debugger

平时启动服务时不要选择run,直接选择debugger。然后可以随时在任何一行代码上添加红点开始调试,爽的一笔。

进入断点后的操作,如下图

上图的停止会结束服务,如果想在调试中途结束调试,但不结束服务。可点击红色方块下2位的三角符号(resume program)。

 2.6、数据库可视化工具

在哪里写sql?

库名右键->New->Query Console 

三:框架/工具

 3.1、SpringBoot框架结构

在 Spring Boot 或微服务架构中,每个服务的文件目录结构通常遵循一定的约定。以下是一个常见的 Spring Boot 服务目录结构示例,以及各个文件和目录的简要说明:

my-service
│
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── myservice
│   │   │               ├── MyServiceApplication.java  # 启动类
│   │   │               ├── controller                 # 控制器包
│   │   │               │   └── MyController.java      # 处理请求的控制器
│   │   │               ├── service                    # 服务包
│   │   │               │   └── MyService.java         # 业务逻辑
│   │   │               ├── repository                 # 数据访问包
│   │   │               │   └── MyRepository.java      # 数据访问层
│   │   │               └── model                      # 模型包
│   │   │                   └── MyModel.java           # 实体类
│   │   └── resources
│   │       ├── application.properties                 # 配置文件
│   │       └── static                                 # 静态资源(如 HTML, CSS, JS)
│   │           └── index.html                         # 主页
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── myservice
│                       └── MyServiceApplicationTests.java  # 测试类
│
├── pom.xml                # Maven 项目管理文件
|---target                 marven 生成的文件
└── README.md              # 项目说明文件

主要目录和文件说明:

  • src/main/java: 存放 Java 代码的主目录。

    • MyServiceApplication.java: Spring Boot 启动类,包含 main 方法。
    • controller: 处理 HTTP 请求的控制器类。
    • service: 包含业务逻辑的服务类。
    • repository: 数据访问层,通常接口定义,与数据库交互。
    • model: 存放实体类,定义核心数据模型。
  • src/main/resources: 存放资源文件的目录。

    • application.properties: 应用配置文件,定义数据库连接、端口等配置。
    • static: 静态资源目录,存放前端资源。
  • src/test/java: 存放测试代码的目录。

    • MyServiceApplicationTests.java: 单元测试类,用于测试应用功能。
  • pom.xml: Maven 项目的配置和依赖管理文件。

  • README.md: 项目的说明文档。

  • target:项目构建的输出结果存放位置,构建、测试和其他过程产生的文件都集中在这里。每次执行 Maven 构建命令(如 mvn clean 或 mvn package)时,target 目录会被重新生成。

这个结构可以根据项目的具体需求做相应调整,但以上是一个基本的布局示例。

3.2、External Libraries

java中external libraries跟前端项目中 node_modules作用与概念一致,都是依赖包或者说外部库

具体使用上有区别,如下

  • Java项目:外部库由构建工具Maven等管理,不直接放在项目根目录中;依赖关系通过pom.xmlbuild.gradle文件定义。
  • 前端项目:依赖库直接下载到项目根目录中的node_modules文件夹中;依赖关系通过webpack等工具,package.json文件定义。

3.3、Maven

Java开发中的Maven就类似前端开发中的webpack

Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建、报告和文档。官网 :http://maven.apache.org

3.4、MyBatis

mybatis是一个优秀的基于java的持久层框架,它内部封装了 jdbc,使开发者只需要关注sql语句本身,而不需要花费精力 去处理加载驱动、创建连接、创建statement等繁杂的过程。

它支持定制化 SQL、存储过程以及高级映射。MyBatis 可以简化数据库访问操作,提供了以下主要功能:

  1. SQL 映射:用户可以直接在 XML 文件或注解中定义 SQL 语句,从而控制 SQL 的执行。同时,MyBatis 还支持动态 SQL 功能。

  2. 对象关系映射:MyBatis 能够将数据库结果集自动映射到 Java 对象,支持复杂数据类型的映射。

  3. 灵活性:MyBatis 则没有强制要求使用特定的编程模型,开发者可以自由选择 SQL 语句的编写方式,更符合项目需求。

  4. 支持多种数据库:MyBatis 可以与多种关系型数据库搭配使用,适应性强。

  5. 缓存机制:MyBatis 提供了一级缓存和二级缓存,旨在提高数据访问性能。

MyBatis 适合于需要复杂 SQL 操作的项目,开发者可以对 SQL 语句进行精细控制。与其他 ORM 框架相比,MyBatis 更加轻量级和灵活,但需要开发者自己管理 SQL 逻辑。

3.5、框架专有名词

SpringBoot代码结构中启动类controller控制器、service服务、repository数据访问、model模型,这些专有名称怎么理解?前端有没有类似的概念可以类比着理解?

以下是每个部分的简要说明,以及与前端的类比:

控制器 (controller)

  • 作用:控制器负责前端HTTP请求处理和路由,并调用相应的服务。
  • 类比:可以类比于前端的路由组件(如 React Router 中的路由),负责处理用户的请求和展示对应的视图。

服务 (service)

  • 作用:包含业务逻辑,处理来自控制器的请求,进行数据处理,然后调用数据访问层(Repository)。
  • 类比:类似于前端的服务模块(如 API 调用逻辑),负责处理请求的具体实现,比如数据获取和处理。

数据访问 (repository)

  • 作用:与数据库交互,负责执行 CRUD(创建、读取、更新、删除)操作。
  • 类比:可以与前端的 API 请求管理工具(如 Axios 或 Fetch API)相对应,这些工具用于与后端接口交互并获取数据。

模型 (model)

  • 作用:定义数据模型,通常对应数据库表的结构,包含数据的属性和验证规则,包装数据的对象。
  • 类比:类似于前端的状态管理(如 Redux 的 store),用来定义和管理应用的数据结构。

启动类 (MyServiceApplication.java)

  • 作用:这是应用的入口,包含 main 方法,负责启动 Spring Boot 应用。
  • 类比:类似于前端应用的入口文件(如 index.js 或 main.js),是应用加载的起点。

假设你有一个获取用户信息的请求:

  1. 前端向 /users/{id} 发送 GET 请求。
  2. 控制器的 getUserById 方法被调用。
  3. 控制器调用服务的 findById 方法,传入用户 ID。
  4. 服务通过调用仓储(Repository的 findById 方法查询数据库。
  5. 仓储(Repository返回用户信息给服务,服务处理后返回给控制器
  6. 控制器将用户信息返回给前端。

这种设计遵循了分层架构的原则,各层关注不同的职责,使代码更加模块化和易于维护。

3.6、微服务 

微服务相关知识有优秀系列博文分享给大家,我也看的这些:地址

3.7、Eureka

负责服务的注册与发现,使得服务能够找到彼此。

3.8、Fegin

Fegin提供了一种声明式的 HTTP 客户端调用方式,简化了 RESTful 服务的调用。使用 Feign 可以让你的代码更加简洁易读,并自动处理负载均衡和服务调用的细节。

3.8.1、有Eureka还需Fegin吗?

在 Spring Boot 中使用 Eureka 进行服务注册和发现,再使用 RestTemplate 或其他手动的 HTTP 客户端进行服务调用可以解决服务启动和互相调用的问题。但 Feign 代替手动,实现服务的自动调用。

3.8.1.1、实例Demo

实例地址:微服务组件之OpenFeign服务调用组件的介绍及其使用方法

如上示例虽然写的很清楚,但是我对了七八遍还是没看懂。如下为AI帮我梳理的注解

当你通过浏览器或工具请求 http://localhost:7070/api/service/consumer/getUserInfo?username=root 时,执行过程如下:

3.8.2.1. 接收请求

  • 请求首先被发送到 service-consumer 微服务。
  • 因为请求的 URL 匹配到 DemoController 的 @GetMapping 注解,Spring 会调用 getUserInfo 方法。

3.8.2.2. 调用 Feign 客户端

  • 在 DemoController 的 getUserInfo 方法中,使用 apiProviderFeign.getUserInfo(username) 调用 Feign 客户端。
  • username 被传递为 root

3.8.2.3. 发送 Feign 请求

  • Feign 客户端 ApiProviderFeign 收到请求,并将其转换为对 service-provider 微服务的 HTTP POST 请求。
  • 请求的 URL 为 http://localhost:8081/api/service/provider/getUserInfo(假设 service-provider 在 8081 端口)。
  • 请求 Body 中包含参数 username=root

3.8.2.4. 处理服务提供者请求

  • service-provider 微服务接收到请求并匹配到 ApiController 的 getUserInfo 方法。
  • 方法内部创建一个 Map,并将 username 和一些静态值放入其中。

3.8.2.5. 返回结果

  • getUserInfo 方法返回一个包含用户信息的 Map(例如:{"id": "1001", "username": "root", "pass": "123456"})。
  • Feign 客户端将接收到的结果转换为一个 Map<String, String> 对象,并返回给 DemoController

3.8.2.6. 返回响应给客户端

  • DemoController 中的 getUserInfo 方法将结果返回给最初发起请求的客户端(浏览器或 HTTP 客户端)。
3.8.1.2、Demo的接口

理解 ApiProviderFeign 需要明确几个概念:

3.8.3.1. 接口的作用

ApiProviderFeign 是一个声明式的 Feign 客户端接口,主要用于定义如何调用外部服务(即 service-provider)。它并不需要实现具体的方法,因为 Feign 会在运行时为这个接口创建代理对象。

3.8.3.2. 实现和动态代理

尽管 ApiProviderFeign 是一个接口,但在 Spring Cloud 的上下文中,Feign 会根据这个接口自动生成一个实现类。所以,你不需要手动实现 ApiProviderFeign,也不需要看到其实现代码。

  • 当你在代码中使用 @FeignClient 注解时,Feign 会扫描并创建一个实现了 ApiProviderFeign 接口的动态代理对象。

3.8.3.3. 如何调用接口

  • 在 DemoController 中,apiProviderFeign 是通过 Spring 的依赖注入 (@Autowired) 获取到的。其实是获取到了 Feign 代理对象,它实现了 ApiProviderFeign 接口。
  • 调用 apiProviderFeign.getUserInfo(username) 实际上是调用这个动态代理对象的方法,而这个方法的逻辑是内部通过 HTTP 调用 service-provider 的相应接口。

3.8.3.4. 调用方式

接口本身并不能被调用,必须通过实现它的类或代理对象来进行调用。在这段代码中,Feign 创建的代理对象实现了 ApiProviderFeign,使得调用 apiProviderFeign.getUserInfo(username) 成为可能。

总结

  • ApiProviderFeign 作为 Feign 客户端接口定义了如何与 service-provider 对接。
  • Spring Cloud Feign 会在应用启动时为这个接口生成实现,并注入到使用它的类中。
  • apiProviderFeign 是通过依赖注入获得的代理对象,可以直接调用接口定义的方法。
3.8.1.3、接口注解理解?

在 service-consumer 子工程中,@PostMapping("/api/service/provider/getUserInfo") 注解的理解如下:

1. 请求类型

@PostMapping 是一个组合注解,用于处理 HTTP POST 请求。它指示该方法会处理发往指定 URL 的 POST 请求。

2. 路径定义

"/api/service/provider/getUserInfo" 是该方法处理请求的具体路径。这意味着当调用 ApiProviderFeign.getUserInfo 方法时,将发起一个 POST 请求,路径为 /api/service/provider/getUserInfo

3. Feign 执行

当你在 DemoController 中通过 apiProviderFeign.getUserInfo(username) 调用时,Feign 会:

  • 生成一个对应的 HTTP POST 请求。
  • 将请求的 URL 设置为 "/api/service/provider/getUserInfo"
  • 传递必要的参数(在这个例子中是 username)。

4. 服务交互

该注解确保了 service-consumer 能够正确地调用 service-provider 提供的 GET 用户信息的功能。这个路径与 service-provider 中 ApiController 的处理路径相对应。

总结

  • @PostMapping 注解表明这个方法处理 POST 请求。
  • 路径指定了请求的目标。
  • 此注解与 Feign 客户端配合使用,使得 service-consumer 可以正确地发起请求并与 service-provider 进行交互。

这里接口的@PostMapping注解指示服务提供者具体地址。

因此Demo中service-provider工程并未直接实现service-consumer工程的interface,所以需要service-provider和interface都需要明确写明@PostMapping路径。

但如果service-provider直接实现该interface,则service-provider无需再写@PostMapping,spiringboot可直接找到。此种情况下,service-consumer中@PostMapping中地址无实际意义可以随意填写(不能包含数字),只要不重复即可,但不写不行。

3.8.2、哪些调用需要Fegin?

包含启动类的文件夹可以视为独立服务,服务之间的调用需要通过 Feign 来实现。

没有启动类的文件夹仅用于存放文件,不需要通过 Feign 进行调用,其他服务可以直接访问这些文件。

3.9、实体类

实体类(Entity类)是与数据库表结构相对应的Java类,它映射了数据库表中的记录为Java对象。实体类通常包含属性(对应数据库表的字段)、getter和setter方法以及可能的构造函数等。

实体类是数据模型层(model)的组成部分,用于表示业务数据,而不是直接与数据库进行交互。

3.10、Mapper

Mapper是数据访问层(DAO层)的一种表现形式。

Mapper层通常用于定义与数据库交互的接口,这些接口中的方法对应着数据库中的CRUD(创建、读取、更新、删除)操作。在MyBatis等ORM框架中,Mapper接口并没有直接的实现类,取而代之的是一个XML文件,该文件中定义了SQL语句和Java接口的绑定关系。当调用Mapper接口的方法时,实际上是通过动态代理机制,根据接口方法与XML文件中的SQL语句进行匹配,从而执行相应的数据库操作。

Mapper和实体类在Java应用程序中扮演着不同的角色,Mapper负责数据访问和操作,而实体类则负责数据的表示和封装。

3.10.1、因mapper,不需要实体类了?

不完全正确。尽管 MyBatis 和 Mapper 提供了便捷的数据访问能力,但实体类仍然是必要的。原因如下:

  1. 对象映射:实体类用来表示数据库表的结构,每个实体类的属性对应数据库表中的字段。MyBatis 通过这些实体类将数据库记录映射为 Java 对象。

  2. 代码清晰性:实体类增进了代码的可读性和维护性,使得数据结构更清晰。

  3. 业务逻辑:在某些情况下,实体类不仅仅用于数据映射,它们可能还包含与业务相关的方法和逻辑,这样可以更好地组织代码。

因此,虽然 MyBatis 和 Mapper 简化了数据库操作,但实体类仍然是不可或缺的部分。在使用 MyBatis 时,你仍然需要定义实体类以便进行数据映射和操作。

3.11、实体类

实体类(entity)通常是用来表示数据库表对应的对象。

它们通常包含与数据库字段相对应的属性,并提供相应的 getter 和 setter 方法。实体类的主要目的是用于存储和传递数据。

待整理

1、model层(数据库表字段映射到实体类)
数据库实体层,也被称为entity层,pojo层。
一般数据库一张表对应一个实体类,类属性同表字段一一对应。
2、dao层(CURD方法)
dao层即数据持久层,也被称为mapper层。
dao层的作用为访问数据库,向数据库发送sql语句,完成数据的增删改查任务。
3、service层 (功能设计)
service层即业务逻辑层。
service层的作用为完成功能设计。
service层调用dao层接口,接收dao层返回的数据,完成项目的基本功能设计。
4、controller层(前后端传参)
controller层即控制层。
controller层的功能为请求和响应控制。
controller层负责前后端交互,接受前端请求,调用service层,接收service层返回的数据,最后返回具体的页面和数据到客户端。

-----------------------------------------------------------------------------------

我还在学习中,伴随学习过程,随时总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sun_qqq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值