EasyExcel数据导出功能封装

news2024/11/18 9:33:19

起因:

最近需要用到excel导出功能,使用EasyExcel可以快速实现导出,又需要优雅的对EasyExcel进行封装,在实现自己的导出功能时又可以制定一定的规则,让其他同事方便使用,最近研究了下网上的常规写法,站在巨人的肩上重新添加了自己的思路,供大家参考,有任何问题请多指教

痛点:

1、导出代码写在业务中,调用不统一且代码层次混乱
2、数据库查询的数据远多于对象中定义的数据,导出时默认导出了不想要的数据
3、相同的对象,在导出时需要根据不同条件进行设置不同的Excel表头字段,又不想定义多个导出对象
4、导出时如果设置过某个属性的表头宽度,优先按照设置的宽度导出,如果未设置,希望表头宽度有个默认值,而不是挤压在一起
5、excel需要导出大数据,都在一个sheet页中查看卡顿
6、导出的数据是数据库字符,查看excel人员看不懂,需要做数据转化

如果你有以上痛点问题,可以继续啦;如果没有也可以看看我的封装思路,还请各位高手不吝赐教,这里非常感谢 雪孤城的这篇文章 给了我很大的启发和参考

1. 工具类

1.1 EasyExcelUtil封装类

package cn.well.cloud.core.util.excel;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * @Description: Easyexcel工具类封装及表格自动列宽设置
 * @Author: jiawei
 * @Date: 2023/7/26
 */
@Slf4j
public class EasyExcelUtil {

    /**
     * 每个sheet的容量,即超过60000时就会把数据分sheet
     */
    private static final int PAGE_SIZE = 60000;

    /**
     * 无过滤字段的导出excel
     * @param data 需要导出的数据集
     * @param fileName 需要导出的excel名
     * @param excelClass 需要导出的excel表头实体
     * @return
     * @author jiawei
     * @since 2023/7/27 下午1:39
     */
    public static void exportByExcel(List<?> data, String fileName, Class<?> excelClass){
        exportByExcel(data, fileName, excelClass, AbstractEasyExcel.getExcludeColumnFieldNames());
    }
    
    /**
     *  自定义过滤字段的导出excel
     * @param data 需要导出的数据集
     * @param fileName 需要导出的excel名
     * @param excelClass 需要导出的excel表头实体
     * @param excludeColumnFieldNames 需要过滤的字段集合
     * @return 
     * @author jiawei
     * @since 2023/7/27 下午1:41
     */
    public static void exportByExcel(List<?> data, String fileName, Class<?> excelClass, Collection<String> excludeColumnFieldNames){
        try {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletResponse response = servletRequestAttributes.getResponse();
            long exportStartTime = System.currentTimeMillis();;
            log.info("报表导出Size: " + data.size() + "条。");
            // 把查询到的数据按设置的sheet的容量进行切割
            List<? extends List<?>> lists = SplitList.splitList(data, PAGE_SIZE);
            // 设置响应头
            AbstractEasyExcel.setHead(response, fileName + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
            // 浏览器访问url直接下载文件的方式
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), excelClass)
                    .registerWriteHandler(AbstractEasyExcel.formatExcel())
                    .registerWriteHandler(new AbstractEasyExcel.ExcelWidthStyleStrategy())
                    .includeColumnFieldNames(AbstractEasyExcel.getIncludeColumnFiledNames(excelClass))
                    .excludeColumnFieldNames(excludeColumnFieldNames)
                    .build();

            ExcelWriterSheetBuilder excelWriterSheetBuilder;
            WriteSheet writeSheet;
            if(ObjectUtil.hasNull(lists)){
                log.info("未查询到要导出的数据,导出终止");
                return;
            }
            for (int i = 1; i <= lists.size(); ++i) {
                excelWriterSheetBuilder = new ExcelWriterSheetBuilder(excelWriter);
                excelWriterSheetBuilder.sheetNo(i).sheetName("sheet" + i);
                writeSheet = excelWriterSheetBuilder.build();
                excelWriter.write(lists.get(i - 1), writeSheet);
            }
            // 必须要finish才会写入,不finish只会创建empty的文件
            excelWriter.finish();
            log.info("报表导出结束时间:" + new Date() + ";导出耗时: " + (System.currentTimeMillis() - exportStartTime) + "ms");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1.2AbstractEasyExcel EasyExcel的基础封装,包含响应头设置,Excel的格式设置,根据实体设置需要导出的字段,设置需要过滤的实体中字段(字符串模式和lambda表达获取get方法引用的属性+连续方法调用模式),设置头部单元格宽度
AbstractEasyExcel

package cn.well.cloud.core.util.excel;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;

/**
 * @Description: EasyExcel的基础封装
 * @Author: jiawei
 * @Date: 2023/7/26
 */
@Slf4j
public class AbstractEasyExcel {

    /**
     * 设置响应头
     *
     * @param response 回应的请求数据
     * @param fileName 文件名字
     */
    public static void setHead(HttpServletResponse response, String fileName) {

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            log.error("编码异常");
        }
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

    }

    /**
     * 设置Excel的格式
     *
     * @return 格式化后的Excel
     */
    public static HorizontalCellStyleStrategy formatExcel() {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillBackgroundColor(IndexedColors.WHITE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 10);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 10);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 设置自动换行
        contentWriteCellStyle.setWrapped(true);
        // 设置垂直居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 设置水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

    }


    /**
     * 设置需要导出的字段
     * @param clazz
     * @return {@link Integer}
     * @author jiawei
     * @since 2023/7/27 上午11:21
     */
    public static Collection<String> getIncludeColumnFiledNames(Class<?> clazz) {
        Set<String> set = new HashSet<String>();
        Field[]     fields;
        do {
            fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                set.add(fields[i].getName());
            }
            clazz = clazz.getSuperclass();
        } while (clazz != Object.class && clazz != null);
        return set;
    }

    /**
     * 设置需要过滤的字段方式一(不推荐)
     * @param fields 字段名
     * @return {@link Collection< String>}
     * @author jiawei
     * @since 2023/7/27 下午1:32
     */
    public static Collection<String> getExcludeColumnFieldNames(Object ... fields) {
        Set<String> excludeColumnFieldNames = new HashSet<String>();

        for (Object field : fields) {
            excludeColumnFieldNames.add(StrUtil.toString(field));
        }
        return excludeColumnFieldNames;
    }

    /**
     * 设置需要过滤的字段方式二(推荐)
     * @param excludeColumn
     * @return {@link Collection< String>}
     * @author jiawei
     * @since 2023/7/27 下午2:57
     */
    public static Collection<String> getExcludeColumnFieldNames(ExcludeColumn excludeColumn) {
        return excludeColumn.excludeColumnFieldNames;
    }


    public static class ExcludeColumn{
        Set<String> excludeColumnFieldNames = new HashSet<String>();

        public  <T> ExcludeColumn add(SFunction<T, ?> fn) {
            String field= FieldUtil.getField(fn).getName();
            if (field instanceof String) {
                excludeColumnFieldNames.add(StrUtil.toString(field));
                return this;
            }
            throw ExceptionUtils.mpe("not support this column :" + field);
        }
    }


    /**
     * 获取class的 包括父类的
     *
     * @param clazz
     * @return
     */
    public static Field[] getClassFields(Class<?> clazz) {
        List<Field> list = new ArrayList<Field>();
        Field[]     fields;
        do {
            fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                list.add(fields[i]);
            }
            clazz = clazz.getSuperclass();
        } while (clazz != Object.class && clazz != null);
        return list.toArray(fields);
    }

    /**
     * 设置头部单元格宽度
     */
    public static class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
        
        /**
         * 设置列表,默认50
         * @param writeSheetHolder
         * @param list
         * @param cell
         * @param head
         * @param relativeRowIndex
         * @param isHead
         * @return 
         * @author jiawei
         * @since 2023/7/27 上午10:52
         */
        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
            Sheet sheet = writeSheetHolder.getSheet();

            boolean needSetWidth = relativeRowIndex != null && (isHead || relativeRowIndex == 0);
            if (!needSetWidth) {
                return;
            }
            Integer width = columnWidth(head, cell.getColumnIndex());
            if (width != null) {
                width = width * 256;
                sheet.setColumnWidth(cell.getColumnIndex(), width);
            }else{
                sheet.setColumnWidth(cell.getColumnIndex(), 5000);
            }
        }


        /**
         * 获取设置的自定义宽度
         * @param head
         * @param columnIndex
         * @return {@link java.lang.Integer}
         * @author jiawei
         * @since 2023/7/27 上午10:50
         */
        protected Integer columnWidth(Head head, Integer columnIndex) {
            if (head == null) {
                return null;
            } else {
                return head.getColumnWidthProperty() != null ? head.getColumnWidthProperty().getWidth() : null;
            }
        }
    }
}

1.3 getField bean属性获取工具类,此工具中使用可序列化的 SFunction,引用的是mybatisplus 核心包底下现成的,当然你如果未引用mybatisplus 的话,也可以自己添加上该类,非常简单,附在该工具类后面了

package cn.well.cloud.core.util.excel;

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 * @Description: bean属性获取工具类
 * @Author: jiawei
 * @Date: 2023/7/27
 */
public class FieldUtil {
    /**
     * 将bean的属性的get方法,作为lambda表达式传入时,获取get方法对应的属性Field
     *
     * @param fn  lambda表达式,bean的属性的get方法
     * @param <T> 泛型
     * @return 属性对象
     */
    public static <T> Field getField(SFunction<T, ?> fn) {
        // 从function取出序列化方法
        Method writeReplaceMethod;
        try {
            writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        // 从序列化方法取出序列化的lambda信息
        boolean isAccessible = writeReplaceMethod.isAccessible();
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda;
        try {
            serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        writeReplaceMethod.setAccessible(isAccessible);

        // 从lambda信息取出method、field、class等
        String implMethodName = serializedLambda.getImplMethodName();
        // 确保方法是符合规范的get方法,boolean类型是is开头
        if (!implMethodName.startsWith("is") && !implMethodName.startsWith("get")) {
            throw new RuntimeException("get方法名称: " + implMethodName + ", 不符合java bean规范");
        }

        // get方法开头为 is 或者 get,将方法名 去除is或者get,然后首字母小写,就是属性名
        int prefixLen = implMethodName.startsWith("is") ? 2 : 3;

        String fieldName = implMethodName.substring(prefixLen);
        String firstChar = fieldName.substring(0, 1);
        fieldName = fieldName.replaceFirst(firstChar, firstChar.toLowerCase());
        Field field;
        try {
            field = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName);
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }

        return field;
    }
}

1.3.1 SFunction 对,你没看错,就是一个空的接口类

package com.baomidou.mybatisplus.core.toolkit.support;

import java.io.Serializable;
import java.util.function.Function;

/**
 * 支持序列化的 Function
 *
 * @author miemie
 * @since 2018-05-12
 */
@FunctionalInterface
public interface SFunction<T, R> extends Function<T, R>, Serializable {
}

1.4 SplitList EasyExcelUtils类的辅助类(切割查询的数据)

package cn.well.cloud.core.util.excel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Description: EasyExcelUtils类的辅助类(切割查询的数据)
 * @Author: jiawei
 * @Date: 2023/7/26
 */
public class SplitList {
    /**
     * 切割查询的数据
     * @param list 需要切割的数据
     * @param len 按照什么长度切割
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> splitList(List<T> list, int len) {
        if (list == null || list.size() == 0 || len < 1) {
            return null;
        }
        List<List<T>> result = new ArrayList<List<T>>();
        int size = list.size();
        int count = (size + len - 1) / len;
        for (int i = 0; i < count; i++) {
            List<T> subList = list.subList(i * len, (Math.min((i + 1) * len, size)));
            result.add(subList);
        }
        return result;
    }

    /**
     * 集合平均分组
     * @param source 源集合
     * @param n 分成n个集合
     * @param <T> 集合类型
     * @return 平均分组后的集合
     */
    public static <T> List<List<T>> groupList(List<T> source, int n) {
        if (source == null || source.size() == 0 || n < 1) {
            return null;
        }
        if (source.size() < n) {
            return Collections.singletonList(source);
        }
        List<List<T>> result = new ArrayList<List<T>>();
        int number = source.size() / n;
        int remaider = source.size() % n;
        // 偏移量,每有一个余数分配,就要往右偏移一位
        int offset = 0;
        for (int i = 0; i < n;i++) {
            List<T> list1 = null;
            if (remaider > 0){
                list1 = source.subList(i * number + offset,(i + 1) * number + offset + 1);
                remaider--;
                offset++;
            }else {
                list1 = source.subList(i * number + offset, (i+1) * number + offset);
            }
            result.add(list1);
        }
        return result;
    }
}

数据转换工具

2.1 AbstactBaseConverter 抽象类,自定义的类只需要实现该类即可

package cn.well.cloud.core.util.excel.converter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.WriteCellData;

/**
 * @Description:
 * @Author: jiawei
 * @Date: 2023/7/27
 */
public class AbstactBaseConverter implements Converter<String> {
    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用
     * @param context
     * @return {@link java.lang.String}
     * @author jiawei
     * @since 2023/7/27 上午9:47
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        return context.getReadCellData().getStringValue();
    }

    /**
     * 这里是写的时候会调用
     * @param context
     * @return {@link com.alibaba.excel.metadata.data.WriteCellData<?>}
     * @author jiawei
     * @since 2023/7/27 上午9:47
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>(context.getValue());
    }
}

2.2 YesOrNotConverter自定义某个字段值导出时,“Y"导出"是”,“N"导出"否”

package cn.well.cloud.core.util.excel.converter;

import cn.well.cloud.core.enums.YesOrNotEnum;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.metadata.data.WriteCellData;

/**
 * @Description:
 * @Author: jiawei
 * @Date: 2023/7/27
 */
public class YesOrNotConverter extends  AbstactBaseConverter {
    /**
     * 重写读方法
     * @param context
     * @return {@link java.lang.String}
     * @author jiawei
     * @since 2023/7/27 上午9:46
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        return super.convertToJavaData(context);
    }

    /**
     * 重写写方法
     * @param context
     * @return {@link com.alibaba.excel.metadata.data.WriteCellData<?>}
     * @author jiawei
     * @since 2023/7/27 上午9:47
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>( YesOrNotEnum.N.getCode().equals(context.getValue())? YesOrNotEnum.N.getMessage():YesOrNotEnum.Y.getMessage() );
    }

}

2.3 YesOrNotEnum 枚举类

package cn.well.cloud.core.enums;

import lombok.Getter;

/**
 * 是或否的枚举
 *
 * @Author: jiawei
 * @Date: 2023/7/27
 */
@Getter
public enum YesOrNotEnum {

    /**
     * 是
     */
    Y("Y",1, "是"),

    /**
     * 否
     */
    N("N",0, "否");

    private final String code;

    private final int value;

    private final String message;

    YesOrNotEnum(String code,Integer value, String message) {
        this.code = code;
        this.value = value;
        this.message = message;
    }

}

以上是基础工具的封装,大家可以写到底层包里,供业务层调用,我的目录格式如下
在这里插入图片描述
业务层
3.1 EapCardNumBo 导出对象

package cn.well.cloud.modular.eap.contract.card.bo;

import cn.well.cloud.core.util.excel.converter.YesOrNotConverter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/**
 * @Description:  卡号表
 * @author jaiwei
 * @since 2023-07-23
 */
@Data
@EqualsAndHashCode
public class EapCardNumBo implements Serializable {

      @ExcelProperty(value = "序号")
      private Integer serialNumber;

      @ExcelProperty(value = "合同唯一标识")
      @ContentStyle(dataFormat = 1)
      @ColumnWidth(80)
      private Long contractUid;

      @ExcelProperty(value = "卡号")
      private String cardNumber;

      @ExcelProperty(value = "是否绑定", converter = YesOrNotConverter.class)
      private String hasBinding;

      @ExcelProperty(value = "卡号类型")
      private Integer cardType;

      @ExcelProperty(value = "创建时间")
      @DateTimeFormat("yyyy-MM-dd hh:mm:ss")
      private Date createTime;

}

3.2 调用方法,此处是业务层方法中的调用方式,mybatisplus查询数据的代码就补贴出来了

@Override
public void export(Long contractUid) {
    List<EapCardNumPO> eapCardNumPOList = baseEapCardNumMapper.selectList(new QueryWrapperX<EapCardNumPO>().lambda().eq(EapCardNumPO::getContractUid, contractUid));
    //调用方式一(推荐)
    AbstractEasyExcel.ExcludeColumn excludeColumn = new AbstractEasyExcel.ExcludeColumn().add(EapCardNumBo::getContractUid).add(EapCardNumBo::getCreateTime);
    EasyExcelUtil.exportByExcel(eapCardNumPOList,"卡号",EapCardNumBo.class, AbstractEasyExcel.getExcludeColumnFieldNames(excludeColumn));
	
	//调用方式二(不推荐)
    EasyExcelUtil.exportByExcel(eapCardNumPOList,"卡号",EapCardNumBo.class, AbstractEasyExcel.getExcludeColumnFieldNames("contractUid","createTime"));

}

总结如下

新增工具类
EasyExcelUtil excel读写工具类
具体实现方法
exportByExcel() 浏览器直接导出

自定义导出实体注解

@ContentStyle 设置数据格式,dataFormat = 1 会避免较长数字科学计数法显示,其他格式参见easyexcel-core包底下的com.alibaba.excel.constant.BuiltinFormats
converter = YesOrNotConverter.class 自定义转换导出的内容,比如Y需要导出是,N需要导出否,不建议在数据和业务层面进行处理,而是抽取出转换器类进行处理
@DateTimeFormat 时间格式化
@ColumnWidth(80) 该注解不添加,默认单元格宽度是50,超过50长度时需要自定义列宽

方法调用一(推荐)

AbstractEasyExcel.ExcludeColumn excludeColumn = new AbstractEasyExcel.ExcludeColumn().add(EapCardNumBo::getContractUid).add(EapCardNumBo::getCreateTime);
EasyExcelUtil.exportByExcel(eapCardNumPOList,"卡号",EapCardNumBo.class, AbstractEasyExcel.getExcludeColumnFieldNames(excludeColumn));

`
方法调用二(不推荐)

EasyExcelUtil.exportByExcel(eapCardNumPOList,"卡号",EapCardNumBo.class, AbstractEasyExcel.getExcludeColumnFieldNames("contractUid","createTime"));

非常感谢阿里巴巴对EasyExcel的开源,且用且珍惜

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

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

相关文章

QT基于TCP协议实现数据传输以及波形绘制

这个玩意我做了两个&#xff0c;一个是安卓app&#xff0c;一个是Windows程序。代码并非全部都是由我从无到有实现&#xff0c;只是实现了我想要的功能。多亏了巨人的肩膀&#xff0c;开源万岁&#xff01;&#xff01;&#xff01; 我把程序放到GitHub上&#xff0c;需要的可…

【shell脚本编写使用mysqldump实现分库分表备份】

shell脚本编写使用mysqldump实现分库分表备份 #!/bin/bash# 检查MySQL是否启动 #systemctl list-units --typeservice命令查看可用的服务列表&#xff0c;并找到正确的MySQL服务名称 mysqld.service mysql_status$(systemctl is-active mysqld.service) if [ "$mysql_sta…

向伟大的中国人民解放军生日献礼 黄河千年清一回张国土考察青海

向伟大的中国人民解放军生日献礼 黄河千年清一回张国土考察青海 Birthday gift to the great Chinese Peoples Liberation Army The Yellow River visited Qinghaiin. the Millennium Qing Dynasty 八一前夕&#xff0c;建国七十周年最俱影响力人物、黄河千年清一回互联网电子…

【黑马头条之自管理敏感词】

本笔记内容为黑马头条项目的新需求-自管理敏感词部分 目录 一、需求分析 二、敏感词-过滤 三、DFA实现原理 SensitiveWordUtil工具类 四、自管理敏感词集成到文章审核中 一、需求分析 文章审核功能已经交付了&#xff0c;文章也能正常发布审核。突然&#xff0c;产品经理…

leetcode刷题(一)

目录标题 NO1:数组中重复的数字&#xff08;简单&#xff09;题目详细&做题链接解法一&#xff1a;辅助数组解法二&#xff1a;排序解法三&#xff1a;交换数据解法四&#xff1a;二分查找 NO2:二维数组的查找&#xff08;中等&#xff09;题目详细&做题链接解法一&…

揭秘APT团体常用的秘密武器——AsyncRAT

AsyncRAT 是 2019 年 1 月在 [GitHub](https://github.com/NYAN-x-CAT/AsyncRAT-C- Sharp)上开源的远控木马&#xff0c;旨在通过远程加密链接控制失陷主机&#xff0c;提供如下典型功能&#xff1a; 截取屏幕 键盘记录 上传/下载/执行文件 持久化 禁用 Windows Defender 关机/…

前端工作中常用 CSS 知识点整理

1.1文字溢出省略号 文字单行溢出: overflow: hidden; // 溢出隐藏 text-overflow: ellipsis; // 溢出用省略号显示 white-space: nowrap; // 规定段落中的文本不进行换行 多行文字溢出: overflow: hidden; // 溢出隐藏 text-overflow: …

百度:文心千帆 网页搭建和示例测评

文章目录 官方文档代码示例token获取流式回答官网完整示例 制作一个网页端 官方文档 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/flfmc9do2按照这个操作进行创建一个应用&#xff1a; 代码示例 token获取 # 填充API Key与Secret Key import requests import jsondef ma…

Ubuntu 曝Linux漏洞,近 40% 用户受影响

Bleeping Computer 网站披露&#xff0c;Wiz 研究人员 s.Tzadik 和 s.Tamari 发现 Ubuntu 内核中存在两个 Linux 漏洞 CVE-2023-32629 和 CVE-2023-2640&#xff0c;没有特权的本地用户可能利用其在设备上获得更高权限&#xff0c;影响大约 40% 的 Ubuntu 用户。 Ubuntu 是目前…

监控概述、安装zabbix、配置zabbixagent、添加被控端主机、常用监控指标、自定义监控项

day01 day01监控概述监控命令zabbix安装zabbix 6.0配置zabbix监控web1服务器在web1上安装agent在web页面中添加对web1的监控常用监控指标自定义监控项实现监控web1用户数量的监控项在被控端创建key创建模板应用模板到主机查看结果 监控概述 对服务的管理&#xff0c;不能仅限…

Andorid播放多媒体文件——播放视频

以下内容摘自郭霖《第一行代码》第三版 播放视频 VideoView的常用方法 方法名功能描述setVideoPath()设置要播放的视频文件的位置start()开始或继续播放视频pause()暂停播放视频resume()将视频从头开始播放seekTo()从指定的位置开始播放视频isPlaying()判断当前是否正在播放…

java-day01

一&#xff1a;基础常识 软件&#xff1a;按照特定顺序的计算机数据与指令的集合。可分为系统软件&#xff08;如操作系统&#xff09;和应用软件&#xff08;如QQ&#xff09; 人机交互方式&#xff1a;图形化界面&#xff08;GUI&#xff09;与命令行&#xff08;CLI&#…

C++:封装一个Vector容器

#include <iostream>using namespace std; template <typename T>class Myvector {private:T * first;T * last;T * end;public://构造函数Myvector(int size 10){this->first new T[size];this->last this->first;this->end this->first size…

Meta论文文献检索国内外检索数据库

今天分享国内外的一个文献检索 因为国内的文献存在一种情况是什么 国内的文献相对来说质量可能大部分来说可能质量偏低 这个不是说是崇洋媚外 我们不能以偏概全只能说大部分来说可能质量这个太低 可以想一下其实如果文章的质量真的是很好的话大家也都知道肯定都发SCI 对于…

【每日一题】—— C - (K+1)-th Largest Number (AtCoder Beginner Contest 273)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

「二分搜索Binary Search」

文章目录 0 框架1 基本二分1.1 寻找一个数题解Code结果 1.2 寻找左侧边界的二分搜索Code 1.3 寻找右侧边界的二分搜索Code 0 框架 int binarySearch(vector<int> &nums, int target) {int left 0, right ....;//right具体看情况while (....){int mid left (righ…

ThinkPHP8知识详解:给PHP8和MySQL8添加到环境变量

在PHPenv安装的时候&#xff0c;环境变量默认的PHP版本是7.4的&#xff0c;MySQL的版本是5.7的&#xff0c;要想使用ThinkPHP8来开发&#xff0c;就必须修改环境变量&#xff0c;本文就详细讲解了如果修改PHP和MySQL的环境变量。 1、添加网站 启动phpenv&#xff0c;网站&…

抖音SEO源码开发指南:介绍如何开发抖音SEO源码的基本步骤和要点。

一、 抖音SEO源码开发指南&#xff1a; 确定目标&#xff1a;首先要明确开发抖音SEO源码的目标是什么&#xff0c;是提高搜索排名还是增加用户量等。根据不同的目标来制定开发策略和思路。 分析竞争&#xff1a;对于同类产品&#xff0c;要进行竞争分析&#xff0c;了解对手的…

安装Windows版nginx以及部署前端代码并就解决刷新出现404

文章目录 1.安装Nginx2.启动Nginx以及常用命令2.1 常用命令 3.部署前端打好的dist包4.前端部署nginx刷新后404&#xff0c;解决Nginx刷新页面后404的问题 1.安装Nginx &#xff08;1&#xff09;下载地址&#xff1a;https://nginx.org/en/download.html &#xff08;2&#x…

从0到1精通,Python接口自动化测试,测试进阶之道...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 如何实现python接…