All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.azbh111.utils.java.csv.CsvExporter Maven / Gradle / Ivy

The newest version!
package com.github.azbh111.utils.java.csv;

import com.github.azbh111.utils.java.charset.Charsets;
import com.github.azbh111.utils.java.datetime.DateTimeUtils;
import com.github.azbh111.utils.java.reflect.ReflectUtils;
import lombok.ToString;

import java.io.OutputStream;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * @author: zyp
 * @date: 2020/12/4 18:24
 */
public class CsvExporter {
    private final Map> cache = new ConcurrentHashMap<>();
    private final Map> toStringMapping = new ConcurrentHashMap<>();
    private final Map> formatMapping = new ConcurrentHashMap<>();
    private final Function toStringConventor = x -> String.valueOf(x);
    private Charset charset = Charsets.UTF_8;

    public void registerToStringConventor(Class srcType, Function conventor) {
        toStringMapping.put(srcType, conventor);
    }

    public CsvExporterTask newTask(Class cls, OutputStream outputStream) {
        return new CsvExporterTask(this, cls, outputStream);
    }

    public CsvExporterTask newTask(Class cls, Writer writer) {
        return new CsvExporterTask(this, cls, writer);
    }

    List getColumns(Class cls) {
        List defines = cache.get(cls);
        if (defines != null) {
            return defines;
        }
        List fieldWrappers = new ArrayList<>();
        for (Field f : ReflectUtils.getAllFields(cls)) {
            if (!f.isAnnotationPresent(CsvColumn.class)) {
                continue;
            }
            f.setAccessible(true);
            CsvColumn config = f.getAnnotation(CsvColumn.class);
            CsvColumnDefine define = CsvColumnDefine.builder()
                    .field(f)
                    .order(config.order())
                    .name(config.value())
                    .conventor(getConventor(f.getType(), config))
                    .nullValue(config.nullValue())
                    .build();
            fieldWrappers.add(define);
        }
        for (Method m : ReflectUtils.getAllMethods(cls)) {
            if (!m.isAnnotationPresent(CsvColumn.class)) {
                continue;
            }
            m.setAccessible(true);
            CsvColumn config = m.getAnnotation(CsvColumn.class);
            CsvColumnDefine define = CsvColumnDefine.builder()
                    .method(m)
                    .order(config.order())
                    .name(config.value())
                    .conventor(getConventor(m.getReturnType(), config))
                    .nullValue(config.nullValue())
                    .build();
            fieldWrappers.add(define);
        }
        fieldWrappers.sort(Comparator.comparingInt(CsvColumnDefine::getOrder));
        defines = Collections.unmodifiableList(fieldWrappers);
        cache.put(cls, defines);
        return defines;
    }

    private Function getConventor(Class cls, CsvColumn config) {
        if (!config.format().isEmpty()) {
//            指定了格式,尝试解析格式
            String format = config.format();
            String key = cls.getName() + ":" + config.format();
            Function mapper = formatMapping.get(key);
            if (mapper != null) {
                return mapper;
            }
            if (TemporalAccessor.class.isAssignableFrom(cls)) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(config.format());
                mapper = x -> formatter.format((TemporalAccessor) x);
            } else if (Date.class == cls) {
                mapper = new Function() {
                    private final String formatter = config.format();
                    //                    SimpleDateFormat线程不安全
                    private final ThreadLocal threadLocal = new ThreadLocal<>();

                    @Override
                    public String apply(Object o) {
                        SimpleDateFormat format = threadLocal.get();
                        if (format == null) {
                            format = new SimpleDateFormat(formatter);
                            threadLocal.set(format);
                        }
                        return format.format((Date) o);
                    }
                };
            } else if (cls == float.class || cls == Float.class || cls == double.class || cls == Double.class || cls == BigDecimal.class) {
//                格式化小数
                mapper = x -> String.format(format, x);
            }
            if (mapper != null) {
                formatMapping.put(key, mapper);
                return mapper;
            }
        }
        Function conventor = toStringMapping.get(cls);
        return conventor == null ? toStringConventor : conventor;
    }

    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    public Charset getCharset() {
        return charset;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy