导出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;
}
@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);
}