笔记
# 知识点
1、API 开放 和 接口开发 是不同的
是的,"API开放"和"接口开发"是两个不同的概念。 "API"(Application Programming Interface)指的是应用程序编程接口,它是一种用于不同软件系统之间互相通信的技术规范。在软件开发中,API可以让开发者在不了解底层实现细节的情况下,使用某个软件系统的功能。 "API开放"通常指的是将某个软件系统的API接口对外公开,以便其他开发者或系统可以使用该系统的功能。例如,一个社交媒体应用可以开放其API接口,以便第三方开发者可以通过API调用来访问该应用的用户数据或其他功能。 "接口开发"则是指在软件开发中,开发人员编写代码来实现API接口。这些接口可以是用于不同系统之间通信的RESTful API,也可以是用于不同模块之间通信的内部API。在接口开发中,开发人员需要定义接口的输入输出参数、处理逻辑、异常处理等细节。 因此,"API开放"是一种用于将某个软件系统的功能对外公开的技术手段,而"接口开发"是一种用于实现API接口的技术实践。
2、API 网关 和 微服务网关 是不一样的
"API网关"和"微服务网关"是两个不同的概念,虽然它们都是用于构建分布式系统的核心组件,但它们的功能和作用有所不同。 API网关通常是指一种用于管理和调度API请求的组件,它可以将来自客户端的API请求路由到相应的后端服务,并进行负载均衡、缓存、认证、授权、限流等操作。API网关常见的应用场景包括微服务架构、云原生应用、RESTful API等。 微服务网关则是一种用于管理和协调微服务请求的组件,它可以将来自客户端的请求路由到相应的微服务,并进行负载均衡、服务发现、熔断等操作。微服务网关常见的应用场景包括微服务架构、服务治理、容错机制等。 因此,API网关和微服务网关的区别在于它们所管理的对象不同。API网关管理的是API请求,而微服务网关管理的是微服务请求。虽然它们的功能有所重叠,但在实际应用中需要根据场景和需求选择合适的网关组件。
3、什么是 npm,node
npm和Node.js是两个不同的概念,但它们通常是一起使用的。 Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它可以让JavaScript在服务器端运行,同时还提供了许多方便的API和模块,让开发者能够快速构建高性能的网络应用程序。Node.js还具有事件驱动、非阻塞I/O等特点,能够处理大量并发请求。 npm(Node Package Manager)是Node.js的包管理器,它是一个用于共享、发布、安装和管理Node.js模块的命令行工具。在npm上,开发者可以搜索、查看和下载各种Node.js模块,同时也可以发布自己编写的模块供其他开发者使用。 通常情况下,开发者在使用Node.js时会使用npm来管理所需的模块和依赖。例如,在一个Node.js项目中,我们可以使用npm安装第三方模块,例如Express、React等:
npm install express
npm install react
2
这样,npm会自动下载和安装所需的模块及其依赖,并将它们保存在项目的node_modules
目录下。在代码中,我们可以使用require
或import
语句来引入所需的模块:
const express = require('express');
import React from 'react';
2
总之,Node.js和npm是一对不可分割的工具,它们为JavaScript开发者提供了方便、高效的开发环境和工具。
4、server: port: 7529 servlet: context-path: /api 其中 servlet: context-path: /api 有什么用?
这个配置是Spring Boot应用中的一项配置,用于指定Servlet的上下文路径。具体来说,这个配置项用于指定Web应用在访问时的根路径,也就是我们常说的上下文路径。在Spring Boot应用中,Servlet的上下文路径默认为“/”,也就是应用的根路径,但是你可以通过修改这个配置项来改变Servlet的上下文路径,从而改变应用的根路径。例如,将Servlet的上下文路径配置为“/api”,那么应用的根路径就变成了“http://localhost:7529/api/”。 具体用途包括:
- 控制Web应用的根路径:这个配置项可以用于控制Web应用的根路径,即访问Web应用时的URL路径。通过修改Servlet的上下文路径,可以改变Web应用的根路径。
- 避免URL冲突:这个配置项可以用于避免URL路径冲突。在实际开发中,可能会出现不同的Web应用使用相同的URL路径的情况,通过修改Servlet的上下文路径,可以避免URL路径冲突。
- 提高Web应用的安全性:这个配置项可以用于提高Web应用的安全性。通过修改Servlet的上下文路径,可以隐藏Web应用的真实路径,从而降低Web应用被攻击的风险。 总之,这个配置项是Spring Boot应用中非常重要的一个配置,它用于控制Web应用的根路径,可以帮助你更好地控制Web应用的行为并提高Web应用的安全性。
5、mvc: pathmatch: matching-strategy: ANT_PATH_MATCHE这个配置是什么意思,有什么用?
这是Spring MVC中的一项配置,用于指定URL路径匹配的策略。具体来说,这个配置项用于指定Spring MVC在匹配URL路径时使用的匹配策略。在Spring MVC中,URL路径的匹配是通过AntPathMatcher类来实现的,这个类可以使用Ant风格的通配符进行路径匹配,比如“/user/*”,“/user/**”,“/user/{id}”等。 具体用途包括:
- 指定URL路径匹配策略:这个配置项可以用于指定Spring MVC在匹配URL路径时使用的匹配策略。默认情况下,Spring MVC使用AntPathMatcher进行匹配,但是你也可以使用其他的匹配策略,比如正则表达式匹配等。
- 控制URL路径匹配的粒度:这个配置项可以用于控制URL路径匹配的粒度。比如,你可以使用“/user/*”来匹配所有以“/user/”开头的URL路径,或者使用“/user/{id}”来匹配指定ID的URL路径。
- 提高URL路径匹配的效率:这个配置项可以用于提高URL路径匹配的效率。在大规模的Web应用中,URL路径的匹配是一个非常重要的性能瓶颈,通过选择合适的匹配策略,可以提高URL路径匹配的效率。 总之,这个配置项是Spring MVC中非常重要的一个配置,它用于控制URL路径匹配的策略和粒度,可以帮助你更好地控制Web应用的行为。
6、npm run install 和 npm install有区别吗?
在npm中,npm install
和npm run install
是有区别的。
npm install
是用来安装项目中所需要的依赖包(和yarn
作用相同),它会查找当前目录下的package.json
文件,并根据dependencies
和devDependencies
字段中所列出的依赖包进行安装。如果你在执行npm install
时没有指定特定的依赖包名称,则默认会安装package.json
文件中所列出的所有依赖包。例如,执行npm install
命令会安装package.json
文件中所列出的所有依赖包,而执行npm install express
则会仅安装express
这个依赖包。npm run install
则是用来运行一个名为install
的脚本。你可以在package.json
文件的scripts
字段中定义脚本,然后使用npm run
命令来运行这个脚本。例如,如果在package.json
文件的scripts
字段中定义了一个名为install
的脚本,那么执行npm run install
命令就会运行这个脚本。 因此,npm install
和npm run install
是不同的命令,它们的作用和用法也不同。npm install
用来安装依赖包,而npm run install
用来运行脚本。
7、关于前端脚手架 Ant Design Pro
Ant Design 是什么?属于 react 吗
Ant Design 是一个基于 React 的 UI 组件库,它提供了大量的高质量组件和模板,可以帮助开发者快速构建美观、易用、高效的 Web 界面。Ant Design 旨在提供一致的设计语言和用户体验,同时提供灵活的自定义和扩展性。 因为 Ant Design 是基于 React 开发的,所以它可以轻松地与 React 应用程序集成。但是,Ant Design 并不仅限于 React,它也可以与其他前端框架集成,例如 Vue 和 Angular。
Ant Design Pro 呢
Ant Design Pro 是一个开箱即用的企业级前端应用程序解决方案,它基于 Ant Design 和 React 技术栈,提供了丰富的业务组件和模板,帮助开发者快速构建出高质量、高效的管理系统、后台应用程序等。Ant Design Pro 提供了许多实用的工具和功能,例如国际化、权限管理、数据可视化、代码生成等,可以大大提高开发效率和质量。 Ant Design Pro还提供了丰富的实践案例和最佳实践,帮助开发者快速上手和掌握如何使用 Ant Design Pro 来构建前端应用程序。Ant Design Pro 是一个完全开源的项目,可以免费使用和自由修改。
Ant Design Pro 与 vue 在开发中怎么选型
Ant Design Pro 便于快速开发,而 Vue 适合那种轻量级开发,单页面解决方案
Ant Design Pro 是一个基于 React 技术栈的企业级前端应用程序解决方案,而 Vue 是一个流行的渐进式 JavaScript 框架。选择 Ant Design Pro 还是 Vue 取决于您的技术栈和项目需求。 如果您的团队熟悉 React 并且需要一个功能丰富的基于 React 的解决方案,那么 Ant Design Pro 可能是一个不错的选择。Ant Design Pro 提供了许多实用的工具和组件,可以加速开发过程,并且有一个强大的社区支持。 如果您更熟悉 Vue 并且需要一个类似的解决方案,那么您可能会考虑使用 Element UI Pro,这是一个基于 Vue 的类似解决方案。 当然,选择 Ant Design Pro 还是 Vue 取决于您的项目需求。如果您需要一个快速开发的解决方案,并且已经熟悉了其中的技术栈,那么您可能更喜欢 Ant Design Pro;如果您需要一个更轻量级的解决方案,并且您更熟悉 Vue 技术栈,那么您可能更喜欢 Element UI Pro。
8、为什么要使用 DTO
包
DTO
(Data Transfer Object)是一种用于在不同层次或模块之间传递数据的对象,它通常包含了需要在不同层次或模块之间传递的数据和相关的元数据。DTO
的使用可以带来以下好处:
- 降低耦合度:使用
DTO
可以将数据传输的逻辑从业务逻辑中分离出来,从而降低不同模块或层次之间的耦合度,便于代码的维护和升级。 - 提高性能:使用
DTO
可以减少不必要的数据传输,从而提高系统的性能和响应速度。例如,在远程调用或网络传输中,使用DTO
可以只传输需要的数据,而不是传输整个对象或实体,从而减少网络流量和传输时间。 - 简化接口设计:使用
DTO
可以将复杂的数据结构转换为简单的数据对象,从而简化接口的设计和维护。例如,在前后端分离的应用中,使用DTO
可以将后端返回的数据转换为前端需要的数据结构,便于前端的渲染和展示。 - 提高安全性:使用
DTO
可以避免将敏感数据直接传输到客户端或其他不安全的环境中,从而提高系统的安全性。例如,在Web应用中,使用DTO
可以将用户输入的数据转换为安全的数据结构,避免SQL注入、XSS等安全问题。 总之,使用DTO
可以提高系统的可维护性、性能、安全性和简洁性,是一种常见的数据传输方案。
9、@PathVariable 和 @RequestParam
PathVariable和RequestParam都是Spring MVC中用于获取请求参数的注解,但它们的使用场景和获取方式有所不同。
PathVariable用于获取URL路径中的参数值,通常用于RESTful风格的接口中。例如,对于以下URL:
http://localhost:8080/user/123
其中,123就是PathVariable,可以使用以下方式获取:
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id) {
// ...
}
2
3
4
其中,@PathVariable注解用于标注参数id是从路径中获取的,"id"指定了PathVariable的名称。
而RequestParam用于获取URL中的查询参数,即**?key=value形式的参数**。例如:
http://localhost:8080/user?id=123
其中,id=123就是RequestParam,可以使用以下方式获取:
@GetMapping("/user")
public User getUserById(@RequestParam("id") Long id) {
// ...
}
2
3
4
其中,@RequestParam注解用于标注参数id是从查询参数中获取的,"id"指定了RequestParam的名称。 总的来说,PathVariable适用于获取URL路径中的参数,RequestParam适用于获取查询参数。两者都是Spring MVC中用于获取请求参数的常用注解。
10、synchronized (userAccount.intern())
synchronized
是Java中用来控制多线程访问共享资源的关键字。它可以修饰方法和代码块,当被修饰的方法或代码块被执行时,只有一个线程可以进入到方法或代码块中执行,其他线程需要等待该线程执行完毕后才能进入。这样可以保证在多线程环境下对共享资源的操作是同步的,能够避免数据不一致或者其他问题。 在这段代码中,synchronized
修饰的是userAccount.intern()
,intern()
是Java中的一个方法,它可以返回字符串对象的一个实例,如果内存中已存在该字符串,则返回已存在的实例,如果不存在,则创建一个新的实例。因此,这行代码的作用是对userAccount
字符串对象进行同步操作。如果有多个线程同时访问这段代码,并且它们都要修改userAccount
字符串对象,使用synchronized
可以保证同一时间只会有一个线程进入到这段代码中,避免多个线程同时修改userAccount
导致数据不一致的问题。
11、@TableField(exist = false)
private static final long serialVersionUID = 1L; 这东西的作用是什么?
这段代码是Java语言中使用MyBatis-Plus框架时,用于实体类字段的注解。其中:
@TableField
表示该注解用于标识实体类对应的数据库表字段。exist = false
表示该字段不是数据库表中的一列,即该字段不对应数据库中的实际列。serialVersionUID
是Java中的一个特殊变量,用于在序列化和反序列化对象时标识对象的版本,以保证对象的兼容性。在实体类中声明serialVersionUID
可以防止序列化和反序列化时出现版本不一致的问题。
12、@EqualsAndHashCode(callSuper = true) 的作用?
这是Java语言中使用Lombok框架时,用于生成equals和hashCode方法的注解。其中:
@EqualsAndHashCode
表示该注解用于生成equals和hashCode方法。callSuper = true
表示在生成的equals和hashCode方法中,将会调用父类的equals和hashCode方法,以确保子类与父类的对象比较时也能正确比较父类中的字段。 在使用Lombok框架时,通过在类上添加@EqualsAndHashCode(callSuper = true)
注解,可以简化开发人员编写equals和hashCode方法的过程,提高开发效率。同时,由于Lombok会自动为类生成equals和hashCode方法,避免了手动编写这些方法带来的风险和错误。
13、断言有什么用
断言是一种用于在代码中检查假设条件的机制。它可以帮助开发人员在编写代码时检查程序是否满足了预期的条件,如果条件不满足,则会引发AssertionError异常,从而提高了代码的健壮性和可靠性。 在软件开发过程中,开发人员通常会有各种假设和前提条件,例如函数参数的有效性、对象的状态等等。使用断言可以帮助开发人员在代码中明确地表达这些假设条件,并在运行时进行检查,从而及早发现和解决潜在的问题。 除了在开发过程中使用断言进行调试和测试,断言还可以在某些情况下作为一种错误检测和容错机制使用。例如,在编写高可靠性的系统时,可以使用断言来检查系统的状态是否处于一种预期的状态,如果发现状态异常,则可以采取相应的措施,例如恢复系统或者报警通知操作人员。 总之,断言是一种非常有用的编程工具,它可以帮助开发人员编写更加健壮、可靠和高效的代码。
14、使用了 GlobalFilter(编程式),全局请求拦截处理(类似 AOP)。这句话是什么意思
这句话指的是在一个Web应用程序中,使用了一种名为GlobalFilter的编程式拦截器来对全局的请求进行拦截和处理。GlobalFilter是Spring WebFlux框架提供的一种全局过滤器,它类似于AOP(面向切面编程)的思想,可以在请求处理的前后、异常处理等各个环节进行拦截和处理。使用GlobalFilter可以方便地对请求进行统一的预处理、鉴权、日志记录等操作,而无需在每个请求处理方法中单独处理。这样可以大大提高代码的复用性和可维护性,同时也可以更好地保障代码的安全性和可靠性。
编程式(Programmatic)指的是以编程的方式实现某种功能或处理某个问题,而不是通过配置或其他方式来实现。在编程式编程中,开发人员需要编写代码来实现特定的功能,这种方式通常需要更多的手动操作和编码工作。相对于声明式编程(Declarative),它更加灵活,可以更加精细地控制程序行为。在全局请求拦截处理中,使用编程式的方式实现GlobalFilter,可以提供更加灵活的拦截处理能力,满足不同场景下的需求。但是相对于声明式的方式,编程式也需要更多的代码维护和处理,需要更多的编程技巧和经验。
15、什么是装饰者模式?
装饰者模式是指在不改变原有对象的基础上,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更为灵活。 装饰者模式的主要角色:
- 抽象构件(Component):定义了抽象接口,为装饰者和被装饰者对象声明了公共接口。
- 具体构件(ConcreteComponent):是被装饰者,实现了抽象构件的接口。
- 抽象装饰器(Decorator):维护一个指向抽象构件对象的引用,并定义了与抽象构件一致的接口。
- 具体装饰器(ConcreteDecorator):是抽象装饰器的子类,负责给具体构件对象添加一些职责。 装饰者模式的实现方式是通过将一个对象包装到另一个对象中,从而形成一条装饰链。每个装饰器对象都引用了被装饰的对象,并定义了自己的装饰行为,这样就可以在不修改原有对象的情况下,动态地给对象添加新的行为。当需要增加新的行为时,只需要添加新的具体装饰器即可,而不需要修改原有的代码。
16、什么是魔法值?
在Java中,魔法值指的是代码中出现的一些不具备明确含义的常量值。这些常量值通常以硬编码的方式出现在代码中,而没有给出明确的说明或注释。这样的常量值不利于代码的可读性和可维护性,而且如果需要修改这些值时,还需要在代码的多个地方进行修改,增加了代码的复杂度和风险。 例如,以下代码中的数字常量就是魔法值:
if (statusCode == 200) {
// do something
}
2
3
在这个例子中,数字常量200并没有明确的含义,如果要理解它的意义,需要查看相关的文档或注释。而如果将它定义为一个常量,如下所示,就可以提高代码的可读性和可维护性:
private static final int HTTP_OK = 200;
if(statusCode == HTTP_OK) {
// do something
}
2
3
4
这样,在代码中使用常量名代替数字常量,可以使代码更加易读,易维护,并且可以提高代码的可复用性。因此,在编写Java代码时,尽可能避免使用魔法值,而是使用常量来代替。
17、什么是 rpc?
RPC(Remote Procedure Call)是一种远程过程调用协议,它允许不同的应用程序在分布式系统中通过网络相互调用,就像本地调用一样。RPC的目标是使分布式应用程序更容易编写,更容易理解和维护。 RPC的基本思想是:客户端像调用本地函数一样,通过传递参数调用远程服务,然后等待远程服务返回结果。RPC框架负责将客户端的请求转换成网络传输的消息,然后将消息发送给服务端,服务端接收到消息后进行处理,并将处理结果返回给客户端。 RPC的优点是:使得分布式应用程序的编写更加简单和高效,客户端和服务端可以使用不同的编程语言和框架,可以将应用程序的不同部分分布在不同的机器上,提高了应用程序的可伸缩性和可靠性。 RPC的缺点是:需要设计和实现通信协议、序列化、反序列化、错误处理、网络传输等细节,需要考虑网络故障、服务端负载均衡等问题,因此实现起来比较复杂。此外,RPC的性能也会受到网络延迟和带宽等因素的影响。
18、分析一下model包和model包下的dto包和vo包
在Java的Web开发中,通常会将数据模型(Model)按照功能和特性分成不同的包,其中比较常见的包有model包、dto包和vo包。
- model包:通常包含业务领域中的核心数据模型,也称为领域模型。它是对业务对象的抽象,描述了业务对象的属性和行为,通常与数据库中的表结构相对应。在应用程序中,model对象可以用来进行数据的持久化和业务逻辑的处理。
- dto包:DTO(Data Transfer Object)即数据传输对象,用于在应用程序的不同层之间传输数据。它通常包含了业务领域中的部分数据模型,但是与model对象不同的是,它并不包含业务逻辑,它只用于数据传输。DTO通常被用于客户端和服务器之间的数据传输,以及在不同服务之间传输数据。
- vo包:VO(Value Object)即值对象,也用于在应用程序的不同层之间传输数据。VO通常包含了业务领域中的部分数据模型,但是与DTO不同的是,VO通常用于向客户端展示数据,它通常会将一些属性进行格式化或者组合,以便于界面显示。VO对象通常只包含少量的属性,而且这些属性通常是只读的,不会进行修改。 综合来说,model包是业务领域中的核心数据模型,dto包是用于数据传输的对象,vo包则是用于向客户端展示数据的对象。这些包的设计可以使应用程序的不同层之间数据的传输和处理更加清晰和高效。
19、这里为什么是输出日志而不是抛异常,是避免服务挂掉吗?
try {
innerUserInterfaceInfoService.invokeInterfaceCount(userId, interfaceInfoId);
} catch (Exception e) {
log.error("invokeInterfaceCount error", e);
}
2
3
4
5
在这段代码中,捕获了invokeInterfaceCount()
方法的异常,并使用日志输出了异常信息。这种处理方式被称作异常屏蔽(Exception Masking),即将异常捕获并处理,而不是将异常继续抛出。
异常屏蔽的目的是为了防止异常传递到上层调用者,并影响程序的正常执行。在本段代码中,由于innerUserInterfaceInfoService.invokeInterfaceCount()
方法是一个远程调用,因此可能会存在网络故障、服务不可用等异常情况,这些异常如果直接抛出,会导致整个请求无法正常响应,从而影响用户体验。 因此,对于这种情况,使用日志输出异常信息,可以帮助开发人员及时了解异常情况,以便问题排查和修复。同时,程序也可以继续执行其他逻辑,提高了程序的健壮性和可靠性。 需要注意的是,在使用异常屏蔽时,应当尽量避免隐藏异常,并结合实际情况进行选择。如果异常是无法处理的,或者需要立即通知上层调用者,那么应当将异常重新抛出,并在上层进行处理。
# 遇到的难题:
1、遇到 TypeError: this.libOptions.parse is not a function
解决方法:执行以下命令安装 ESLint 8.22 版本:
npm install eslint@8.22.0 --save-exact
2、查询表格页为英文,这是因为删除了初始化的国际化文件导致的,有 Bug
解决方法:修改 src/pages/TableList/index.tsx 文件
更改 title
3、查询分页数据有误
解决方法:
开启 mybatis-plus 的驼峰映射
原因:sql
语句是 IService
内的方法,是属于 mybatis-plus
的,mybatis
的 xml
文件映射其实没有生效
4、数据无法加载
原因:修改文件的时候不小心把 interfaceInfoController 中的路径名也改了
5、添加接口数据时,请求参数有误
解决办法:
取消这个判断
6、调用 hutool 的 http 工具类,测试报错
原因:未启动服务器
启动服务器之后即可运行成功
7、一直登录不成功
要改这里,跳转的布局
8、Nacos 注册中心没有信息,网关项目空指针
原因:backend 项目的启动类中没有导入 @EnableDubbo
9、java.lang.IllegalStateException: Failed to check the status of the service com.chenmeng.provider.DemoService. No provider available for the service com.chenmeng.provider.DemoService from the url consumer://192.168.194.1/com.chenmeng.provider.DemoService?application=dubbo-springboot-demo-provider&background=false&dubbo=2.0.2&interface=com.chenmeng.provider.DemoService&methods=sayHello,sayHelloAsync,sayHello2&pid=1388®ister.ip=192.168.194.1&release=3.0.9&side=consumer&sticky=false×tamp=1684249636933 to the consumer 192.168.194.1 use dubbo version 3.0.9
这是因为提供者和调用方的接口类 DemoService
所在的目录不是同样的名字下
10、Map<Long, List<UserInterfaceInfo> interfaceInfoIdObjMap = userInterfaceInfoList.stream() .collect(Collectors.groupingBy(UserInterfaceInfo::getInterfaceInfoId));
这句话为什么会报java.lang.ClassCastException: com.chenmeng.project.model.vo.InterfaceInfoVO cannot be cast to com.chenmeng.cmapicommon.model.entity.UserInterfaceInfo
错误是指不能强行转换,把 UserInterfaceInfo
改成 InterfaceInfoVO
即可解决
11、响应错误
原因:一步步 debug 发现 accessKey 测试的时候用了中文,出现了乱码,导致 response 响应出错
12、
# TODO
1、追求性能的话可以注释,直接走缓存。这句话什么意思?应该怎么实现
该句话的意思是:如果追求性能,可以将从数据库查询用户信息的操作注释掉,直接从缓存中获取用户信息,以提高查询效率。 具体实现可以参考以下步骤:
- 在用户登录成功后,将用户信息存储到缓存中,例如:
// 用户登录成功后,将用户信息存储到缓存中
redisTemplate.opsForValue().set(USER_LOGIN_STATE + currentUser.getId(), currentUser);
2
其中,redisTemplate是Spring提供的与Redis交互的工具类,USER_LOGIN_STATE是常量,表示存储在缓存中的键值前缀,currentUser.getId()则是用户ID,表示具体的键值。 2. 修改获取当前登录用户信息的方法,先从缓存中获取用户信息,如果缓存中不存在则从数据库中查询,并将查询结果存储到缓存中,例如:
public User getLoginUser(HttpServletRequest request) {
// 先从Session中获取用户信息
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
User currentUser = (User) userObj;
if (currentUser == null || currentUser.getId() == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
// 从缓存中查询用户信息
String key = USER_LOGIN_STATE + currentUser.getId();
currentUser = redisTemplate.opsForValue().get(key);
if (currentUser == null) {
// 从数据库中查询用户信息
currentUser = this.getById(currentUser.getId());
if (currentUser == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
// 将查询结果存储到缓存中
redisTemplate.opsForValue().set(key, currentUser);
}
return currentUser;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
其中,redisTemplate.opsForValue().get(key)表示从缓存中获取指定键值的值,this.getById(userId)表示从数据库中查询指定ID的用户信息。 需要注意的是,在使用缓存的场景下,需要考虑缓存与数据库的数据一致性问题,即当用户信息发生变更时,需要及时更新缓存。可以在更新用户信息的方法中同时更新缓存,例如:
public void updateUser(User user) {
// 更新数据库中的用户信息
this.updateById(user);
// 更新缓存中的用户信息
redisTemplate.opsForValue().set(USER_LOGIN_STATE + user.getId(), user);
}
2
3
4
5
6
2、根据测试地址来调用模拟接口
利用反射来解决问题
核心代码如下:
public Object reflectionInterface(Class<?> reflectionClass, String methodName, String parameter, String accessKey, String secretKey) {
//构造反射类的实例
Object result = null;
try {
Constructor<?> constructor = reflectionClass.getDeclaredConstructor(String.class, String.class);
//获取SDK的实例,同时传入密钥
CmApiClient tempClient = (CmApiClient) constructor.newInstance(accessKey, secretKey);
//获取SDK中所有的方法
Method[] methods = tempClient.getClass().getMethods();
//筛选出调用方法
for (Method method : methods
) {
if (method.getName().equals(methodName)) {
//获取方法参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
Method method1;
if (parameterTypes.length == 0){
method1 = tempClient.getClass().getMethod(methodName);
return method1.invoke(tempClient);
}
method1 = tempClient.getClass().getMethod(methodName, parameterTypes[0]);
//getMethod,多参会考虑重载情况获取方法,前端传来参数是JSON格式转换为String类型
//参数Josn化
Gson gson = new Gson();
Object args = gson.fromJson(parameter, parameterTypes[0]);
return result = method1.invoke(tempClient, args);
}
}
} catch (Exception e) {
log.error("反射调用参数错误",e);
}
return result;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
这段代码通过反射机制,根据传入的类名和方法名,实例化相应的对象,调用相应的方法,并将参数传递给方法执行,最后返回结果。它可以灵活地调用不同类的方法,适用于一些动态性较强的场景,但需要注意反射调用的性能和安全性。