Download file in csv format for java

上篇轻微的了解了反射,及将要用的工具类,今天咱继续站在巨人的肩膀上学习从浏览器下载文件相关工具类,开发最快的速度,创造更高的成就,就是直接传送门:https://blog.csdn.net/accountwcx/article/details/46775397;

今天要讲的是第一种实现csv格式数据导出(注解式),闲话少说直接刚;

    private static final String FILE_FORMAT = ".csv";
	private static final String COMMA_DELIMITER = ",";
	private static final String NEW_LINE_SEPARATOR = "\n";
	private static final String ENCODINT_GBK = "gbk";
	private static final String BLANK_STRING = "";
	// 处理下载数据时数字出现科学计数法问题
	private static final String SPECIAL_SYMBOLS = "`";
    

 

	/**
	 * 创建csv文件,基于注解实现
	 * @param fileName 文件名
	 * @param list 导出数据对象集合
	 * @return csv文件
	 */
	public File createCsvFile(String fileName, List<T> list) {
		// 注解
		List<Object[]> annotationList = Lists.newArrayList();
		// 标题头
		List<String> headerList = Lists.newArrayList();
		// 域名
		List<String> fieldList = Lists.newArrayList();
		File f = null;
		OutputStreamWriter fileWriter = null;
		try {
			f = File.createTempFile(fileName, FILE_FORMAT);
			fileWriter = new OutputStreamWriter(new FileOutputStream(f), ENCODINT_GBK);
			Class<? extends Object> cla = list.get(0).getClass();
			Field[] fields = cla.getDeclaredFields();
			for (Field field : fields) {
				CsvField csvField = field.getAnnotation(CsvField.class);
				if (Objects.nonNull(csvField)) {
					annotationList.add(new Object[] { csvField, field });
					// 获取域名
					fieldList.add(field.getName());
				}
			}
			// 获取表头
			for (Object[] os : annotationList) {
				String fieldTitle = ((CsvField) os[0]).title();
				// 如果是非必填,加上注释
				int required = ((CsvField) os[0]).required();
				if (required == 0) {
					fieldTitle = fieldTitle + "(非必填)";
				}
				headerList.add(fieldTitle);
			}
			fileWriter.append(listToString(fieldList));
			fileWriter.append(NEW_LINE_SEPARATOR);
			fileWriter.append(listToString(headerList));
			fileWriter.append(NEW_LINE_SEPARATOR);
			//
			for (Object v : list) {
				for (Object[] os : annotationList) {
					CsvField ef = (CsvField) os[0];
					Object val = null;
					// 获取入参值
					try {
						if (StringUtils.isNotBlank(ef.value())) {
							val = ReflectUtils.invokeGetter(v, ef.value());
						} else if (os[1] instanceof Field) {
							val = ReflectUtils.invokeGetter(v, ((Field) os[1]).getName());
						}
					} catch (Exception ex) {
						logger.error("the reflect is error msg is {}", ex);
						// 如果异常,忽略
						val = BLANK_STRING;
					}
					if (ef.isSpecial()) {
						fileWriter.append(SPECIAL_SYMBOLS);
						fileWriter.append(Objects.isNull(val) ? BLANK_STRING : val.toString());
					} else {
						fileWriter.append(Objects.isNull(val) ? BLANK_STRING : val.toString());
					}
					fileWriter.append(COMMA_DELIMITER);
				}
				fileWriter.append(NEW_LINE_SEPARATOR);
			}
			return f;
		} catch (Exception e) {
			logger.error("export data is error,msg is {}", e);
			throw new RuntimeException("export data is error,msg is " + e.getMessage());
		} finally {
			try {
				fileWriter.flush();
				fileWriter.close();
			} catch (IOException e) {
				logger.error("close stream is error,msg is {}", e);
			}

		}

	}

	protected String listToString(List<String> exportName) {
		return Joiner.on(",").join(exportName);
	}

 csv注释自定义(可根据自身需求进行导出数据时的限制):

/**
 * csv注解定义
 */
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CsvField {
	/**
	 * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.
	 * name”)
	 */
	String value() default "";

	/**
	 * 标题
	 */
	String title();

	/**
	 * 必输项(0:非必输;1:必输)
	 */
	int required() default 1;

	/**
	 * 是否加含特殊符号(主要针对导出数据出现科学计数法)
	 */
	boolean isSpecial() default false;
}

测试类:


class Test {
	@CsvField(title = "测试a")
	String a;
	@CsvField(title = "测试b", isSpecial = true)
	Integer b;
	@CsvField(value = "test1.c", title = "测试类Test1")
	Test1 test1;

	public Test1 getTest1() {
		return test1;
	}

	public void setTest1(Test1 test1) {
		this.test1 = test1;
	}

	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}

	public Integer getB() {
		return b;
	}

	public void setB(Integer b) {
		this.b = b;
	}

	public Test(String a, Integer b) {
		super();
		this.a = a;
		this.b = b;
	}

	public Test(String a, Integer b, Test1 test1) {
		super();
		this.a = a;
		this.b = b;
		this.test1 = test1;
	}

	@Override
	public String toString() {
		return "Test [a=" + a + ", b=" + b + "]";
	}

}

class Test1 {
	@CsvField(title = "测试c")
	String c;

	public String getC() {
		return c;
	}

	public void setC(String c) {
		this.c = c;
	}

	public Test1(String c) {
		super();
		this.c = c;
	}

	@Override
	public String toString() {
		return "Test1 [c=" + c + "]";
	}

}

测试使用:


	public static void main(String[] args) {
		List<Test> list = Lists.newArrayList(new Test("zhang", 1, new Test1("c1")),
				new Test("wang", 2, new Test1("c1")));
		ExportCsvUtils<Test> csvUtils = new ExportCsvUtils<Test>();
		File file = csvUtils.createCsvFile("测试导出", list);
		System.err.println(file);
	}

 测试结果(print的是file的文件路径,直接在我的电脑打开就行):

基于注解的方式实现数据导出不可置否的要用到反射,每次用到java反射时都需要慎重考虑是否会影响性能,在实际开发中有些常用数据会频繁被下载,即使加上缓存等一些提高性能手段,也会增加开发过程,效率比较低;同时该方式限制了所需导出数据源的自由(即如果Test1增加属性d被导出,Test也需要增加相应Dto属性d比较繁琐).因此,需要考虑其他可行性方式.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值