Java导出DBF文件(附带工具类)

导出DBF文件

先看效果
在这里插入图片描述

JavaDBF

使用JavaDBF

数据类型映射

写入支持的类型

类型XBase类型XBase 符号JavaDBF 中使用的 Java 类型
字符CharacterCjava.lang.String
数值NumericNjava.math.BigDecimal
浮点Floating PointFjava.math.BigDecimal
布尔LogicalLjava.lang.Boolean
时间DateDjava.util.Date

注:读取这里不总结,可以参考上面链接的官方文档

安装

这里只讲Maven操作

在 pom.xml 中使用此依赖项将 JavaDBF 添加到项目中

<dependency>
	<groupId>com.github.albfernandez</groupId>
	<artifactId>javadbf</artifactId>
	<version>1.14.0</version>
</dependency>

编写DBF文件

创建 .dbf(DBFWriter) 数据文件时,必须处理两个方面:
1、定义字段(DBFField)
2、填充数据(public void addRecord(Object[] values))

官网的例子:

import com.linuxense.javadbf.*;
import java.io.*;

public class JavaDBFWriterTest {

	public static void main(String args[]) throws IOException {
		// 1、DBFWriter 用于创建 .dbf 文件
		DBFWriter writer = new DBFWriter(new FileOutputStream(args[0]));

		// 2、定义字段
		// 创建三个 DBFField 类的对象
		DBFField[] fields = new DBFField[3];
		fields[0] = new DBFField();
		fields[0].setName("emp_code"); // 给字段一个名字
		fields[0].setType(DBFDataType.CHARACTER); // 设置它的类型
		fields[0].setLength(10); // 字段的长度

		fields[1] = new DBFField();
		fields[1].setName("emp_name");
		fields[1].setType(DBFDataType.CHARACTER);
		fields[1].setLength(20);

		fields[2] = new DBFField();
		fields[2].setName("salary");
		fields[2].setType(DBFDataType.NUMERIC);
		fields[2].setLength(12);
		fields[2].setDecimalCount(2);

		// 3、写入字段
		writer.setFields(fields);

		// 4、填充数据
		Object rowData[] = new Object[3];
		rowData[0] = "1000";
		rowData[1] = "John";
		rowData[2] = new Double(5000.00);
		writer.addRecord(rowData);

		rowData = new Object[3];
		rowData[0] = "1001";
		rowData[1] = "Lalit";
		rowData[2] = new Double(3400.00);
		writer.addRecord(rowData);

		rowData = new Object[3];
		rowData[0] = "1002";
		rowData[1] = "Rohit";
		rowData[2] = new Double(7350.00);
		writer.addRecord(rowData);

		writer.close();
	}
}

到此,.dbf文件就创建成功。此时,还有个问题存在当出现中文字符时,内容显示?。

在这里插入图片描述

我们只需要做一下变动

DBFWriter writer = new DBFWriter(new FileOutputStream(args[0]), Charset.forName("GBK"));
// 或
DBFWriter writer = new DBFWriter(new FileOutputStream(args[0]), Charset.forName("UTF-8"));

工具类

1、创建 Dbf 注解类

import com.linuxense.javadbf.DBFDataType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义导出DBF数据注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Dbf
{
    /**
     * 列名字.   xxx,C,30  xxx位置的名字
     */
    public String name() default "";

    /**
     * 值类型 默认字符串  参考 DBFDataType 枚举类
     */
    public DBFDataType dataType() default DBFDataType.CHARACTER;

    /**
     * 数据长度
     *
     * 字符串   最大254
     * 布尔值   最大1
     * 时间     最大8
     * 数值     最大32
     *
     */
    public int length() default 1;

    /**
     * 精度
     */
    public int decimalCount() default 0;

    /**
     * 列显示的顺序
     */
    public int sort() default Integer.MAX_VALUE;
}

2、创建 DBFUtils 工具类

import com.linuxense.javadbf.DBFField;
import com.linuxense.javadbf.DBFWriter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * DBF文件工具类
 **/
public class DBFUtils<T> {
    private DBFWriter writer;

    // 需要排除列
    private String[] excludeFields;

    // 注解字段信息
    private List<Object[]> fields;

    // 数据
    private List<T> data;

    // 实体
    private Class<T> clazz;

    public DBFUtils(Class<T> clazz) {
        this.clazz = clazz;
    }

    /**
     * 排除列导出
     *
     * @param fields 列属性名 示例[单个"name"/多个"id","name"]
     * @throws Exception
     */
    public void excludeColumn(String... fields)
    {
        this.excludeFields = fields;
    }

    /**
     * 导出DBF
     *
     * <h1>写入DBF支持的数据类型</h1>
     *
     * XBase类型	        XBase符号	   JavaDBF中使用的Java类型
     * Character	    C	           java.lang.String
     * Numeric	        N	           java.math.BigDecimal
     * Floating Point	F	           java.math.BigDecimal
     * Logical	        L	           java.lang.Boolean
     * Date	            D	           java.util.Date
     *
     * @param response 返回数据
     * @param data 导出数据集合
     * @param fileName 文件名称
     */
    public void exportDBF(HttpServletResponse response, List<T> data, String fileName)
    {
        try {
            // 初始化
            this.init(response, data, fileName);
            // 写入内容
            this.writeContent();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void init(HttpServletResponse response, List<T> data, String fileName) throws IOException {
        this.responseByDBF(response, fileName);
        this.writer = new DBFWriter(response.getOutputStream(), Charset.forName("GBK"));
        this.data = data;
        this.fields = this.getFields();
    }

    private void responseByDBF(HttpServletResponse response, String fileName) {
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".DBF");
    }

    /**
     * 往工作区中写入内容
     */
    private void writeContent() throws IllegalAccessException {
        int size = fields.size();

        // 写入表头
        writer.setFields(this.dbfFields());

        if (ObjectUtils.isNotEmpty(this.data)) {
            Object[] row = null;

            for (T vo : this.data) {
                row = new Object[size];

                for (int i = 0; i < size; i++) {
                    Object[] os = fields.get(i);

                    Field field = (Field) os[0];
                    field.setAccessible(true);
                    Object o = field.get(vo);
                    // TODO 这里可能会出现类型异常,遇到再处理
                    row[i] = o;
                }
                // 写入行数据
                writer.addRecord(row);
            }
        }

        writer.close();
    }

    /**
     * 获取表头
     *
     * @return  返回标题信息
     */
    private DBFField[] dbfFields() {
        int size = this.fields.size();

        // 写入表头
        DBFField[] dbfFields = new DBFField[size];
        for (int i = 0; i < fields.size(); i++) {
            Object[] os = fields.get(i);

            Dbf dbf = (Dbf) os[1];
            dbfFields[i] = new DBFField(dbf.name(), dbf.dataType(), dbf.length(), dbf.decimalCount());
        }

        return dbfFields;
    }

    /**
     * 获取导出DBF的字段
     *
     * @return  注解字段信息
     */
    private List<Object[]> getFields() {
        List<Object[]> fields = new ArrayList<Object[]>();
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        for (Field field : tempFields)
        {
            if (!ArrayUtils.contains(this.excludeFields, field.getName()))
            {
                // 单注解
                if (field.isAnnotationPresent(Dbf.class))
                {
                    Dbf attr = field.getAnnotation(Dbf.class);
                    if (attr != null)
                    {
                        field.setAccessible(true);
                        fields.add(new Object[] { field, attr });
                    }
                }
            }
        }
        return fields.stream().sorted(Comparator.comparing(objects -> ((Dbf) objects[1]).sort())).collect(Collectors.toList());
    }
}

3、使用
创建实体

import com.linuxense.javadbf.DBFDataType;

import java.math.BigDecimal;
import java.util.Date;

public class Student
{
    private static final long serialVersionUID = 1L;

    // 名称
    @Dbf(name = "NAME", length = 254)
    private String name;

    //  年龄
    @Dbf(name = "AGE", dataType = DBFDataType.NUMERIC, length = 32)
    private Integer age;

    // 成绩
    @Dbf(name = "GRADE", dataType = DBFDataType.NUMERIC, length = 32)
    private BigDecimal grade;

    // 是否寄宿
    @Dbf(name = "IS_LODGE", dataType = DBFDataType.LOGICAL, length = 1)
    private Boolean isLodge;

    // 入学时间
    @Dbf(name = "ENROL_TIME", dataType = DBFDataType.DATE, length = 8)
    private Date enrolTime;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public BigDecimal getGrade() {
        return grade;
    }

    public void setGrade(BigDecimal grade) {
        this.grade = grade;
    }

    public Boolean getIsLodge() {
        return isLodge;
    }

    public void setIsLodge(Boolean islodge) {
        this.isLodge = islodge;
    }

    public Date getEnrolTime() {
        return enrolTime;
    }

    public void setEnrolTime(Date enrolTime) {
        this.enrolTime = enrolTime;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", grade=" + grade +
                ", isLodge=" + isLodge +
                ", enrolTime=" + enrolTime +
                '}';
    }
}

Controller

@PostMapping("/exportDBF")
public void exportDBF(HttpServletResponse response)
{
    List<Student> data = new ArrayList<>();

    Student bean = new Student();
    bean.setName("小明");
    bean.setAge(16);
    bean.setGrade(BigDecimal.valueOf(80));
    bean.setIsLodge(Boolean.FALSE);
    bean.setEnrolTime(new Date(2023, 8, 8));
    data.add(bean);
    bean = new Student();
    bean.setName("小刚");
    bean.setAge(16);
    bean.setGrade(BigDecimal.valueOf(85));
    bean.setIsLodge(Boolean.FALSE);
    bean.setEnrolTime(new Date(2023, 8, 8));
    data.add(bean);
    bean = new Student();
    bean.setName("小华");
    bean.setAge(16);
    bean.setGrade(BigDecimal.valueOf(100));
    bean.setIsLodge(Boolean.TRUE);
    bean.setEnrolTime(new Date(2021, 8, 8));
    data.add(bean);
    bean = new Student();
    bean.setName("小丽");
    bean.setAge(16);
    bean.setGrade(BigDecimal.valueOf(90));
    bean.setIsLodge(Boolean.TRUE);
    bean.setEnrolTime(new Date(2022, 8, 8));
    data.add(bean);

    DBFUtils<Student> utils = new DBFUtils<>(Student.class);
    utils.exportDBF(response, data, null);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值