Excel Module: Iteration #1 EasyExcel生成下拉列表模版时传入动态参数查询下拉数据
系列文章
- EasyExcel生成带下拉列表或多级级联列表的Excel模版+自定义校验导入数据(修订)
目录
- 系列文章
- 前言
- 仓库
- 一、实现
- 1.1 下拉元数据对象
- 1.2 构建下拉元数据的映射关系
- 1.3 框架方式
- 1.3.1 框架实现
- 1.3.2 框架用例
- 模版类
- 加载下拉业务
- 导出接口
- 1.4 EasyExcel方式
- 1.4.1 EasyExcel用例
- 导出接口
- 二、效果
- 2.1 下拉sheet
- 2.2 业务sheet
- 附录
- SpELHelper
前言
有同好提过这问题, 有一定的使用场景, 最近设计了一下并落地了, 支持直接使用框架方式或直接使用EasyExcel方式.
该迭代仅限使用SpEL能力最新版本代码, 历史版本忽略.
仓库
仓库: excel-common-spring-boot-starter (请参考最新代码, 文档内容更新不会很勤快, 没License看得上就随便用)
一、实现
核心逻辑: 创建下拉元数据对象时需要通过解析SpEL
表达式获取下拉数据, 该能力提供的上下文对象EvaluationContext
支持传入自定义参数, 并可以根据表达式指定的参数名从上下文中获取到指定参数并传给指定的调用方法.
调用方式: 使用框架和直接使用EasyExcel的两种方式, 在传入动态参数的方式上有所不同, 用例 部分会通过代码说明.
例如: SpEL表达式为 @xxxBean.findAllByTypeAndCode(#type, #code)
- @开头指定选择SpringBean的名称
- .findAllByTypeAndCode指定调用该bean的方法
- #type和#code指定从表达式上下文中解析名为 type 和 code 的 变量, 并传入findAllByTypeAndCode()方法.
1.1 下拉元数据对象
解析表达式时, 通过Visitor将参数设置到上下文中.
- SpELHelper 见 附录 部分
/*** @author hp*/
@Slf4j
@Getter
@Setter
public abstract class AbstractExcelSelectModel<T> {protected int headLayerCount;protected T options;protected String columnName;protected int columnIndex;protected String parentColumnName;protected int parentColumnIndex;protected int firstRow;protected int lastRow;public AbstractExcelSelectModel(@Nonnull Field field, @Nonnull ExcelSelect excelSelect, @Nullable ExcelProperty excelProperty, int defaultSort, @Nullable Map<String, Object> parameters) {final Optional<ExcelProperty> excelPropertyOpt = Optional.ofNullable(excelProperty);this.headLayerCount = excelPropertyOpt.map(property -> property.value().length).orElse(1);this.firstRow = Math.max(excelSelect.firstRow(), this.headLayerCount);this.lastRow = excelSelect.lastRow();this.parentColumnName = excelSelect.parentColumnName();this.columnName = excelPropertyOpt.map(property -> property.value()[this.headLayerCount - 1]).orElse(field.getName());this.columnIndex = excelPropertyOpt.map(property -> property.index() > -1 ? property.index() : defaultSort).orElse(defaultSort);this.options = resolveOptions(excelSelect, parameters);}public boolean hasParentColumn() {return StrUtil.isNotEmpty(this.parentColumnName);}@SuppressWarnings("unchecked")@Nullableprotected T resolveOptions(@Nonnull ExcelSelect excelSelect, @Nullable Map<String, Object> parameters) {final ExcelOptions excelOptions = excelSelect.options();if (StrUtil.isEmpty(excelOptions.expression())) {log.warn("The ExcelSelect on {} has no options whatsoever.", this.columnName);return null;}final SpELHelper spELHelper = SpringUtil.getBean(SpELHelper.class);return (T) spELHelper.newGetterInstance(excelOptions.expression()).apply(null,// 在这里向上下文中设置自定义变量.(evaluationContext -> Optional.ofNullable(parameters).ifPresent(map -> map.forEach(evaluationContext::setVariable))));}
}
1.2 构建下拉元数据的映射关系
Convention: @Nullable Map<String, Object> parameters
参数定义为Map集合类型
提交动态数据的入口, 同时根据实际列注解情况构建下拉元数据的映射关系
/*** @author hp*/
@Slf4j
@UtilityClass
public class ExcelSelectHelper {@Nullablepublic static <T> Map<Integer, ? extends AbstractExcelSelectModel<?>> createSelectionMapping(@Nonnull Class<T> dataClass) {return createSelectionMapping(dataClass, null);}@Nullablepublic static <T> Map<Integer, ? extends AbstractExcelSelectModel<?>> createSelectionMapping(@Nonnull Class<T> dataClass, @Nullable Map<String, Object> parameters) {final Field[] fields = ReflectUtil.getFields(dataClass);final AtomicInteger fieldIndex = new AtomicInteger(0);final Map<Integer, ? extends AbstractExcelSelectModel<?>> selectionMapping = Arrays.stream(fields).map(field -> {final ExcelSelect excelSelect = AnnotatedElementUtils.getMergedAnnotation(field, ExcelSelect.class);if (Objects.isNull(excelSelect)) {log.debug("No ExcelSelect annotated on {}, skip processing", field.getName());fieldIndex.getAndIncrement();return null;}final ExcelProperty excelProperty = AnnotatedElementUtils.getMergedAnnotation(field, ExcelProperty.class);AbstractExcelSelectModel<?> excelSelectModel;if (StrUtil.isNotEmpty(excelSelect.parentColumnName())) {excelSelectModel = new ExcelCascadeModel(field, excelSelect, excelProperty, fieldIndex.getAndIncrement(), parameters);} else {excelSelectModel = new ExcelSelectModel(field, excelSelect, excelProperty, fieldIndex.getAndIncrement(), parameters);}return excelSelectModel;}).filter(Objects::nonNull).collect(Collectors.toMap(AbstractExcelSelectModel::getColumnIndex, Function.identity(), (a, b) -> a));if (MapUtil.isEmpty(selectionMapping)) {return null;}// 设置父列索引final Map<String, Integer> columnNamedMapping = selectionMapping.values().stream().collect(Collectors.toMap(AbstractExcelSelectModel::getColumnName, AbstractExcelSelectModel::getColumnIndex));selectionMapping.forEach((k, v) -> {if (v.hasParentColumn() && columnNamedMapping.containsKey(v.getParentColumnName())) {v.setParentColumnIndex(columnNamedMapping.get(v.getParentColumnName()));}});return selectionMapping;}
}
1.3 框架方式
框架方式基于SpringAOP能力, 纯静态配置方式导出模版或数据, 所以无法通过人为调用的方式提交动态参数.
1.3.1 框架实现
同动态指定导出文件名称的方式相同, 在导出时, 通过向HttpServletRequest
对象中设置指定Key(ExcelConstants.DROPDOWN_QUERY_PARAMS_ATTRIBUTE_KEY
)的Attributes, 根据约定, 框架将通过该指定Key查询是否存在参数, 有则使用.
框架通过Enhance类配置ExcelWriterBuilder
和ExcelWriterSheetBuilder
, 并且框架考虑自动导出多sheet情况, 所以在enhanceExcel()
中获取动态参数并处理.
/*** @author hp*/
@Slf4j
public class ExcelSelectExcelWriterBuilderEnhance implements ExcelWriterBuilderEnhance {protected final AtomicInteger selectionColumnIndex = new AtomicInteger(0);protected Map<Class<?>, Map<Integer, ? extends AbstractExcelSelectModel<?>>> selectionMapMapping = Maps.newHashMap();@SuppressWarnings("unchecked")@Overridepublic ExcelWriterBuilder enhanceExcel(ExcelWriterBuilder writerBuilder,ResponseExcel responseExcel,Collection<? extends Class<?>> dataClasses,HttpServletRequest request,HttpServletResponse response) {final Object attribute = Objects.requireNonNull(request).getAttribute(ExcelConstants.DROPDOWN_QUERY_PARAMS_ATTRIBUTE_KEY);final Map<String, Object> parameters = Optional.ofNullable(attribute).map(attr -> {Preconditions.checkArgument(attr instanceof Map<?, ?>);return (Map<String, Object>) attribute;}).orElse(null);dataClasses.forEach(dataClass -> selectionMapMapping.put(dataClass, ExcelSelectHelper.createSelectionMapping(dataClass, parameters)));return writerBuilder.registerWriteHandler(new SelectDataWorkbookWriteHandler());}@Overridepublic ExcelWriterSheetBuilder enhanceSheet(ExcelWriterSheetBuilder writerSheetBuilder,Integer sheetNo,String sheetName,Class<?> dataClass,Class<? extends HeadGenerator> headEnhancerClass,String templatePath) {if (selectionMapMapping.containsKey(dataClass)) {final Map<Integer, ? extends AbstractExcelSelectModel<?>> selectionMapping = selectionMapMapping.get(dataClass);writerSheetBuilder.registerWriteHandler(new SelectDataSheetWriteHandler(selectionColumnIndex, selectionMapping));}return writerSheetBuilder;}
}
1.3.2 框架用例
模版类
/*** @author hp*/
@EqualsAndHashCode(callSuper = true)
@Data
public class DynamicParametersExcelTemplate extends ExcelTemplate {@ExcelSelect(options = @ExcelOptions(expression = "@excelSelectDynamicDataHandler.findAll()"))@ExcelProperty("动态单列下拉列表")private LocalDate dynamicSelectColumn;@ExcelProperty("非下拉列No3")private String noneDropdownNo3;@ExcelSelect(options = @ExcelOptions(expression = "@excelSelectDynamicParameterDataHandler.findAllForParentByType(#type)"))@ExcelProperty("动态参数父列")private Integer dynamicParameterParentColumn;@ExcelProperty("非下拉列No1")private String noneDropdownNo1;@ExcelProperty("非下拉列No2")private String noneDropdownNo2;@ExcelSelect(parentColumnName = "动态参数父列",options = @ExcelOptions(expression = "@excelSelectDynamicParameterDataHandler.findAllForChildrenByValueGt(#value)"))@ExcelProperty("动态参数子列")private Integer dynamicParameterChildColumn;
}
加载下拉业务
/*** @author hp*/
@Component
public class ExcelSelectDynamicParameterDataHandler {public List<String> findAllForParentByType(String type) {final Map<String, List<String>> map = Maps.newHashMap();map.put("TYPE-A", List.of("1", "2", "3", "4"));map.put("TYPE-B", List.of("一", "二", "三", "四"));return map.getOrDefault(type, Collections.emptyList());}public Map<String, List<Integer>> findAllForChildrenByValueGt(Integer limitation) {final Map<String, List<Integer>> map = Maps.newHashMap();map.put("1", Stream.of(10, 20, 30, 40, 50, 60).filter(i-> i> limitation).toList());map.put("2", Stream.of(30, 40, 50, 60, 70, 80, 90).filter(i-> i> limitation).toList());return map;}
}
导出接口
@ResponseExcel(name = "DynamicParametersExcelTemplate",sheets = {@Sheet(sheetName = "sheet", sheetNo = 0),},enhancement = {ExcelSelectExcelWriterBuilderEnhance.class}
)
@PostMapping("template/sheet/single/DynamicParametersExcelTemplate")
public List<DynamicParametersExcelTemplate> singleSheet5(HttpServletRequest request) {final Map<String, Object> map = Maps.newHashMap();map.put("type","TYPE-A");map.put("value",40);request.setAttribute(ExcelConstants.DROPDOWN_QUERY_PARAMS_ATTRIBUTE_KEY, map);return Collections.singletonList(new DynamicParametersExcelTemplate());
}
1.4 EasyExcel方式
原生方式相当于很多框架做的配置工作都给人来完成, 那自然很容易拿到提交动态参数的入口, 可以直接提交参数.
1.4.1 EasyExcel用例
导出接口
在设置handler时, 直接将下拉元数据映射提交给 SelectDataSheetWriteHandler
即可, 此时可以提交动态参数, 用例里偷懒写了null.
new SelectDataSheetWriteHandler(index, ExcelSelectHelper.createSelectionMapping(MultipleSheetNo1ExcelTemplate.class, null))
@PostMapping("/easyexcel/template")
public void template(HttpServletRequest request, HttpServletResponse response) {String filename = "文件名称";final AtomicInteger index = new AtomicInteger(0);String userAgent = request.getHeader("User-Agent");if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {// 针对IE或者以IE为内核的浏览器:filename = java.net.URLEncoder.encode(filename, StandardCharsets.UTF_8);} else {// 非IE浏览器的处理:filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);}response.setContentType("application/vnd.ms-excel");response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", filename + ".xlsx"));response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-cache");response.setDateHeader("Expires", -1);response.setCharacterEncoding("UTF-8");final ExcelWriterBuilder excelWriterBuilder;try {excelWriterBuilder = EasyExcel.write(response.getOutputStream());} catch (IOException e) {throw new RuntimeException(e);}try (ExcelWriter excelWriter = excelWriterBuilder.registerWriteHandler(new SelectDataWorkbookWriteHandler()).build()) {WriteSheet writeSheet = EasyExcel.writerSheet(0, "sheet名称").head(MultipleSheetNo1ExcelTemplate.class).registerWriteHandler(new SelectDataSheetWriteHandler(index, ExcelSelectHelper.createSelectionMapping(MultipleSheetNo1ExcelTemplate.class, null))).build();excelWriter.write(new ArrayList<String>(), writeSheet);WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "sheet名称2").head(MultipleSheetNo2ExcelTemplate.class).registerWriteHandler(new SelectDataSheetWriteHandler(index, ExcelSelectHelper.createSelectionMapping(MultipleSheetNo2ExcelTemplate.class, null))).build();excelWriter.write(new ArrayList<String>(), writeSheet2);excelWriter.finish();} catch (Exception e) {log.error("导出Excel文件异常", e);}
}
二、效果
2.1 下拉sheet
可见根据框架用例的条件和查询方法, TYPE-A 类型的数据和 大于40的数据被用于创建下拉选项
2.2 业务sheet
附录
SpELHelper
package com.luban.common.base.utils;import cn.hutool.core.util.StrUtil;
import com.luban.common.base.visitor.Visitor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.*;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;/*** 很多判断是Groovy语法* <p>* Tips:* <ul>* <li>字符串单引号. 可以调用方法或访问属性</li>* <li>属性首字母大小写不敏感</li>* <li>集合元素: Map用 {@code map['key']} 获取元素, Array/List用 {@code 集合名称[index]} 获取元素</li>* <li>定义List: {@code {1,2,3,4} 或 {{'a','b'},{'x','y'}} }</li>* <li>instance of: {@code 'xyz' instanceof T(int)}</li>* <li>正则: {@code '字符串' matches '正则表达式'}</li>* <li>逻辑运算符: {@code !非 and与 or或}</li>* <li>类型: {@code java.lang包下直接用, 其他的要用T(全类名)}</li>* <li>构造器: {@code new 全类名(构造参数)}</li>* <li>变量: StandardEvaluationContext当中的变量 {@code #变量名称 }</li>* <li>#this: 当前解析的对象</li>* <li>#root: 上下文的根对象</li>* <li>Spring Bean引用: {@code @beanName} </li>* <li>三元表达式和Java一样</li>* <li>Elvis Operator: {@code Names?:'Unknown'} Names为空提供默认值</li>* <li>防NPE操作符: {@code PlaceOfBirth?.City} 如果为NULL 防止出现NPE</li>* <li>筛选集合元素: {@code 集合.?[筛选条件]} 如果是Map集合,Map.Entry为当前判断对象</li>* <li>筛选第一个满足集合元素: {@code 集合.^[筛选条件]}</li>* <li>筛选第一个满足集合元素: {@code 集合.$[筛选条件]}</li>* <li>集合映射,类似StreamAPI的map()再collect(): 使用语法 {@code 集合.![映射规则]}, Map集合类似上述说明</li>* <li>表达式模版: 默认{@code #{} }, 指定解析模版内部的内容</li>* </ul>** @author hp*/@Slf4j
@Configuration
public class SpELHelper implements ApplicationContextAware {private BeanResolver beanResolver;private final ExpressionParser expressionParser = new SpelExpressionParser();private final ParserContext parserContext = ParserContext.TEMPLATE_EXPRESSION;public <T, R> StandardSpELGetter<T, R> newGetterInstance(String expression) {return new StandardSpELGetter<>(expression, new StandardEvaluationContext());}public <T, R> StandardSpELSetter<T, R> newSetterInstance(Field field) {return new StandardSpELSetter<>(field);}@Overridepublic void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {this.beanResolver = new BeanFactoryResolver(applicationContext);}public class StandardSpELGetter<T, R> implements BiFunction<T, Visitor<EvaluationContext>, R> {private final Expression expression;private final EvaluationContext evaluationContext;private StandardSpELGetter(String expression, EvaluationContext evaluationContext) {if (StrUtil.isNotEmpty(expression) && expression.startsWith(parserContext.getExpressionPrefix())) {this.expression = expressionParser.parseExpression(expression, parserContext);} else {this.expression = expressionParser.parseExpression(expression);}this.evaluationContext = Objects.requireNonNull(evaluationContext);if (this.evaluationContext instanceof StandardEvaluationContext standardEvaluationContext) {standardEvaluationContext.setBeanResolver(beanResolver);}}@SuppressWarnings("unchecked")@Overridepublic R apply(T data, Visitor<EvaluationContext> visitor) {Optional.ofNullable(visitor).ifPresent(v -> v.visit(evaluationContext));return (R) expression.getValue(evaluationContext, data);}public R apply(T data) {return apply(data, Visitor.defaultVisitor());}}public class StandardSpELSetter<T, R> implements BiConsumer<T, Collection<R>> {private final String fieldName;private final boolean isCollection;private final Expression expression;private StandardSpELSetter(Field field) {this.fieldName = Objects.requireNonNull(field).getName();this.expression = expressionParser.parseExpression(fieldName);this.isCollection = Collection.class.isAssignableFrom(Objects.requireNonNull(field).getType());}@Overridepublic void accept(T data, Collection<R> result) {if (isCollection) {this.expression.setValue(data, result);} else {int size = result.size();if (size == 1) {this.expression.setValue(data, result.stream().findFirst().get());} else {log.error("write join result to {} error: Too many results, field is {}, data is {}", data, fieldName, result);}}}}
}
相关文章:

Excel Module: Iteration #1 EasyExcel生成下拉列表模版时传入动态参数查询下拉数据
系列文章 EasyExcel生成带下拉列表或多级级联列表的Excel模版自定义校验导入数据(修订) 目录 系列文章前言仓库一、实现1.1 下拉元数据对象1.2 构建下拉元数据的映射关系1.3 框架方式1.3.1 框架实现1.3.2 框架用例模版类加载下拉业务导出接口 1.4 EasyExcel方式1.4.1 EasyExce…...
【回溯算法】【Python实现】TSP旅行售货员问题
文章目录 [toc]问题描述回溯算法Python实现时间复杂性 问题描述 给定一组城市和它们之间的距离矩阵,找到一条距离最短的路径,使得旅行商从一个城市出发,经过所有城市恰好一次,并最终回到出发城市 回溯算法 旅行售货员问题的解空间…...
Java处理xml
Java处理xml DOM(Document Object Model)读取写入参考文献[Java DOM 教程](https://geek-docs.com/java/java-tutorial/dom.html#ftoc-heading-5) DOM(Document Object Model) Java的DOM(Document Object Model&#…...

软考中级-软件设计师 (十一)标准化和软件知识产权基础知识
一、标准化基础知识 1.1标准的分类 根据适用的范围分类: 国际标准指国际化标准组织(ISO)、国际电工委员会(IEC)所制定的标准,以及ISO所收录的其他国际组织制定的标准。 国家标准:中华人民共和…...

pytest教程-46-钩子函数-pytest_sessionstart
领取资料,咨询答疑,请➕wei: June__Go 上一小节我们学习了pytest_report_testitemFinished钩子函数的使用方法,本小节我们讲解一下pytest_sessionstart钩子函数的使用方法。 pytest_sessionstart 是 Pytest 提供的一个钩子函数,…...

Windows内核函数 - ASCII字符串和宽字符串
本章介绍了Windows内核中字符串处理函数、文件读写函数、注册表读写函数。这些函数是DDK提供的运行时函数,他们比标准C语言的运行时函数功能更丰富。普通的C语言运行时库是不能在内核模式下使用的,必须使用DDK提供的运行时函数。 和应用程序一样…...
从零开始学习MySQL 事务处理
事务处理与ACID特性 事务是数据库操作的基本单元,它确保一组操作要么全部成功,要么全部失败,以此来维护数据库的一致性。这四个字母缩写ACID代表了事务的四大特性: 原子性(Atomicity)**:事务被…...
字符数组以及字符串相关的几个函数
一.字符数组 1.定义:格式如下 char a[10]; //此处就表示定义了一个长度为10的字符数组 2.引用: 也和其余的数组一样,是下标引用。 3.初始化: 如下代码为字符数组初始化的几种情况: int main() {char arr[5] {…...
AOP面向切面编程
1,注入依赖 <!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</grou…...

C# WinForm —— 15 DateTimePicker 介绍
1. 简介 2. 常用属性 属性解释(Name)控件ID,在代码里引用的时候会用到,一般以 dtp 开头Format设置显示时间的格式,包含Long: Short: Time: Custom:采用标准的时间格式 还是 自定义的格式CustomFormat自定…...
SpringBoot中六种批量更新Mysql 方式效率对比
SpringBoot中六种批量更新Mysql 方式效率对比 先上结论吧,有空可以自测一下,数据量大时运行一次还时挺耗时的 效率比较 小数据量时6中批量更新效率不太明显,根据项目选择合适的即可,以1万条为准做个效率比较,效率从高到低一次排名如下 replace into和ON DUPLICATE KEY效率最…...

【SpringBoot】SpringBoot整合jasypt进行重要数据加密
📝个人主页:哈__ 期待您的关注 目录 📕jasypt简介 🔥SpringBoot使用jasypt 📂创建我需要的数据库文件 📕引入依赖 🔓配置数据库文件(先不进行加密) 🌙创…...
【Go语言入门学习笔记】Part1.梦开始的地方
一、前言 经过一系列的学习,终于有时间来学习一些新的语言,Go语言在现在还是比较时髦的,多一个技能总比不多的好,故有时间来学一下。 二、配置环境 按照网络中已有的配置方法配置好,本人采用了Jetbrain的Goland&#…...
数据特征降维 | 主成分分析(PCA)附Python代码
主成分分析(Principal Component Analysis,PCA)是一种常用的数据降维技术和探索性数据分析方法,用于从高维数据中提取出最重要的特征并进行可视化。 PCA的基本思想是通过线性变换将原始数据投影到新的坐标系上,使得投影后的数据具有最大的方差。这些新的坐标轴称为主成分…...
当服务实例出现故障时,Nacos如何处理?
当服务实例出现故障时,Nacos的应对策略 在微服务架构日益盛行的今天,服务之间的稳定性与可靠性成为了我们架构师们不得不面对的重要课题。尤其是在面对服务实例出现故障时,如何确保整个系统的稳定运行,成为了我们首要考虑的问题。…...

遥感数据集制作(Potsdam数据集为例):TIF图像转JPG,TIF标签转PNG,图像重叠裁剪
文章目录 TIF图像转JPGTIF标签转PNG图像重叠裁剪图像重命名数据集转COCO格式数据集转VOC格式 遥感图像不同于一般的自然图像,由于波段数量、图像位深度等原因,TIF图像数据不能使用简单的格式转换方法。本文以Potsdam数据集为例,制作能够直接用…...
根据web访问日志,封禁请求量异常的IP,如IP在半小 时后恢复正常则解除封禁
在网络安全日益受到重视的今天,如何有效防范恶意流量和攻击成为了每个网站管理员必须面对的问题。恶意流量不仅会影响网站的正常运行,还可能导致服务器崩溃,给网站带来不可估量的损失。为了应对这一问题,我们特别推出了一款实用的…...
2.go语言初始(二)
本篇博客涉及到go 的基础数据类型、 go 语言中的运算符、转义字符、格式化输出、字符串操作 go 语言中的运算符 在 go 语言中,基本数据类型主要包括以下几类:整数类型、浮点数类型、复数类型、布尔类型、字符串类型、字节类型(byte…...
MQTT对比HTTP
吞吐量:根据3G网络的测量结果,MQTT的吞吐量比HTTP快93倍。这意味着在相同的网络条件下,MQTT能够更有效地传输数据,从而在处理大量数据或实时数据传输时具有更高的效率。架构与模式:MQTT基于发布/订阅模型,提…...

暴力数据结构之二叉树(堆的相关知识)
1. 堆的基本了解 堆(heap)是计算机科学中一种特殊的数据结构,通常被视为一个完全二叉树,并且可以用数组来存储。堆的主要应用是在一组变化频繁(增删查改的频率较高)的数据集中查找最值。堆分为大根堆和小根…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
6.计算机网络核心知识点精要手册
计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法:数据与控制信息的结构或格式,如同语言中的语法规则语义:控制信息的具体含义和响应方式,规定通信双方"说什么"同步:事件执行的顺序与时序…...

二叉树-144.二叉树的前序遍历-力扣(LeetCode)
一、题目解析 对于递归方法的前序遍历十分简单,但对于一位合格的程序猿而言,需要掌握将递归转化为非递归的能力,毕竟递归调用的时候会调用大量的栈帧,存在栈溢出风险。 二、算法原理 递归调用本质是系统建立栈帧,而非…...

联邦学习带宽资源分配
带宽资源分配是指在网络中如何合理分配有限的带宽资源,以满足各个通信任务和用户的需求,尤其是在多用户共享带宽的情况下,如何确保各个设备或用户的通信需求得到高效且公平的满足。带宽是网络中的一个重要资源,通常指的是单位时间…...