Excel Module: Iteration #1 EasyExcel生成下拉列表模版时传入动态参数查询下拉数据

news2025/1/18 9:08:29

系列文章

  1. 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指定从表达式上下文中解析名为 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")
    @Nullable
    protected 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 {

    @Nullable
    public static <T> Map<Integer, ? extends AbstractExcelSelectModel<?>> createSelectionMapping(@Nonnull Class<T> dataClass) {
        return createSelectionMapping(dataClass, null);
    }

    @Nullable
    public 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类配置ExcelWriterBuilderExcelWriterSheetBuilder, 并且框架考虑自动导出多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")
    @Override
    public 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());
    }

    @Override
    public 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);
    }

    @Override
    public 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")
        @Override
        public 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());
        }

        @Override
        public 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);
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1658755.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP8266基础资源了解

封装的硬件资源 参考1&#xff0c;参考2 常说的esp8266指的是有一个屏蔽罩盖着的模块&#xff0c;里面包含了esp8266芯片和一个能够存储数据和程序的flash&#xff0c;因为esp8266没有存储功能。 使用arduino常用的nodemcu是包含这个模块并含有电源LDO和串口下载的设计电路如…

【知识碎片】2024_05_09

本篇记录了关于C语言的一些题目&#xff08;puts&#xff0c;printf函数的返回值&#xff0c;getchar&#xff0c;跳出多重循环&#xff09;&#xff0c;和一道关于位运算的代码&#xff3b;整数转换&#xff3d;。 C语言碎片知识 如下程序的功能是&#xff08; &#xff09; #…

原来pip是有默认路径的。

今天一直报错&#xff1a; bash: /root/data1/anaconda3/envs/li_3_10/bin/pip: /root/lsc/anaconda3/envs/li_3_10/bin/python: bad interpreter: No such file or directory 原来是root/data1/anaconda3/envs/li_3_10/bin/pip: 这个位置的pip 自身带默认路径&#xff0c;然…

使用css的box-reflect属性制作倒影效果

box-reflect 是一个在 CSS 中创建元素倒影效果的非标准属性。尽管它在过去的一些 WebKit 浏览器中&#xff08;如旧版的 Safari 和 Chrome&#xff09;得到了支持&#xff0c;但由于它并未成为 CSS 标准的一部分&#xff0c;因此在现代浏览器中的兼容性较差。以下是对 box-refl…

C++ | Leetcode C++题解之第80题删除有序数组中的重复项II

题目&#xff1a; 题解&#xff1a; class Solution { public:int removeDuplicates(vector<int>& nums) {int n nums.size();if (n < 2) {return n;}int slow 2, fast 2;while (fast < n) {if (nums[slow - 2] ! nums[fast]) {nums[slow] nums[fast];slo…

03-Fortran基础--Fortran函数和子程序

03-Fortran基础--Fortran函数和子程序 0 引言1 各函数介绍1.1 函数&#xff08;Functions&#xff09;1.2. 子程序&#xff08;Subroutines&#xff09;1.3 递归函数&#xff08;Recursive Functions&#xff09;1.4. 泛型函数&#xff08;Generic Functions&#xff09;1.5. P…

blender 制作圆角立方体模型,倒角实现。cocos 使用。导出fbx

图片&#xff1a; 步骤&#xff1a; 1.首先创建一个立方体&#xff0c;这里可以使用默认的立方体。 2.在属性面板选择如“扳手”图标一样的修改器工具。 3.设置数量和段数实现圆角的圆滑效果&#xff0c;没有菱角。 保存导出相关的教程&#xff1a;

短信平台群发服务有什么优点

短信平台群发服务有什么优点 提高营销效率 短信平台群发服务利用自动化技术&#xff0c;可以帮助企业迅速向大量潜在客户营销信息。相比传统的逐一方式&#xff0c;群发服务可以同时大批目标客户&#xff0c;大大提高了营销效率。企业可以轻松地在短时间内覆盖更多的潜在客户&…

开源免费的定时任务管理系统:Gocron

Gocron&#xff1a;精准调度未来&#xff0c;你的全能定时任务管理工具&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 Gocron是github上一个开源免费的定时任务管理系统。它使用Go语言开发&#xff0c;是一个轻量级定时任务集中调度和管理系统&#xff0c;用于替代L…

Python 2.x与Python 3.x:初学者该如何选择?

自从Python在1994年首次发布以来,已经经历了多个版本的更新和改进。Python 1.x虽然在发展史上具有重要意义,但早已过时,不再用于实际开发。2000年发布的Python 2.x和2008年发布的Python 3.x则成为了Python家族中最常用的两个版本,形成了一个重要的分界线。特别是Python 3.x…

FPGA+HDMI转换方案,用于网络直播切换直播画面,客户应用:直播,自媒体

FPGAHDMI转换方案&#xff0c;用于网络直播切换直播画面 客户应用:直播&#xff0c;自媒体 主要功能: 1.支持多路HDMI高清输入/输出 2.支持各路输入输出灵活切换 3.支持USB接口 4.支持网口 5.支持音频输出接口 6.支持serders

吴恩达机器学习笔记:第 9 周-17大规模机器学习(Large Scale Machine Learning)17.3-17.4

目录 第 9 周 17、 大规模机器学习(Large Scale Machine Learning)17.3 小批量梯度下降17.4 随机梯度下降收敛 第 9 周 17、 大规模机器学习(Large Scale Machine Learning) 17.3 小批量梯度下降 小批量梯度下降算法是介于批量梯度下降算法和随机梯度下降算法之间的算法&…

【SRC实战】利用APP前端加密构造数据包

挖个洞先 https://mp.weixin.qq.com/s/ZnaRn222xJU0MQxWoRaiJg “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合” 01 — 漏洞证明 “ 参数加密的情况&#xff0c;不会逆向怎么办&#xff1f;” 1、新用户首次设置密码时抓包&#xff0c;此处设置为0000…

【最大公约数 唯一分解定理 调和级数】2862. 完全子集的最大元素和

本文涉及知识点 质数、最大公约数、菲蜀定理 组合数学汇总 唯一分解定理 调和级数 LeetCode2862. 完全子集的最大元素和 给你一个下标从 1 开始、由 n 个整数组成的数组。你需要从 nums 选择一个 完全集&#xff0c;其中每对元素下标的乘积都是一个 完全平方数&#xff0c;例…

《系统架构设计师教程(第2版)》第10章-软件架构的演化和维护-06-大型网站系统架构演化实例

文章目录 第一阶段&#xff1a;单体架构第二阶段&#xff1a;垂直架构第三阶段&#xff1a;使用缓存改善网站性能第四阶段&#xff1a;使用服务集群改善网站并发处理能力第五阶段&#xff1a;数据库读写分离第六阶段&#xff1a;使用反向代理和CDN加速网站响应第七阶段&#xf…

Java | Leetcode Java题解之第80题删除有序数组中的重复项II

题目&#xff1a; 题解&#xff1a; class Solution {public int removeDuplicates(int[] nums) {int n nums.length;if (n < 2) {return n;}int slow 2, fast 2;while (fast < n) {if (nums[slow - 2] ! nums[fast]) {nums[slow] nums[fast];slow;}fast;}return sl…

Sarcasm detection论文解析 |基于语义知识和辅助信息增强讽刺检测方法

论文地址 论文地址&#xff1a;https://www.sciencedirect.com/science/article/abs/pii/S0306457322000139?via%3Dihub 论文首页 笔记框架 基于语义知识和辅助信息增强讽刺检测方法 &#x1f4c5;出版年份:2022 &#x1f4d6;出版期刊:Information Processing & Managem…

CTF-Web Exploitation(持续更新)

CTF-Web Exploitation 1. GET aHEAD Find the flag being held on this server to get ahead of the competition Hints Check out tools like Burpsuite to modify your requests and look at the responses 根据提示使用不同的请求方式得到response可能会得到结果 使用…

正则表达式-前瞻和后顾

正则表达式中的前瞻和后顾。 前瞻(Lookahead) 前瞻是一种断言,它会检查在当前位置之后是否存在某种模式,但不会实际匹配该模式。前瞻有两种形式: 正向前瞻 (?pattern) 检查当前位置之后是否存在指定的模式如果存在,则匹配成功,但不会消耗该模式例如 \w(?\d) 将匹配后面跟数…

反转链表(C语言)———链表经典算法题

题目描述​​​​​​206. 反转链表 - 力扣&#xff08;LeetCode&#xff09;&#xff1a; 答案展示: 迭代&#xff1a; 递归&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* rev…