常用工具方法集合

后端项目java中字符串、集合、日期时间常用方法 简单梳理一下,java中常用的字符串、ArrayList、日期、时间的一些常用方法吧 阅读详情

自用小工具

word工具类

  • 支持段落、表格的文本占位符、图片占位符替换
  • 支持设置文本颜色

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * word工具类
 */
public class WordBuilder {

    private static final String TEXT = "${";
    private static final String IMAGE = "${image:";
    private static final Pattern TEXT_PLACEHOLDER = Pattern.compile("\\$\\{([^}]+)}");
    private static final Pattern IMAGE_PLACEHOLDER = Pattern.compile("\\$\\{image:([^}]+)}");

    private final XWPFDocument doc;

    public WordBuilder(InputStream tpl) throws IOException {
        this.doc = new XWPFDocument(tpl);
    }

    public WordBuilder(byte[] tpl) throws IOException {
        this(new ByteArrayInputStream(tpl));
    }

    /**
     * 普通占位符
     */
    public WordBuilder replace(Map<String, Object> vars) {
        replaceAll(vars);
        return this;
    }

    /**
     * 图片
     *
     * @param images 字段名:base68字符串
     */
    public WordBuilder image(Map<String, Object> images) {
        return image(images, -1, -1);
    }

    /**
     * 图片
     *
     * @param key         占位符名称
     * @param base68Image 图片:base68字符串
     * @param widthEmus   宽度
     * @param heightEmus  高度
     */
    public WordBuilder image(String key, String base68Image, int widthEmus, int heightEmus) {
        Map<String, Object> map = new HashMap<>();
        map.put(key, base68Image);
        replaceAllImages(map, widthEmus * 9525, heightEmus * 9525);
        return this;
    }

    /**
     * 图片
     *
     * @param key        占位符名称
     * @param bytes      图片:bytes[]
     * @param widthEmus  宽度
     * @param heightEmus 高度
     */
    public WordBuilder image(String key, byte[] bytes, int widthEmus, int heightEmus) {
        Map<String, Object> map = new HashMap<>();
        map.put(key, bytes);
        replaceAllImages(map, widthEmus * 9525, heightEmus * 9525);
        return this;
    }

    /**
     * 图片
     *
     * @param images     字段名:base68字符串 或 bytes[]
     * @param widthEmus  图片宽度
     * @param heightEmus 图片高度
     */
    public WordBuilder image(Map<String, Object> images, int widthEmus, int heightEmus) {
        replaceAllImages(images, widthEmus * 9525, heightEmus * 9525);
        return this;
    }

    /**
     * 表格
     *
     * @param data 数据列表
     */
    public WordBuilder table(List<Map<String, Object>> data) {
        return table(data, 0, 1);
    }

    /**
     * 表格
     *
     * @param data         数据列表
     * @param tableIndex   文档中第几个表格(0 开始)
     * @param tempRowIndex 模板行号(0 开始)
     */
    public WordBuilder table(List<Map<String, Object>> data, int tableIndex, int tempRowIndex) {
        if (data == null || data.isEmpty() || tableIndex < 0 || tempRowIndex < 0) {
            return this;
        }
        List<XWPFTable> tables = doc.getTables();
        if (tableIndex >= tables.size()) {
            return this;
        }
        XWPFTable table = tables.get(tableIndex);
        if (tempRowIndex >= table.getRows().size()) {
            return this;
        }
        XWPFTableRow templateRow = table.getRow(tempRowIndex);
        for (int i = 0; i < data.size(); i++) {
            Map<String, Object> rowData = data.get(i);
            // 复制模板行
            XWPFTableRow newRow = new XWPFTableRow((CTRow) templateRow.getCtRow().copy(), table);
            for (XWPFTableCell newCell : newRow.getTableCells()) {
                for (XWPFParagraph newPara : newCell.getParagraphs()) {
                    // 替换文本占位符
                    replaceParagraph(newPara, rowData);
                }
            }
            int newRowIndex = tempRowIndex + 1 + i;
            table.addRow(newRow, newRowIndex);
        }
        // 删除模板行
        table.removeRow(tempRowIndex);
        return this;
    }

    /**
     * 设置文本颜色(全局)
     *
     * @param textColor 文本颜色
     */
    public WordBuilder textColor(String textColor) {
        return textColorParagraph(textColor, -1);
    }

    /**
     * 设置段落文本颜色
     *
     * @param textColor 文本颜色
     * @param index     文档中第几个段落(0 开始)
     */
    public WordBuilder textColorParagraph(String textColor, int index) {
        // TODO

        return this;
    }

    /**
     * 设置表格文本颜色
     *
     * @param textColor 文本颜色
     * @param index     文档中第几个表格(0 开始)
     */
    public WordBuilder textColorTable(String textColor, int index) {
        return textColorTable(textColor, index, -1, -1);
    }

    /**
     * 设置表格文本颜色
     *
     * @param textColor 文本颜色
     * @param index     文档中第几个表格(0 开始)
     * @param rowIndex  行下标
     */
    public WordBuilder textColorTableRow(String textColor, int index, int rowIndex) {
        return textColorTable(textColor, index, rowIndex, -1);
    }

    /**
     * 设置表格文本颜色
     *
     * @param textColor 文本颜色
     * @param index     文档中第几个表格(0 开始)
     * @param colIndex  列下标
     */
    public WordBuilder textColorTableCol(String textColor, int index, int colIndex) {
        return textColorTable(textColor, index, -1, colIndex);
    }

    /**
     * 设置表格文本颜色
     *
     * @param textColor 文本颜色
     * @param index     文档中第几个表格(0 开始)
     * @param rowIndex  行下标
     * @param colIndex  列下标
     */
    public WordBuilder textColorTable(String textColor, int index, int rowIndex, int colIndex) {
        // TODO

        return this;
    }

    public void write(HttpServletResponse resp) throws IOException {
        resp.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        resp.setHeader("Content-Disposition", "attachment;filename=file.docx");
        try (ServletOutputStream sos = resp.getOutputStream()) {
            doc.write(sos);
        } finally {
            if (doc != null) {
                doc.close();
            }
        }
    }

    public void write(File file) throws IOException {
        try (FileOutputStream out = new FileOutputStream(file)) {
            doc.write(out);
        } finally {
            if (doc != null) {
                doc.close();
            }
        }
    }

    public byte[] toBytes() throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            doc.write(bos);
            return bos.toByteArray();
        } finally {
            if (doc != null) {
                doc.close();
            }
        }
    }

    private void replaceAll(Map<String, Object> map) {
        // 段落
        for (XWPFParagraph p : doc.getParagraphs()) {
            replaceParagraph(p, map);
        }
        // 表格
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph p : cell.getParagraphs()) {
                        replaceParagraph(p, map);
                    }
                }
            }
        }
        // 页眉
        for (XWPFHeader header : doc.getHeaderList()) {
            for (XWPFParagraph paragraph : header.getParagraphs()) {
                replaceParagraph(paragraph, map);
            }
        }
        // 页脚
        List<XWPFFooter> footerList = doc.getFooterList();
        for (XWPFFooter footer : footerList) {
            for (XWPFParagraph paragraph : footer.getParagraphs()) {
                replaceParagraph(paragraph, map);
            }
        }
    }

    private void replaceParagraph(XWPFParagraph p, Map<String, Object> data) {
        if (!p.getText().contains(TEXT)) {
            return;
        }
        // 合并 run,防止占位符被拆
        joinRuns(p);
        for (XWPFRun run : p.getRuns()) {
            String txt = run.text();
            if (txt.contains(TEXT) && !txt.contains(IMAGE)) {
                Matcher m = TEXT_PLACEHOLDER.matcher(txt);
                StringBuffer sb = new StringBuffer();
                while (m.find()) {
                    String key = m.group(1);
                    Object val = data.get(key);
                    if (val != null) {
                        m.appendReplacement(sb, val.toString());
                    }
                }
                m.appendTail(sb);
                txt = sb.toString();
                // 换行处理
                if (txt.contains("\n")) {
                    String[] lines = txt.split("\n");
                    run.setText(lines[0], 0);
                    for (int i = 1; i < lines.length; i++) {
                        run.addBreak();
                        run.setText(lines[i]);
                    }
                } else {
                    run.setText(txt, 0);
                }
            }
        }
    }

    private void replaceAllImages(Map<String, Object> images, int widthEmus, int heightEmus) {
        // 段落
        for (XWPFParagraph p : doc.getParagraphs()) {
            replaceParagraphWithImage(p, images, widthEmus, heightEmus);
        }
        // 表格
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph p : cell.getParagraphs()) {
                        replaceParagraphWithImage(p, images, widthEmus, heightEmus);
                    }
                }
            }
        }
    }

    private void replaceParagraphWithImage(XWPFParagraph p, Map<String, Object> images, int widthEmus, int heightEmus) {
        if (!p.getText().contains(IMAGE)) {
            return;
        }
        joinRuns(p);
        for (XWPFRun run : p.getRuns()) {
            String txt = run.text();
            Matcher m = IMAGE_PLACEHOLDER.matcher(txt);
            while (m.find()) {
                String key = m.group(1);
                Object val = images.get(key);
                if (val == null) {
                    continue;
                }
                byte[] bytes = toBytes(val);
                if (bytes == null || bytes.length == 0) {
                    continue;
                }
                String ext = getFormat(bytes);
                int pictureType = getPictureType(ext);

                try {
                    int width = widthEmus > 0 ? widthEmus : 200 * 9525;
                    int height = heightEmus > 0 ? heightEmus : 200 * 9525;

                    run.addPicture(new ByteArrayInputStream(bytes), pictureType, "image." + ext, width, height);
                    run.setText("", 0);
                } catch (Exception e) {
                    throw new RuntimeException("插入图片失败: " + key, e);
                }
            }
        }
    }

    /**
     * 合并 run,防止占位符被拆开
     */
    private void joinRuns(XWPFParagraph p) {
        if (p.getRuns().size() <= 1) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        for (XWPFRun r : p.getRuns()) {
            sb.append(r.text());
        }
        p.getRuns().get(0).setText(sb.toString(), 0);
        while (p.getRuns().size() > 1) {
            p.removeRun(1);
        }
    }

    private byte[] toBytes(Object val) {
        try {
            if (val instanceof byte[]) {
                return (byte[]) val;
            }
            if (val instanceof String) {
                String s = (String) val;
                // 去掉 data URI 头(如果有)
                if (s.contains(",")) {
                    s = s.split(",")[1];
                }
                return Base64.getDecoder().decode(s.trim());
            }
            if (val instanceof File) {
                return org.apache.poi.util.IOUtils.toByteArray(Files.newInputStream(((File) val).toPath()));
            }
            if (val instanceof InputStream) {
                return org.apache.poi.util.IOUtils.toByteArray((InputStream) val);
            }
        } catch (IOException e) {
            throw new RuntimeException("读取图片失败", e);
        }
        return null;
    }

    private String getFormat(byte[] bs) {
        // 简单魔数
        if (bs[0] == (byte) 0x89 && bs[1] == (byte) 0x50) {
            return "png";
        }
        if (bs[0] == (byte) 0xFF && bs[1] == (byte) 0xD8) {
            return "jpg";
        }
        if (bs[0] == (byte) 0x47 && bs[1] == (byte) 0x49) {
            return "gif";
        }
        return "png";
    }

    private int getPictureType(String ext) {
        switch (ext.toLowerCase(Locale.ENGLISH)) {
            case "jpg":
                return Document.PICTURE_TYPE_JPEG;
            case "jpeg":
                return Document.PICTURE_TYPE_JPEG;
            case "gif":
                return Document.PICTURE_TYPE_GIF;
            case "png":
                return Document.PICTURE_TYPE_PNG;
            default:
                throw new IllegalArgumentException("不支持的图片类型: " + ext);
        }
    }

}


PDF工具类

  • word转pdf
import com.spire.doc.Document;
import com.spire.doc.FileFormat;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;

/**
 * PDF工具类
 */
public class PdfUtil {

    public static byte[] convertWordToPdf(byte[] docBytes) {
        Document doc = new Document();
        try (ByteArrayOutputStream pdfOut = new ByteArrayOutputStream()) {
            doc.loadFromStream(new ByteArrayInputStream(docBytes), FileFormat.Docx);
            doc.saveToStream(pdfOut, FileFormat.PDF);
            return pdfOut.toByteArray();
        } catch (IOException e) {
            throw new MyWzcgglException("Word 转 PDF 失败");
        } finally {
            doc.dispose();
        }
    }

}

集合工具

  • 差集
  • 交集
  • 去重
  • 切片
  • 自适应切片
  • 切片操作数据库查询(串行、并行)
  • 拷贝
import cn.hutool.core.collection.CollectionUtil;
import org.springframework.beans.BeanUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 集合工具
 */
public class ListUtil {

    /**
     * 求差集
     *
     * @param comparator    比较器
     * @param keyExtractors 比较字段
     * @return list1 与 list2 的差集
     */
    @SafeVarargs
    public static <T> List<T> difference(List<T> list1, List<T> list2, Comparator<T> comparator, Function<T, ?>... keyExtractors) {
        if (CollectionUtil.isEmpty(list1)) {
            return new ArrayList<>();
        }
        if (CollectionUtil.isEmpty(list2)) {
            return new ArrayList<>(list1);
        }
        // 用 Wrapper 包装 list2,建立哈希索引
        Set<Wrapper<T>> set2 = new HashSet<>(list2.size() * 2);
        for (T t : list2) {
            set2.add(new Wrapper<>(t, comparator, keyExtractors));
        }

        List<T> result = new ArrayList<>(list1.size());
        for (T t : list1) {
            if (!set2.contains(new Wrapper<>(t, comparator, keyExtractors))) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     * 求差集
     *
     * @param keyExtractors 比较字段
     * @return list1 与 list2 的差集
     */
    @SafeVarargs
    public static <T> List<T> difference(List<T> list1, List<T> list2, Function<T, ?>... keyExtractors) {
        Comparator<T> comparator = createComparator(keyExtractors);
        return difference(list1, list2, comparator, keyExtractors);
    }

    /**
     * 求交集
     *
     * @param objectComparator 比较器
     * @param keyExtractors    比较字段
     * @return list1 与 list2 的交集(以list1为原型)
     */
    @SafeVarargs
    public static <T> List<T> intersection(List<T> list1, List<T> list2, Comparator<T> objectComparator, Function<T, ?>... keyExtractors) {
        if (CollectionUtil.isEmpty(list1) || CollectionUtil.isEmpty(list2)) {
            return new ArrayList<>();
        }
        Set<Wrapper<T>> index = new HashSet<>(Math.min(list1.size(), list2.size()) * 2);

        // 用较小列表建索引,减少内存
        List<T> small = list1.size() <= list2.size() ? list1 : list2;
        for (T t : small) {
            index.add(new Wrapper<>(t, objectComparator, keyExtractors));
        }

        // 遍历较大列表,命中且未输出过的元素加入结果
        List<T> large = small == list1 ? list2 : list1;
        Set<Wrapper<T>> seen = new HashSet<>(index.size() * 2);
        List<T> result = new ArrayList<>(index.size());

        for (T t : large) {
            Wrapper<T> w = new Wrapper<>(t, objectComparator, keyExtractors);
            if (index.contains(w) && seen.add(w)) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     * 求交集
     *
     * @param keyExtractors 比较字段
     * @return list1 与 list2 的交集
     */
    @SafeVarargs
    public static <T> List<T> intersection(List<T> list1, List<T> list2, Function<T, ?>... keyExtractors) {
        Comparator<T> comparator = createComparator(keyExtractors);
        return intersection(list1, list2, comparator, keyExtractors);
    }

    /**
     * 去重
     *
     * @param comparator    比较器
     * @param keyExtractors 比较字段
     */
    @SafeVarargs
    public static <T> List<T> distinct(List<T> list, Comparator<T> comparator, Function<T, ?>... keyExtractors) {
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        Set<Wrapper<T>> wrapperSet = new LinkedHashSet<>(list.size() * 2);
        for (T element : list) {
            wrapperSet.add(new Wrapper<>(element, comparator, keyExtractors));
        }

        // 提取原始元素
        List<T> result = new ArrayList<>(wrapperSet.size());
        for (Wrapper<T> wrapper : wrapperSet) {
            result.add(wrapper.target);
        }
        return result;

    }

    /**
     * 去重
     *
     * @param keyExtractors 比较字段
     */
    @SafeVarargs
    public static <T> List<T> distinct(List<T> list, Function<T, ?>... keyExtractors) {
        Comparator<T> comparator = createComparator(keyExtractors);
        return distinct(list, comparator, keyExtractors);
    }

    /**
     * 比较器
     *
     * @return 0:相等,-1:不相等
     */
    @SafeVarargs
    public static <T> Comparator<T> createComparator(Function<T, ?>... keyExtractors) {
        return (o1, o2) -> {
            for (Function<T, ?> keyExtractor : keyExtractors) {
                Object key1 = keyExtractor.apply(o1);
                Object key2 = keyExtractor.apply(o2);
                if (!Objects.equals(key1, key2)) {
                    return -1;
                }
            }
            return 0;
        };
    }

    /**
     * 切片
     *
     * @param num 每组分片数量
     */
    public static <T> List<List<T>> sharding(List<T> list, int num) {
        if (list == null || list.isEmpty() || num <= 0) {
            return Collections.emptyList();
        }
        List<List<T>> result = new ArrayList<>((list.size() + num - 1) / num);
        for (int i = 0; i < list.size(); i += num) {
            result.add(list.subList(i, Math.min(i + num, list.size())));
        }
        return result;
    }

    /**
     * 切片
     * 默认500一组
     */
    public static <T> List<List<T>> sharding(List<T> list) {
        return sharding(list, 500);
    }

    /**
     * 自适应切片
     * 数据量级  |  策略  |  单组条数  |  总组数
     * < 500  |  不切  |  500  |  1
     * 501-20k  |  自适应  |  500-2000  | 1-20
     * >20k  |  固定2000  |  2000  |  >=10
     */
    public static <T> List<List<T>> autoSharding(List<T> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        int size = list.size();
        // 如果长度小于等于500,直接返回
        if (size <= 500) {
            return Collections.singletonList(list);
        }
        // 计算“理想组大小”:目标组数 10~20
        int targetGroups = Math.min(20, Math.max(10, (int) Math.sqrt(size)));
        int groupSize = (size + targetGroups - 1) / targetGroups;
        // 把组大小钳在 500~2000
        groupSize = Math.max(500, Math.min(2000, groupSize));

        return sharding(list, groupSize);
    }

    /**
     * 自适应切片,并单线程串行执行查询数据库
     *
     * @param list          参数列表
     * @param queryFunction 查询函数,接收一个批次参数,返回该批次查询结果
     * @param <T>           参数类型
     * @param <V>           结果类型
     * @return 合并后的查询结果集合
     */
    public static <T, V> List<V> autoShardingToSelectDb(List<T> list, Function<List<T>, List<V>> queryFunction) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        // 自适应切片
        List<List<T>> shards = autoSharding(list);
        // 单线程串行执行
        List<V> result = new ArrayList<>();
        for (List<T> shard : shards) {
            List<V> shardResult = queryFunction.apply(shard);
            if (shardResult != null && !shardResult.isEmpty()) {
                result.addAll(shardResult);
            }
        }
        return result;
    }

    /**
     * 自适应切片,并并行执行查询数据库
     *
     * @param list          参数列表
     * @param queryFunction 查询函数
     * @param executor      线程池执行器
     * @param <T>           参数类型
     * @param <V>           结果类型
     * @return 合并后的查询结果集合
     */
    public static <T, V> List<V> autoShardingToSelectDbParallel(
            List<T> list,
            Function<List<T>, List<V>> queryFunction,
            Executor executor) {

        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }

        // 自适应切片
        List<List<T>> shards = autoSharding(list);

        // 只有1个分片时,无需走线程池
        if (shards.size() == 1) {
            List<V> result = queryFunction.apply(shards.get(0));
            return result != null ? result : Collections.emptyList();
        }

        // 并行执行
        List<CompletableFuture<List<V>>> futures = shards.stream()
                .map(shard -> CompletableFuture.supplyAsync(() -> {
                    try {
                        List<V> shardResult = queryFunction.apply(shard);
                        return shardResult != null ? shardResult : Collections.<V>emptyList();
                    } catch (Exception e) {
                        throw new RuntimeException("查询批次失败,批次大小: " + shard.size(), e);
                    }
                }, executor))
                .collect(Collectors.toList());

        // 等待所有任务完成并合并结果
        return futures.stream()
                .map(CompletableFuture::join)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }

    /**
     * 拷贝集合对象属性
     *
     * @param data          原始对象集合
     * @param targetFactory 目标对象工厂(不能为 null)
     * @param result        接收结果的集合(允许为 null)
     * @param <T>           源类型
     * @param <V>           目标类型
     * @return 填充后的 result(不会返回 null)
     */
    public static <T, V> List<V> copyProperties(List<T> data, Supplier<V> targetFactory, List<V> result) {
        if (data == null || data.isEmpty()) {
            return result == null ? Collections.emptyList() : result;
        }
        if (result == null) {
            result = new ArrayList<>(data.size());
        }
        for (T src : data) {
            V tgt = targetFactory.get();
            BeanUtils.copyProperties(src, tgt);
            result.add(tgt);
        }
        return result;
    }

    /**
     * 包装器:equals/hashCode 都服从 comparator + keyExtractors
     */
    private static final class Wrapper<T> {
        private final T target;
        private final Comparator<T> cmp;
        private final Function<T, ?>[] extractors;

        @SafeVarargs
        Wrapper(T target, Comparator<T> cmp, Function<T, ?>... extractors) {
            this.target = target;
            this.cmp = cmp;
            this.extractors = extractors;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof Wrapper)) {
                return false;
            }
            Wrapper<?> other = (Wrapper<?>) o;
            return cmp.compare(this.target, (T) other.target) == 0;
        }

        @Override
        public int hashCode() {
            // 只用 comparator 实际比较的字段计算哈希
            int h = 1;
            for (Function<T, ?> ex : extractors) {
                h = 31 * h + Objects.hashCode(ex.apply(target));
            }
            return h;
        }
    }

}


map工具类

  • list转map
import io.seata.common.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * map工具类
 */
public class MapUtil {

    /**
     * List 转成 Map
     *
     * @param list      list数据
     * @param keyMapper 取主键的 Lambda
     * @param <T>       原始元素类型
     * @param <K>       主键类型
     * @return Map<主键, VO>
     */
    public static <T, K> Map<K, T> listToMap(List<T> list, Function<T, K> keyMapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        return list.stream().collect(Collectors.toMap(
                keyMapper,
                Function.identity(),
                (oldVal, newVal) -> oldVal));
    }

    /**
     * List 转成 Map
     *
     * @param list        list数据
     * @param keyMapper   取主键的 Lambda
     * @param valueMapper 取值的 Lambda
     * @param <T>         原始元素类型shi
     * @param <K>         主键类型
     * @param <V>         值类型
     * @return Map<主键, 值>
     */
    public static <T, K, V> Map<K, V> listToMap(List<T> list, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        return list.stream().collect(Collectors.toMap(
                keyMapper,
                valueMapper,
                (oldVal, newVal) -> oldVal));
    }

}

文件工具类

  • 下载
  • 判断文件类型
import com.sinopec.sicii.wzcggl.config.MyWzcgglException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.MimeTypeUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Locale;

/**
 * 文件工具类
 */
@Slf4j
public class FileUtil {

    public static void download(HttpServletResponse response, byte[] bytes, String fileName) {
        if (bytes == null || bytes.length == 0) {
            throw new MyWzcgglException("文件为空!");
        }

        try {
            MediaType mediaType = resolveMediaType(fileName);

            response.reset();
            response.setContentType(mediaType.toString());
            response.setContentLength(bytes.length);
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            try (ServletOutputStream outputStream = response.getOutputStream()) {
                outputStream.write(bytes);
                outputStream.flush();
            }
        } catch (IOException e) {
            log.error("文件下载失败,fileName:{},错误:{}", fileName, e.getMessage());
            throw new MyWzcgglException("文件下载失败!");
        }
    }

    private static MediaType resolveMediaType(String fileName) {
        if (fileName == null) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
        String ext = fileName
                .substring(fileName.lastIndexOf('.') + 1)
                .toLowerCase(Locale.ENGLISH);
        switch (ext) {
            case "pdf":
                return MediaType.APPLICATION_PDF;
            case "xls":
                return MediaType.valueOf("application/vnd.ms-excel");
            case "xlsx":
                return MediaType.valueOf(
                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            case "doc":
                return MediaType.valueOf("application/msword");
            case "docx":
                return MediaType.valueOf(
                        "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            case "ppt":
                return MediaType.valueOf("application/vnd.ms-powerpoint");
            case "pptx":
                return MediaType.valueOf(
                        "application/vnd.openxmlformats-officedocument.presentationml.presentation");
            case "txt":
                return MediaType.TEXT_PLAIN;
            case "png":
                return MediaType.IMAGE_PNG;
            case "jpg":
            case "jpeg":
                return MediaType.IMAGE_JPEG;
            case "gif":
                return MediaType.IMAGE_GIF;
            case "zip":
                return MediaType.valueOf("application/zip");
            default:
                String mime = MimeTypeUtils.parseMimeType(ext).toString();
                return MediaType.parseMediaType(mime);
        }
    }

}

反射工具

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 反射工具
 */
public class FieldUtil {

    /**
     * 获取包括父类在内的所有字段
     */
    public static Map<String, Object> getFieldMap(Object obj) {
        Map<String, Object> fieldMap = new HashMap<>();
        if (obj == null) {
            return fieldMap;
        }

        try {
            Class<?> clazz = obj.getClass();
            while (clazz != null && clazz != Object.class) {
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    Object fieldValue = field.get(obj);
                    // 如果值为null,设为空字符串
                    if (fieldValue == null){
                        fieldValue = "";
                    }
                    // 处理Date类型且带有@JsonFormat注解的字段
                    if (fieldValue instanceof Date) {
                        JsonFormat jsonFormat = field.getAnnotation(JsonFormat.class);
                        if (jsonFormat != null) {
                            fieldValue = formatDate((Date) fieldValue, jsonFormat);
                        }
                    }
                    fieldMap.put(fieldName, fieldValue);
                }
                clazz = clazz.getSuperclass();
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return fieldMap;
    }

    /**
     * 根据@JsonFormat注解格式化日期
     */
    private static String formatDate(Date date, JsonFormat jsonFormat) {
        if (date == null) {
            return "";
        }

        String pattern = jsonFormat.pattern();
        if (pattern.isEmpty()) {
            // 默认格式
            pattern = "yyyy-MM-dd HH:mm:ss";
        }

        SimpleDateFormat sdf = new SimpleDateFormat(pattern);

        // 设置时区
        String timezone = jsonFormat.timezone();
        if (!timezone.isEmpty() && !timezone.equals(JsonFormat.DEFAULT_TIMEZONE)) {
            sdf.setTimeZone(TimeZone.getTimeZone(timezone));
        }

        return sdf.format(date);
    }


}

Validator 校验框架工具

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import cn.hutool.extra.spring.SpringUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.Set;

/**
 * Validator 校验框架工具
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtil {

    private static final Validator VALID = SpringUtil.getBean(Validator.class);

    /**
     * 对给定对象进行参数校验,并根据指定的校验组进行校验
     *
     * @param object 要进行校验的对象
     * @param groups 校验组
     * @throws ConstraintViolationException 如果校验不通过,则抛出参数校验异常
     */
    public static <T> void validate(T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
        if (!validate.isEmpty()) {
            throw new ConstraintViolationException("参数校验异常", validate);
        }
    }

}

阿里excel工具类

import com.alibaba.excel.EasyExcel;
import com.esse.projects.inm.common.excel.DefaultExcelListener;
import com.esse.projects.inm.common.excel.ExcelListener;
import com.esse.projects.inm.common.excel.ExcelResult;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * 阿里excel工具类
 */
public class EasyExcelUtil {

    /**
     * 同步导入(适用于小数据量)
     *
     * @param is 输入流
     * @return 转换后集合
     */
    public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
    }

    /**
     * 使用校验监听器 异步导入 同步返回
     *
     * @param is         输入流
     * @param clazz      对象类型
     * @param isValidate 是否 Validator 检验 默认为是
     * @return 转换后集合
     */
    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
        DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
        EasyExcel.read(is, clazz, listener).sheet().doRead();
        return listener.getExcelResult();
    }

    /**
     * 使用自定义监听器 异步导入 自定义返回
     *
     * @param is       输入流
     * @param clazz    对象类型
     * @param listener 自定义监听器
     * @return 转换后集合
     */
    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
        EasyExcel.read(is, clazz, listener).sheet().doRead();
        return listener.getExcelResult();
    }

    /**
     * 导出excel
     *
     * @param list      导出数据集合
     * @param sheetName 工作表的名称
     * @param clazz     实体类
     */
    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), clazz)
                .sheet(sheetName)
                .doWrite(list);
    }

}

import java.util.List;

/**
 * excel返回对象
 */
public interface ExcelResult<T> {

    /**
     * 对象列表
     */
    List<T> getList();

    /**
     * 错误列表
     */
    List<String> getErrorList();

    /**
     * 导入回执
     */
    String getAnalysis();
}

import com.alibaba.excel.read.listener.ReadListener;

/**
 * Excel 导入监听
 */
public interface ExcelListener<T> extends ReadListener<T> {

    ExcelResult<T> getExcelResult();

    void addError(String error);

}

import lombok.Setter;

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

/**
 * 默认excel返回对象
 */
public class DefaultExcelResult<T> implements ExcelResult<T> {

    /**
     * 数据对象list
     */
    @Setter
    private List<T> list;

    /**
     * 错误信息列表
     */
    @Setter
    private List<String> errorList;

    public DefaultExcelResult() {
        this.list = new ArrayList<>();
        this.errorList = new ArrayList<>();
    }

    public DefaultExcelResult(List<T> list, List<String> errorList) {
        this.list = list;
        this.errorList = errorList;
    }

    public DefaultExcelResult(ExcelResult<T> excelResult) {
        this.list = excelResult.getList();
        this.errorList = excelResult.getErrorList();
    }

    @Override
    public List<T> getList() {
        return list;
    }

    @Override
    public List<String> getErrorList() {
        return errorList;
    }

    /**
     * 获取导入回执
     *
     * @return 导入回执
     */
    @Override
    public String getAnalysis() {
        int successCount = list.size();
        int errorCount = errorList.size();
        if (errorCount == 0) {
            return "全部导入成功!";
        } else {
            if (successCount == 0) {
                return "全部导入失败<br/>" + String.join("<br/>", errorList);
            } else {
                return "部分导入失败<br/>" + String.join("<br/>", errorList);
            }
        }
    }
}

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;
import com.esse.projects.inm.common.util.ValidatorUtil;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Excel 默认导入监听
 */
@Slf4j
@NoArgsConstructor
public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> {

    /**
     * 是否Validator检验,默认为是
     */
    private Boolean isValidate = Boolean.TRUE;

    /**
     * excel 表头数据
     */
    private Map<Integer, String> headMap;

    /**
     * 导入回执
     */
    private ExcelResult<T> excelResult;

    private static final String FORMAT = "第{}行数据校验异常: {}";
    private static final String BUSINESS = "第{}行业务逻辑异常: {}";

    public DefaultExcelListener(boolean isValidate) {
        this.excelResult = new DefaultExcelResult<>();
        this.isValidate = isValidate;
    }

    /**
     * 处理异常
     *
     * @param exception ExcelDataConvertException
     * @param context   Excel 上下文
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            // 如果是某一个单元格的转换异常 能获取到具体行号
            Integer rowIndex = excelDataConvertException.getRowIndex();
            Integer columnIndex = excelDataConvertException.getColumnIndex();
            addError(StrUtil.format("第{}行-第{}列-表头{}: 解析异常<br/>",
                    rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)));
        } else if (exception instanceof ConstraintViolationException) {
            ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception;
            Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();
            String constraintViolationsMsg = constraintViolations.stream().map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(", "));
            addFormatError(context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);
        }
    }

    /**
     * 处理表头
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
        log.debug("解析到一条表头数据: {}", JSON.toJSONString(headMap));
    }

    /**
     * 处理数据
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        if (isValidate) {
            ValidatorUtil.validate(data);
        }
        excelResult.getList().add(data);
    }

    /**
     * 所有数据分析完成后的回调
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.debug("所有数据解析完成!");
    }

    @Override
    public ExcelResult<T> getExcelResult() {
        return excelResult;
    }

    @Override
    public void addError(String error) {
        excelResult.getErrorList().add(error);
    }

    public void addFormatError(Integer rowIndex, String error) {
        addError(StrUtil.format(FORMAT, rowIndex, error));
    }

    public void addBusinessError(Integer rowIndex, String error) {
        addError(StrUtil.format(BUSINESS, rowIndex, error));
    }

}

使用示例
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.io.Serializable;


@EqualsAndHashCode(callSuper = true)
@Data
@ExcelTarget("***")
public class StableUnitExcel extends BaseExcel {

    @ExcelProperty("类型*")
    @ColumnWidth(20)
    @NotBlank(message = "类型不能为空")
    private String typeName;

    @ExcelProperty("社会统一信用代码*")
    @ColumnWidth(30)
    @NotBlank(message = "社会统一信用代码不能为空")
    private String unitIntegrityCode;

    @ExcelProperty("单位名称")
    @ColumnWidth(25)
    private String unitName;

    @ExcelProperty("项目编号*")
    @ColumnWidth(25)
    @NotBlank(message = "项目编号不能为空")
    private String projectCode;

    @ExcelProperty("项目名称")
    @ColumnWidth(30)
    private String projectName;

    @ExcelProperty("禁用到期时间(不填为永久)")
    @ColumnWidth(25)
    @Pattern(message = "禁用到期时间格式错误,正确示例:2025-10-01", regexp = "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$")
    private String forbiddenEndTime;

    @ExcelProperty("事由*")
    @ColumnWidth(50)
    @NotBlank(message = "事由不能为空")
    @Size(message = "事由长度不能大于2000", max = 2000)
    private String remark;

}

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.context.AnalysisContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 监听
 */
@Slf4j
public class StableGreyExcelListener extends DefaultExcelListener<StableGreyExcel> {

    private final IStableGreyService stableGreyService;
    private final RemoteEmployeeServer remoteEmployeeServer;
    private final CmService cmService;
    private final ProjectInfoService projectInfoService;
    private final ProjectSystemDetailService projectSystemDetailService;

    public StableGreyExcelListener() {
        super(false);
        this.remoteEmployeeServer = SpringUtil.getBean(RemoteEmployeeServer.class);
        this.stableGreyService = SpringUtil.getBean(IStableGreyService.class);
        this.cmService = SpringUtil.getBean(CmService.class);
        this.projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
        this.projectSystemDetailService = SpringUtil.getBean(ProjectSystemDetailService.class);
    }

    @Override
    public void invoke(StableGreyExcel data, AnalysisContext context) {
        // 保存行号信息
        data.setRowIndex(context.readRowHolder().getRowIndex() + 1);
        // 格式校验
        ValidatorUtil.validate(data);
        getExcelResult().getList().add(data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        List<StableGreyExcel> list = getExcelResult().getList();

        // 批量查询单位信息、项目信息
        Set<String> unitIntegrityCodeSet = list.stream().map(StableGreyExcel::getUnitIntegrityCode).collect(Collectors.toSet());
        Set<String> projectCodeSet = list.stream().map(StableGreyExcel::getProjectCode).collect(Collectors.toSet());
        Map<String, ContractorUnitVO> unitMap = MapUtil.listToMap(
                cmService.getUnitListByIntegrityCodeList(new ArrayList<>(unitIntegrityCodeSet)).getData(),
                ContractorUnitVO::getIntegrityCode
        );
        Map<String, ProjectInfoVO> projectMap = MapUtil.listToMap(
                projectInfoService.getProjectByCodes2(String.join(",", projectCodeSet)),
                ProjectInfoVO::getProjectInfoCode
        );

        Long tenantId = SecurityUtils.getUser().getSysTenantUserVO().getTenantId();

        List<StableGreyEntity> insertList = new ArrayList<>();
        for (StableGreyExcel stableGreyExcel : list) {
            Integer rowIndex = stableGreyExcel.getRowIndex();

            StableGreyEntity entity = new StableGreyEntity();
            BeanUtils.copyProperties(stableGreyExcel, entity);

            // 禁用到期时间
            if (StrUtil.isNotBlank(stableGreyExcel.getForbiddenEndTime())) {
                entity.setForbiddenEndTime(DateUtil.stringToDate(stableGreyExcel.getForbiddenEndTime()));
            }

            // 人员信息
            List<IdNameOrgVO> userList = remoteEmployeeServer.listByidNo(stableGreyExcel.getIdentityCard(), tenantId).getData();
            if (CollectionUtils.isEmpty(userList)) {
                addBusinessError(rowIndex, "未找到相关人员信息");
                continue;
            }
            IdNameOrgVO user = userList.get(0);
            if (!stableGreyExcel.getGreyUserName().equals(user.getName())) {
                addBusinessError(rowIndex, "人员姓名与身份证号不匹配");
                continue;
            }
            entity.setGreyUserId(Long.parseLong(user.getId()));

            // 单位信息
            ContractorUnitVO unit = unitMap.get(stableGreyExcel.getUnitIntegrityCode());
            if (unit == null) {
                addBusinessError(rowIndex, "未找到该统一信用社会代码的单位");
                continue;
            }
            if (StrUtil.isNotEmpty(stableGreyExcel.getUnitName())
                    && !stableGreyExcel.getUnitName().equals(unit.getName())) {
                addBusinessError(rowIndex, "统一信用社会代码与单位名称不匹配");
                continue;
            }
            entity.setUnitId(unit.getId());
            entity.setUnitName(unit.getName());

            // 项目信息
            if (StrUtil.isNotBlank(stableGreyExcel.getProjectCode())) {
                ProjectInfoVO projectInfoVO = projectMap.get(stableGreyExcel.getProjectCode());
                if (projectInfoVO == null) {
                    addBusinessError(rowIndex, "未找到该项目编码的项目信息");
                    continue;
                }
                if (StrUtil.isNotBlank(stableGreyExcel.getProjectName())
                        && !stableGreyExcel.getProjectName().equals(projectInfoVO.getProjectInfoName())) {
                    addBusinessError(rowIndex, "项目编码和项目名称不匹配");
                    continue;
                }
                entity.setProjectId(projectInfoVO.getProjectInfoId());
                entity.setProjectName(projectInfoVO.getProjectInfoName());
            }

            // 职务信息 如果未匹配到则不处理
            if (StrUtil.isNotBlank(stableGreyExcel.getPostName()) && entity.getUnitId() != null) {
                List<SimpleBeanVO> simpleBeanVOList = projectSystemDetailService.personListOfPerson(Long.parseLong(user.getId()), entity.getUnitId()).getData();
                for (SimpleBeanVO simpleBeanVO : simpleBeanVOList) {
                    if (stableGreyExcel.getPostName().equals(simpleBeanVO.getName())) {
                        entity.setPostId(simpleBeanVO.getId());
                    }
                }
            }

            insertList.add(entity);
        }

        if (CollectionUtils.isNotEmpty(insertList)) {
            stableGreyService.saveBatch(insertList);
        }

        log.info("所有数据解析完成!");
    }

}

kepserverEX6创建tcpserver接入自有协议(使用ucon接入) kepserverEX6创建tcpserver接入自有协议 阅读详情

相关推荐

DataWorks PyODPS第三方包全攻略:从打包到加载的完整流程

本文详细介绍了在DataWorks的PyODPS节点中使用第三方Python包的完整流程,包括环境限制、打包工具pyodps-pack的使用、资源上传与加载实战,以及特殊场景处理技巧。通过本文,开发者可以掌握在MaxCompute受限环境中灵活使用自定义依赖的方法,提升数据处理效率。

dd012的博客 993

常用工具类的集合方法总结

Collections 1.反转指定列表中元素的顺序 public static void reverse(List<?> list) 2.随机排列集合 public static void shuffle(List<?> list) 3.交换指定位置的集合 public static void swap(List<?> list, int i, int j) 4.用指定的元素替换指定列表中的所有元素 public static <T> void f

尚凯辉的博客 1662

Simulink中通过MEX与MinGW实现C/C++结构体变量的高效导入

本文详细介绍了在Simulink中通过MEX工具链与MinGW编译器,高效导入C/C++结构体变量的完整流程。文章从需求背景出发,逐步讲解了MinGW环境配置、.h文件编写规范、核心导入命令Simulink.importExternalCTypes的使用,以及如何在MATLAB Function模块和总线创建器中调用自定义结构体,旨在实现模型与代码的无缝对齐,为后续仿真和代码生成奠定坚实基础。

weixin_29056781的博客 345

集合常用工具方法

package com.util; import java.util.*; public class CollectionUtils extends org.apache.commons.collections.CollectionUtils { /** * 过滤空 * * @param list * @param <T> ...

Jie_Dn的博客 240

Oracle数据库安装图文教程 附百度云oracle Database 11g 安装包

一,Oracle数据库安装包下载 1.从Oracle官网下载所需的数据库安装包【下载需要注册登录Oracle账户】     http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html 2.此处有下载好的Oracle Database 11g Release 2  百度云网盘  提取码:z...

向来如此,就一定是对的吗 6万+

奥比中光Dabai深度相机SDK在Ubuntu22.04的兼容性安装指南

本文详细指导如何在Ubuntu22.04系统上安装奥比中光Dabai深度相机的SDK。针对新旧版本不兼容的核心问题,重点推荐使用经过验证的v1.10.18版本SDK,并提供了从系统依赖检查、SDK下载安装、Python环境配置到编译测试的完整步骤,帮助用户成功解决安装难题并实现相机驱动。

j2k3l4的博客 1001

MongoDB常用工具和集合方法

MongoDB 常用工具 工具 描述 mongosniff mongodb监测工具,作用类似于 tcpdump mongodump MongoDB数据备份工具 mongoimport Mongodb数据导入工具 mongoexport Mongodb数据导出工具 bsondump 将 bson 格式的文件转储为 json 格式的数据 ...

菲宇运维 767

Camera | 瑞芯微rk3568平台MIPI-CSI驱动:从设备树到V4L2框架的完整链路解析

本文深入解析瑞芯微rk3568平台MIPI-CSI驱动的完整链路,从设备树配置到V4L2框架集成。详细介绍了rk3568的MIPI-CSI驱动架构、设备树关键节点布局、驱动初始化流程及数据流路径,帮助开发者快速掌握摄像头控制器的调试与优化技巧,实现稳定的视频采集系统。

weixin_28703489的博客 291

【Java常用工具类】集合操作常用方法

package util; import com.alibaba.fastjson.JSONObject; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import static com.alibaba.fastjson.JSON.parseObject; public class Col

自律使我自由 1025

Windows 11 的C盘User(用户)文件夹下的用户文件夹名称的修改

背景介绍:由于系统重装导致Windows 11的系统用户名与C盘User(用户)文件夹下的用户名文件夹(公用文件夹旁边的文件夹)出现名称不一致,事例中系统用户名命名为“寂萧”,User(用户)文件夹下的文件夹名称却是“77555”。【QQ邮箱前五位真的真的看着很别扭】注:改名有风险,三思而后行。User(用户)文件夹下的用户名是中文在某些软件的应用场景下产生不便,导致很多软件莫名其妙报错,甚至无法使用,笔者不建议修改为中文名。//和笔者一样的强迫症除外//

2302_79084172的博客 10万+

Geant4学习一:写一个简单程序

1、 基本介绍

ccwwNUAA的博客 7699

layui工具函数util:常用工具方法的集合

> 还在为Web开发中的日期处理、HTML转义、事件绑定等常见需求而烦恼吗?layui的util模块提供了一套完整、易用的工具函数集合,让你的开发效率提升数倍! 通过本文,你将掌握: - ✅ util模块的核心功能和使用方法 - ✅ 日期时间处理的完整解决方案 - ✅ HTML安全转义与还原的最佳实践 - ✅ 批量事件绑定的高效技巧 - ✅ 实际项目中的代码示例和应用场景 ## 什么是l...

gitblog_00395的博客 760

华为OD技术面八股_C++_05

汇总华为OD技术面C++方向技术面八股文,提供详细解答。

qq_45776114的博客 413

GO 语言常用工具类-通用方法集合

GO 语言常用工具类-通用方法集合 github: https://github.com/gitstliu/go-commonfunctions 1. PanicHandler 通用Panic处理器 2. InterfacesToStrings 将Interface数组转换为String数组 3. GetFilesWithFolder 获得文件夹下所有文件 4. ObjectToJson 将对象转...

在白板上作画 4518

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

浅谈集合框架三、Map常用方法及常用工具类

最近刚学完集合框架,想把自己的一些学习笔记与想法整理一下,所以本篇博客或许会有一些内容写的不严谨或者不正确,还请大神指出。初学者对于本篇博客只建议作为参考,欢迎留言共同学习。   之前有介绍集合框架的体系概念(http://www.cnblogs.com/yjboke/p/8761195.html),本篇介绍一下Map的常用方法及常用工具类。 map基本查询方法:   增加:...

dichong9855的博客 143

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

js常用工具方法集合

如何将浮点数点左边的数每三位添加一个逗号,如12000000.11转化为『12,000,000.11』? function formatNumber(value) { var re = /^(\-?)(\d{1,3}(,\d\d\d)*(\.\d+)?|\d+(\.\d+)?)$/; if (!re.test(value)) { return value;...

小白变怪兽 3604

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Java常用工具方法整理集合

/** * @Author: MrZcc * @Description: * @Modified By: */ public class Utils { /** * @Description:判断字符串是否为数字,支持整数,负数,小数 * @param: string 需要判断的字符串 * @return: boolean true---是数字,f...

zcczero的博客 190

操作集合的常用工具类Collections和Arrays的常见方法

Collections 工具类和 Arrays 工具类常见方法 Collections 排序操作 查找,替换操作 同步控制 Arrays类的常见操作 排序 : sort() 查找 : binarySearch() 比较: equals() 填充 : fill() 转列表 asList() 转字符串 toString() 复制 copyOf() Collections 工具类和 Arrays 工具类常见方法 Collections Collections 工具类常用方法: 排序 查..

tc979907461的博客 406

Awesome DeepSeek Integrations工具函数:常用工具类与工具方法集合

Awesome DeepSeek Integrations项目汇集了众多与DeepSeek大模型集成的优秀工具和框架,为开发者提供了丰富的工具函数和工具类。这些工具函数涵盖了从API调用、数据处理到智能体开发的各个方面,极大地简化了AI应用的开发流程。 ## 核心工具函数分类 ### 1. API调用工具类 #### DeepSeek API客户端工具 ```typescript // T...

gitblog_00905的博客 917

集合

集合 集合可以分位单列集合和双列集合 单列集合 Collection:是单例集合的根接口,用于存储一系列符合某种规则的元素。Collection集合一共有两个子接口,分别对是List和Set。其中,List集合的特点是元素有序,可以重复;Set集合的特点是元素无序并且不可重复。List接口主要实现的类有ArrayList和LinkList;Set接口主要实现的类有HashSet和TreeSet。 List接口下有ArrayList和LinkList接口,两者的区别在于ArrayList内部的数据存储结

m0_48567257的博客 193

Java常用工具类之集合List、Set、Map

Java常用工具类之集合 一、List 在Collection中,List集合是有序的,Developer可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素。 在List集合中,我们常用到ArrayList和LinkedList这两个类。 0x1 ArrayList ArrayList底层通过数组实现,随着元素的增加而动态扩容。而LinkedList底...

慕白博客 1432

java 常用工具方法

1.需求场景 java 开发常用工具方法 2.环境 JDK1.7 3.方法 (1)java计算时间差及比较时间大小 //方法一 DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date d1 = df.parse("2019-03-26 13:31:40"); Date d2 = df.parse(...

u011625492的专栏 209

Java的集合

1. 集合类体系结构 2. Collection集合概述和使用 2.1 Collection集合概述 是单列集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素 JDk不提供此接口的任何直接实现,它提供更具体的子接口实现 2.2 创建Collection集合的对象 多态的方式 具体的实现类ArrayList 2.3 Collection集合常用方法 方法名 说明 对象名.add() 添加元素 对象名.remove() 从集合中移除指定的元素 对象名.cl

打代码是一天,不打代码也是一天 221

Day12 JavaSE基础复习 (14)正则表达式&常用工具类 (15)Collection集合

(14)正则表达式&常用工具类 一. 正则表达式(regex) 字符类 预定义字符类 数量词 Pattern和Matcher java.util.regex.Pattern java.util.regex.Matcher Pattern p = Pattern.compile(regex); //获取到正则表达式 Matcher m = p.matche...

ambition 282

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 303
上一篇: 自定义注解实现数据转换(单条和批量),支持aop自动转换和手动转换
String_001
博客等级 码龄5年 16粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值