Java导出DBF文件(附带工具类)
导出DBF文件
先看效果
JavaDBF
使用JavaDBF库
数据类型映射
写入支持的类型
类型 | 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 |
注:读取这里不总结,可以参考上面链接的官方文档
安装
这里只讲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;}@Overridepublic 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);
}