当前位置: 首页 > news >正文

Aop+自定义注解实现数据字典映射

数据字典

    Web项目开发中,字典表的一般都会存在,主要用来给整个系统提供基础服务。

  比如男女性别的类型可以使用0和1来进行表示,在存储数据和查询数据的时候,就可以使用字典表中的数据进行翻译处理。

   再比如之前做的一个项目中宠物类型包含老虎-1、海豚-2、大象-3、长颈鹿-4等等;做答题处理时的答题类型,比如单选题、多选题、填空题等等;

   比较常用的有用户类型,普通用户还是VIP用户等等;这些类型的数据也可以存储在数据字典中进行统一处理。

数据结构以及业务

举例:

在业务表中使用的是业务目录,而其中的“数据结构”,“数据目录类型”,“数据来源”使用的是字典表中的id,但我们在页面显示的时候,想用字典表中的value值,即我们在库里相应的业务表的外键存字典表的ID,查询的时候返回给前端在字典表中的value字段。

如以下表以及内容的展示:

目录表:

内容: 外键,字典的ID

如图所示:(字典表)需要我们在表中拿出外键所对应的Label

列举方法

   那有什么办法可以让我们查询出key的同时,将value值也查询出来,当时处理问题的时候想了三种解决方法:

1.要么就写sql 匹配。(在SQL查询的时候做字段的匹配,但是增加了SQL的复杂性不易维护)

2.要么就业务处理。得写个工具类(针对当时的情况感觉可以实现,然后查找了一些资料比如,自定义注解啥的)

3.再就是前端调两次接口,查询一次数据,再查询一次字典表做转译。(所涉及到的字段有四五个甚至更多,这是我问的别的同学,他们公司采用的就是这种方法)

根据查找资料以及实际考虑,最终采用了使用自定义注解的方式去做字段映射。

实现步骤:

首先展示项目的目录结构

总共三个,自定义注解,切面,具体实现

一 ,创建自定义注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {/*** 字典类型,对应数据库的类型,下方展示*/String dictType();/*** 实体类内对应的中文字段名,默认为“当前字段+Text”* <p>*  例如当前字段为“type”,则对应中文字段默认为“typeText”* 就是你在实体中想要给某个字段赋值,这个字段就要写成那个字段*/String dictField() default "";}

二,创建切面


@Slf4j
@Aspect
@Component
public class BydDaoDictAspect {
//  * `@Pointcut` 注解用于定义一个切点,切点是决定哪些方法应该被通知(advice)的表达式。
//	* `execution(* com.wiseom.asset.manage.service..*.*(..))` 是一个切点表达式,它表示匹配 `com.wiseom.asset.manage.service` 包及其子包下的所有类的所有方法。
//	* `doPointcut()` 方法本身没有执行任何操作,它只是为切点提供了一个标识符。@Pointcut("execution(* com.wiseom.asset.manage.service..*.*(..))")public void doPointcut() {}
//  * `@AfterReturning` 注解表示在匹配的方法成功执行并返回结果后执行通知。
//  * `pointcut = "doPointcut()"` 表示这个通知应用于之前定义的 `doPointcut` 切点。
//	* `returning = "result"` 捕获返回的结果,并将其作为 `result` 参数传递给通知方法。
//	* 在 `doAfterReturning` 方法中,`DictUtils.convertDict(result)` 是将返回的 `result` 对象转换为字典格式。如果在转换过程中发生异常,它会被捕获并记录到日志中。@AfterReturning(pointcut = "doPointcut()", returning = "result")public void doAfterReturning(JoinPoint pjp, Object result) {try {DictUtils.convertDict(result);} catch (Exception e) {log.error(String.valueOf(e));}}
}

备注:

1:切点在com.wiseom.asset.manage.service的原因,因为我们使用了mybitsplus ,在我们处理查询,或者执行SQL的时候大多都在service层就被处理了,所以切点设在了service层。

2:如果切点设置在Controller,则需要修改下方实现三中的 方法 convertDict,因为 Controller的返回值拿到的是 R 包裹的内容,返回值对象是R,而不是实体,具体问题查看下方的扩展四

三,创建实现


@Component
public class DictUtils {private static final String DICT_FIELD_SUFFIX = "Text";/*** 统一获取当前实体类涉及到的字典表数据,避免多次查询数据库造成的性能消耗* 这个工具类主要的改动就是这个,所以我就把这一段放在上面了* @param dictNames 字典表type值* @return 字典表数据*/@SneakyThrowsprivate static  Map<String, Map<Long, String>> getDictMap(List<String> dictNames) {//创建fegin的实例,调用系统的sys_dict_item表,需要新写一个接口final 	RemoteDictService remoteDictService = SpringContextHolder.getBean(RemoteDictService.class);//把注解里的所有字典的类型查出来,具体根据需求做查询List<SysDictItem> dictList = remoteDictService.getDictItemByType(dictNames);//根据类型做一个分组,这里对应的是 Map<DictType, Map<ID, Label>>return dictList.stream().collect(Collectors.groupingBy(SysDictItem::getDictType, Collectors.toMap(SysDictItem::getId, SysDictItem::getLabel, (v1, v2) -> v2)));}/*** 这是主方法主要是判断AOP后返回的内容,并根据判断条件拿到里面的内容*  然后先判断有哪些带有注解,根据注解拿到对应的dictType去库里查找对应的内容 *  根据拿到内容在对指定的字段dictField进行赋值*/public static void convertDict(Object target) {//判断对象是不是分页的if (target instanceof Page) {//拿到分页中的records对象里边包含实体的内容for(Object object : ((Page<?>)target).getRecords()){//拿到实体List<DictDefinition> dictDefinitions = getMetadata(object);// 如果没有注解,则直接返回if (CollectionUtils.isEmpty(dictDefinitions)) return;// 从字典定义中提取所有的注解的 dictType(数据库字典的类型)List<String> dictNames = dictDefinitions.stream().map(d -> d.getDict().dictType()).collect(Collectors.toList());// 根据字典类型获取字典映射Map<String, Map<Long, String>> dictMapMap = getDictMap(dictNames);// 转换target对象的字典字段doConvertDict(object, dictDefinitions, dictMapMap);}} elseif (target instanceof List) {// 将target强制转换为List<?>类型List<?> objectList = ((List<?>) target);// 使用CollectionUtils.isNotEmpty来检查列表是否非空if (CollectionUtils.isNotEmpty(objectList)) {// 获取列表中第一个元素的字典定义List<DictDefinition> dictDefinitions = getMetadata(objectList.get(0));// 如果没有注解,则直接返回if (CollectionUtils.isEmpty(dictDefinitions)) return;// 从字典定义中提取所有的注解的 dictType(数据库字典的类型)List<String> dictNames = dictDefinitions.stream().map(d -> d.getDict().dictType()).collect(Collectors.toList());// 根据字典类型获取字典映射Map<String, Map<Long, String>> dictMapMap = getDictMap(dictNames);// 遍历列表中的每个元素,并转换其字典字段objectList.forEach(t -> doConvertDict(t, dictDefinitions, dictMapMap));}} else {// 如果target不是List,则直接获取其字典定义List<DictDefinition> dictDefinitions = getMetadata(target);// 如果没有注解,则直接返回if (CollectionUtils.isEmpty(dictDefinitions)) return;// 从字典定义中提取所有的注解的 dictType(数据库字典的类型)List<String> dictNames = dictDefinitions.stream().map(d -> d.getDict().dictType()).collect(Collectors.toList());// 根据字典类型获取字典映射Map<String, Map<Long, String>> dictMapMap = getDictMap(dictNames);// 转换target对象的字典字段doConvertDict(target, dictDefinitions, dictMapMap);}}/*** 仅获取一次Dict元数据,降低多次反射造成的性能消耗* @param target 目标实体类* @return Dict元数据*/private static List<DictDefinition> getMetadata(Object target) {//这一段是判断存在注解的字段List<DictDefinition> dictDefinitions = new ArrayList<>();if (ClassUtils.isPrimitiveOrWrapper(target.getClass())|| target instanceof Map || target instanceof String) {return dictDefinitions;}List<Field> fields = FieldUtils.getAllFieldsList(target.getClass());for (Field field : fields) {Dict dict = AnnotationUtils.getAnnotation(field, Dict.class);if (dict != null) {DictDefinition dictDefinition = new DictDefinition();dictDefinition.setDict(dict);dictDefinition.setField(field);dictDefinitions.add(dictDefinition);}}return dictDefinitions;}@SneakyThrowsprivate static void doConvertDict(Object target, List<DictDefinition> dictDefinitions,Map<String, Map<Long, String>> dictMapMap) {for (DictDefinition dictDefinition : dictDefinitions) {//获取Dict注解和字段信息Dict dict = dictDefinition.getDict();Field field = dictDefinition.getField();//获取字典映射Map<Long, String> dictMap = dictMapMap.get(dict.dictType());//读取实体中带有注解的字段原有的值String dictCode = String.valueOf(FieldUtils.readField(target, field.getName(), true));//类型转换,我在库中用的存储的字段是String,所以需要进行类型的转换,如果你的库设置的不是,或者其他的类型,需要注意到这个地方Long longDictCode=Long.valueOf(dictCode);//拿到字典注解的labelString dictField = StringUtils.isEmpty(dict.dictField()) ? field.getName() + DICT_FIELD_SUFFIX : dict.dictField();//设置字段的字典文本值FieldUtils.writeField(target, dictField, dictMap.get(longDictCode), true);}}@Datapublic static class DictDefinition {private Dict dict;private Field field;}}

系统表的查询接口:

//这个我是在SysDictController下添加的接口,目的是实现查找多个类型的内容,同时还需要写个fegin接口以供别的模块使用
/*** 通过字典类型查找字典* @param types 类型* @return 同类型字典*/@PostMapping("/types")public List<SysDictItem> getDictByTypes(@RequestBody List<String> types) {return sysDictItemService.list(Wrappers.<SysDictItem>query().lambda().in(SysDictItem::getDictType, types));}

使用方法

直接在实体字段上方添加注解

1.dictType:数据库中的字典的类型

2.dictField:实体中赋值的字段

如上方使用方法所示,如果你想将字典中的label值给实体中的 catalogStructure,则标注

如果前端需要,一个原来的ID,一个label,那就需要创建一个DTO,如图所示,将dictField 后边写上你想要的字段名称就行了

四,备注以及扩展

这个是公司用的pigx框架,没用到的同学,可以跳过了,仅供参考,依据具体项目实际来定

参数的入值:

@AfterReturning(pointcut = "doPointcut()", returning = "result")public void doAfterReturning(JoinPoint pjp, Object result) {try {DictUtils.convertDict(result);} catch (Exception e) {log.error(String.valueOf(e));}}

这个代码中的result需要着重注意,他可能会存在判断的问题

举例:这个是正常的,只拿到这个返回的实体就行,在我们实现三中的方法convertDict所有if()的目的都是为了拿到返回值中的实体

比如底下这个图,分页返回的就需要做一个判断(实现三我已经加上了,这个做一个参考):

判断:

五:具体实现 优化1,多个字段的匹配,用“,”隔开代码优化


@Component
public class DictUtils {private static final String DICT_FIELD_SUFFIX = "Text";/*** 执行字典转换的公共方法* @param target 待转换的对象*/public static void convertDict(Object target) {//判断是否是分页if (target instanceof Page) {for (Object object : ((Page<?>) target).getRecords()) {convertDictInternal(object);}//是否是list} else if (target instanceof List) {if (CollectionUtils.isNotEmpty((List<?>) target)) {for (Object object : (List<?>) target) {convertDictInternal(object);}}} else {convertDictInternal(target);}}/*** 内部的字典转换实现方法* @param target 待转换的对象*/@SneakyThrowsprivate static void convertDictInternal(Object target) {// 获取目标对象的字典定义List<DictDefinition> dictDefinitions = getMetadata(target);// 如果没有字典定义则直接返回if (CollectionUtils.isEmpty(dictDefinitions)) {return;}// 提取字典类型并获取字典映射String commaSeparatedString = dictDefinitions.stream().map(d -> d.getDict().dictType()).collect(Collectors.joining(","));List<String> dictNames = Arrays.asList(commaSeparatedString.split(","));Map<String, Map<Long, String>> dictMapMap = getDictMap(dictNames);// 执行具体的字典转换操作doConvertDict(target, dictDefinitions, dictMapMap);}/*** 获取目标对象的字典定义* @param target 目标对象* @return 字典定义列表*/private  static List<DictDefinition> getMetadata(Object target) {List<DictDefinition> dictDefinitions = new ArrayList<>();// 排除基本类型、包装类型、Map 和 String 类型if (ClassUtils.isPrimitiveOrWrapper(target.getClass())|| target instanceof Map || target instanceof String) {return dictDefinitions;}// 获取目标对象的所有字段List<Field> fields = FieldUtils.getAllFieldsList(target.getClass());for (Field field : fields) {// 获取字段上的 Dict 注解Dict dict = AnnotationUtils.getAnnotation(field, Dict.class);if (dict!= null) {// 创建并添加字典定义DictDefinition dictDefinition = new DictDefinition();dictDefinition.setDict(dict);dictDefinition.setField(field);dictDefinitions.add(dictDefinition);}}return dictDefinitions;}/*** 根据字典名称获取字典映射* @param dictNames 字典名称列表* @return 字典映射*/@SneakyThrowsprivate static  Map<String, Map<Long, String>> getDictMap(List<String> dictNames) {final RemoteDictService remoteDictService = SpringContextHolder.getBean(RemoteDictService.class);List<SysDictItem> dictList = remoteDictService.getDictItemByType(dictNames);return new HashMap<>(dictList.stream().collect(Collectors.groupingBy(SysDictItem::getDictType, Collectors.toMap(SysDictItem::getId, SysDictItem::getLabel, (v1, v2) -> v2))));}/*** 执行具体的字典字段转换* @param target 目标对象* @param dictDefinitions 字典定义列表* @param dictMapMap 字典映射*/@SneakyThrowsprivate static  void doConvertDict(Object target, List<DictDefinition> dictDefinitions,Map<String, Map<Long, String>> dictMapMap) {for (DictDefinition dictDefinition : dictDefinitions) {Dict dict = dictDefinition.getDict();Field field = dictDefinition.getField();String[] dictTypes = dict.dictType().split(",");for (String dictType : dictTypes) {Map<Long, String> dictMap = dictMapMap.get(dictType.trim());// 读取字段的字典编码String dictCode = String.valueOf(FieldUtils.readField(target, field.getName(), true));// 类型转换Long longDictCode = Long.valueOf(dictCode);// 确定字典字段名String dictField = StringUtils.isEmpty(dict.dictField())? field.getName() + DICT_FIELD_SUFFIX : dict.dictField();// 设置字段的字典文本值if (dictMap!= null && dictMap.containsKey(longDictCode)) {FieldUtils.writeField(target, dictField, dictMap.get(longDictCode), true);}}}}@Datapublic static class DictDefinition {private Dict dict;private Field field;}
}

使用方式:

参考:

主要内容参考:

java自定义注解实现数据字典映射_字典映射 java-CSDN博客

分页扩展参考:

字典翻译@Dict - 莫大人 - 博客园

相关文章:

Aop+自定义注解实现数据字典映射

数据字典 Web项目开发中&#xff0c;字典表的一般都会存在&#xff0c;主要用来给整个系统提供基础服务。 比如男女性别的类型可以使用0和1来进行表示&#xff0c;在存储数据和查询数据的时候&#xff0c;就可以使用字典表中的数据进行翻译处理。 再比如之前做的一个项目中宠物…...

大语言模型(LLM)入门级选手初学教程 III

指令微调 一、指令数据的构建 包括任务描述&#xff08;也称为指令&#xff09;、任务输入-任务输出以及可选的示例。 Self-Instruct 指令数据生成&#xff1a;从任务池中随机选取少量指令数据作为示例&#xff0c;并针对Chat-GPT 设计精细指令来提示模型生成新的微调数据…...

STM32G0xx使用LL库将Flash页分块方式存储数据实现一次擦除可多次写入

STM32G0xx使用LL库将Flash页分块方式存储数据实现一次擦除可多次写入 参考例程例程说明一、存储到Flash中的数据二、Flash最底层操作(解锁&#xff0c;加锁&#xff0c;擦除&#xff0c;读写)三、从Flash块中读取数据五、测试验证 参考例程 STM32G0xx HAL和LL库Flash读写擦除操…...

SAP B1 认证考试习题 - 解析版(三)

前一篇&#xff1a;《SAP B1 认证考试习题 - 解析版&#xff08;二&#xff09;》 题目纯享版合集&#xff1a;《SAP B1 认证考试习题 - 纯享版》 五、运费&#xff08;附加费用&#xff09; 57. 以下哪个选项能够影响库存商品的价格 A. 仅为总量级别的附加费用 B. 只为行级…...

数据库开发规范

一、概述 ​ 本规范规定了&#xff0c;软件项目团队开发数据库的全流程规范。规范覆盖了数据库设计、管理及配套文件等。 二、项目阶段 ​ 项目阶段包括需求评审&#xff08;需求分析阶段&#xff09;、技术评审&#xff08;方案阶段&#xff09;、数据库开发&#xf…...

使用python向钉钉群聊发送消息

使用python向钉钉群聊发送消息 一、在钉钉群中新建机器人二、使用代码发送消息 一、在钉钉群中新建机器人 在群设置中添加机器人 选择自定义 勾选对应的安全设置 完成后会展示webhook&#xff0c;将地址复制出来&#xff0c;并记录&#xff0c;后面会用到 二、使用代码发送消…...

YOLOv11改进:SE注意力机制【注意力系列篇】(附详细的修改步骤,以及代码,与其他一些注意力机制相比,不仅准确度更高,而且模型更加轻量化。)

如果实验环境尚未搭建成功&#xff0c;可以参考这篇文章 ->【YOLOv11超详细环境搭建以及模型训练&#xff08;GPU版本&#xff09;】 文章链接为&#xff1a;YOLOv11超详细环境搭建以及模型训练&#xff08;GPU版本&#xff09;-CSDN博客 -------------------------------…...

STM32 基于HAL库和STM32cubeIDE的应用教程 (二)--GPIO的使用

如果有什么不懂的地方欢迎私聊博主&#xff0c;欢迎小白&#xff0c;博主必一一解答。 在 STM32 中&#xff0c;GPIO&#xff08;通用输入输出&#xff09;是与外部硬件接口进行交互的主要方式之一。STM32 HAL 库提供了简洁的接口来配置和控制 GPIO 引脚。下面是使用 STM32 HA…...

【毫米波雷达(七)】自动驾驶汽车中的精准定位——RTK定位技术

一、什么是RTK&#xff1f; RTK&#xff0c;英文全名叫做Real-time kinematic&#xff0c;也就是实时动态。这是一个简称&#xff0c;全称其实应该是RTK&#xff08;Real-time kinematic&#xff0c;实时动态&#xff09;载波相位差分技术。 二、RTK的组装 如上图所示&#x…...

Transformer和BERT的区别

Transformer和BERT的区别比较表&#xff1a; 两者的位置编码&#xff1a; 为什么要对位置进行编码&#xff1f; Attention提取特征的时候&#xff0c;可以获取全局每个词对之间的关系&#xff0c;但是并没有显式保留时序信息&#xff0c;或者说位置信息。就算打乱序列中token…...

linux 加载uPD720201固件

硬件 jetson orin nano jetpack 35.5.0 uPD720201是瑞萨推出的怕pcie扩展usb3.0芯片&#xff0c;支持flash主动加载与在系统被动加载 本文介绍如何做到没接flash情况下由系统加载固件 在uPD720201没接spi flash时候nano启动会报XhciDxe错误而自动重启&#xff0c;首先需要在ue…...

C语言中的信号量semaphore详解

在C语言中&#xff0c;**信号量&#xff08;Semaphore&#xff09;**是一种常用的同步机制&#xff0c;用于控制多个线程或进程对共享资源的访问。信号量可以实现类似于锁的效果&#xff0c;但更为灵活&#xff0c;适用于并发编程场景。 1. 什么是信号量 信号量可以看作是一个…...

0087__DirectX11 With Windows SDK--02 顶点/像素着色器的创建、顶点缓冲区

DirectX11 With Windows SDK--02 顶点/像素着色器的创建、顶点缓冲区-CSDN博客...

Windows换机华为擎云(银河麒麟V10+麒麟9000C CPU)后,使用selenium的程序怎么办(20241030)

原本的 seleniumChrome 已无法正常工作。chromedriver 报错&#xff1a;不支持 Linux/aarch64。 1、尝试Firefox、edge驱动。Firefox有一个geckodriver版本与Firefox版本的对照表&#xff0c;我看了一下&#xff0c;感觉他们是始终跟进新技术的。银河麒麟的很多库都是几年前的…...

linux 下 signal() 函数的用法,信号类型在哪里定义的?

--------------------------------------------------- author: hjjdebug date: 2024年 11月 07日 星期四 14:47:33 CST description: linux 下 signal() 函数的用法 --------------------------------------------------- signal 是linux 下最基础的进程通讯机制…...

享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

介绍 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享对象来减少内存使用&#xff0c;尤其是对于大量相似对象的场景。享元模式通常与工厂模式和单例模式结合使用&#xff0c;从而有效地控制和复用对象的创建。在享元模式中&am…...

【物联网技术】ESP8266 WIFI模块在STA模式下实现UDP与电脑/手机网络助手通信——UDP数据透传

前言:完成ESP8266 WIFI模块在STA模式下实现UDP与电脑/手机网络助手通信——实现UDP数据透传 STA模式,通俗来说就是模块/单片机去连接路由器/热点来通信。 UDP协议,是传输层协议,UDP没有服务器和客户端的说法。 本实验需要注意,wifi模块/单片机与电脑/手机需要连接在同一个…...

【SQL Server】华中农业大学空间数据库实验报告 实验一 数据库

实验目的 熟悉了解掌握SQL Server软件的基本操作与使用方法&#xff0c;认识界面&#xff0c;了解其两个基本操作系统文件&#xff0c;并能熟练区分与应用交互式与T-SQL式两种方法在SQL Server中如何进行操作&#xff1b;学习有关数据库的基本操作&#xff0c;包括&#xff1a…...

操作系统页面置换算法Java实现(LFU,OPT,LRU,LFU,CLOCK)

FIFO先进先出算法 java import java.util.LinkedList; import java.util.Queue; public class Main { //先进先出的思想 是 用一个队列去模拟数据 如果当前不存在就是发生缺页中断了 就需要添加 如果已经满了 将队头的元素出队 即可 //先进先出 就是一个数组 frameCount publi…...

Request和Response

前言 这一节主要讲的是Request和Response还有一些实例 1. 介绍 就是这两个参数 WebServlet("/demo7") public class ServletDemo7 extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExcepti…...

【青牛科技】GC8549替代LV8549/ONSEMI在摇头机、舞台灯、打印机和白色家电等产品上的应用分析

引言 在现代电子产品中&#xff0c;控制芯片的性能直接影响到设备的功能和用户体验。摇头机、舞台灯、打印机和白色家电等领域对控制精度、功耗和成本等方面的要求日益提高。LV8549/ONSEMI等国际品牌的芯片曾是这些产品的主要选择&#xff0c;但随着国内半导体技术的进步&…...

(十二)JavaWeb后端开发——MySQL数据库

目录 1.数据库概述 2.MyQSL 3.数据库设计 DDL 4.MySQL常见数据类型 5.DML 1.数据库概述 数据库&#xff1a;DataBase(DB)&#xff0c;是存储和管理数据的仓库 数据库管理系统&#xff1a;DataBase ManagementSystem(DBMS)&#xff0c;操纵和管理数据库的大型软件 SQL&a…...

pnpm管理多工作区依赖

pnpm是一个支持多包仓库的一个包管理工具,那么怎么可以在项目根目录下执行pnpm install的时候,也能同步让所有的工作区都能够通安装依赖呢? 方式一,在执行pnpm install指令的时候,添加recursive参数: pnpm install --recursive 方式二,在项目的根目录下通过pnpm的配置文件p…...

如何在本地Linux服务器搭建WordPress网站结合内网穿透随时随地可访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…...

二、应用层,《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》

文章目录 零、前言一、应用层协议原理1.1 网络应用的体系结构1.1.1 客户-服务器(C/S)体系结构1.1.2 对等体&#xff08;P2P&#xff09;体系结构1.1.3 C/S 和 P2P体系结构的混合体 1.2 进程通信1.2.1 问题1&#xff1a;对进程进行编址&#xff08;addressing&#xff09;&#…...

面粉直供系统|基于java和小程序的食品面粉直供系统设计与实现(源码+数据库+文档)

面粉直供系统 目录 基于java和小程序的食品面粉直供系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#x…...

十四:java web(6)-- Spring Spring MVC

目录 Spring MVC 1.1 Spring MVC 概述 1.1.1 什么是 MVC 模式 1.1.2 Spring MVC 工作原理 1.2 Spring MVC 核心组件 1.2.1 DispatcherServlet 1.2.2 控制器&#xff08;Controller&#xff09; 1.2.3 请求映射&#xff08;RequestMapping&#xff09; 1.2.4 视图解析器…...

Java代码实现策略模式处理支付付款业务

1.需求:因为付款功能集成的第三方支付SDK越来越来多不好维护,改用策略模式实现,来代替代码中多余的if else 判断。 2.什么是策略模式? 策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式将不同的算法封装成独立的策略类,并使这些…...

unity3d————四元数概念

一、定义与表示 四元数是由一个实数部分和三个虚数部分组成&#xff0c;通常表示为q w xi yj zk&#xff0c;其中w是实数&#xff0c;x、y、z是实数系数&#xff0c;i、j、k是虚数单位&#xff0c;满足以下关系&#xff1a; i j k -1ij k&#xff0c;ji -kjk i&…...

spring相关的面试题

Spring 框架是 Java 开发中最常用的框架之一&#xff0c;因此在面试中经常会被问到与 Spring 相关的问题。以下是一些常见的 Spring 面试题及其答案。 基础概念 什么是 Spring 框架&#xff1f; Spring 框架是一个开源的 Java 平台&#xff0c;用于构建企业级应用程序。它提供…...