本文没什么比较特别的技术点。硬要说有的话,可能是以下三点,最主要的是抽象
1,抽象
2,反射
3,IO操作
1,新建一个文件生成对象,主要用来取临时文件路径
public class GenteraterRetunData {
private String localFilePath;
public GenteraterRetunData(String localFilePath) {
this.localFilePath = localFilePath;
}
public String getLocalFilePath() {
return localFilePath;
}
public void setLocalFilePath(String localFilePath) {
this.localFilePath = localFilePath;
}
}
2,创建一个txt文件生成的基类接口
import com.xxx.entity.PolicyLeads;
import com.xxx.submit.model.GenteraterRetunData;
import java.util.List;
/**
* Created by dearx on 2019/12/19
*/
public interface TxtBaseGenerater {
GenteraterRetunData generate(List<PolicyLeads> policyLeads, String fileName) throws Exception;
}
3,创建一个txt文件生成类来实现TxtBaseGenerater 基类接口 ,这个类主要用于生成文件。文件生成路径,fileDist我采用注入的方式。PolicyLeads是一个实体类,就不赘述了
import com.xxx.entity.PolicyLeads;
import com.xxx.submit.model.GenteraterRetunData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by dearx on 2019/12/19
*/
public abstract class TxtWorkBookGenerater implements TxtBaseGenerater {
protected Logger logger = LoggerFactory.getLogger(TxtWorkBookGenerater.class);
@Value("${local.file.path}")
public String fileDist;
/*获取txt表头的map,map中的key如果是policy表的字段名,可直接获取字段值。如果不是字段名,可以再子类继承后自定义*/
abstract public Map<String, String> getHearMap();
/*获取txt文件的内容*/
abstract public String getContent(PolicyLeads policyLeads,String headKey);
/*获取txt文件每行各个字段隔开的符号标识*/
abstract public String getSplitSymbol();
@Override
public GenteraterRetunData generate(List<PolicyLeads> policyLeadsList, String fileName) throws Exception {
/*拼接表头*/
StringBuffer hearStr=new StringBuffer();
getHearMap().forEach((k, v) -> {
if("".equals(hearStr.toString())){
hearStr.append(v);
}else{
hearStr.append(getSplitSymbol()+v);
}
});
logger.info("txt文件表头为 【{}】",hearStr.toString());
/*创建一个文件,File.separator 是为了适应windows和linux不同的文件夹分隔符*/
File file = new File(fileDist + File.separator + fileName+".txt");
logger.info("txt文件【{}】创建成功",file.getAbsolutePath());
/*给文件填充内容*/
exportTxt(file, policyLeadsList, hearStr.toString());
logger.info("txt文件【{}】生成成功",file.getAbsolutePath());
/*返回文件路径*/
return new GenteraterRetunData(file.getAbsolutePath());
}
/**
* 导出
*
* @param file Txt文件(路径+文件名),Txt文件不存在会自动创建
* @param heads 表头
* @return
* @author [email protected]
* @create 2016-4-27 上午9:49:49
*/
public void exportTxt(File file, List<PolicyLeads> policyLeadsList, String heads) {
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
List<String> contenList = new ArrayList<>();
/*这个for循环主要用来根据表头拼接内容*/
for (PolicyLeads policyLeads : policyLeadsList) {
/*每行的内容*/
StringBuffer content = new StringBuffer();
/*遍历静态表头的map*/
getHearMap().forEach((headKey, headkValue) -> {
Boolean hashead = false;
/*遍历此次导出的表头*/
for (String hearName : heads.split(getSplitSymbol())) {
/*如果静态表头中包含此次导出的表头,退出循环,使hashead=true*/
if (headkValue .equals(hearName) ) {
hashead = true;
break;
}
}
/*如果hashead=true,表示需要把这个字段加入到导出文件中*/
if (hashead) {
/*获取这个字段的值*/
String data = getContent(policyLeads,headKey);
/*将字段的值拼接到这一行*/
content.append("".equals(content.toString()) ? data : getSplitSymbol() + data);
}
});
contenList.add(content.toString());
}
if (exportTxtByOS(out, contenList, heads)) {
logger.info("文件【{}】文件流写入成功", file.getName(), file.getParent());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
logger.info(e.getStackTrace().toString());
}
}
/**
* 导出
* @param out 输出流
* @param dataList 内容数据
* @param heads 表头
*/
public static boolean exportTxtByOS(OutputStream out, List<String> dataList, String heads) {
boolean isSucess = false;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
osw = new OutputStreamWriter(out);
bw = new BufferedWriter(osw);
//循环表头
if (heads != null && !heads.equals("")) {
bw.append(heads).append("\r");
}
//循环数据
if (dataList != null && !dataList.isEmpty()) {
for (String data : dataList) {
bw.append(data).append("\r");
}
}
isSucess = true;
} catch (Exception e) {
e.printStackTrace();
isSucess = false;
} finally {
if (bw != null) {
try {
bw.close();
bw = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (osw != null) {
try {
osw.close();
osw = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
out = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return isSucess;
}
}
4,创建一个文件模板类来继承文件生成类。如果有多个不同 的模板,只需要多创建几个其他的模板类,在子类修改父类的抽象方法即可
import com.xxx.common.utils.MethodUtil;
import com.xxx.common.utils.StringUtil;
import com.xxx.entity.PolicyLeads;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Created by dearx on 2019/12/19
*/
@Component("SampleTxt")
public class SampleTxtGenerater extends TxtWorkBookGenerater {
protected Logger logger = LoggerFactory.getLogger(SampleTxtGenerater.class);
@Override
public Map<String, String> getHearMap() {
/*LinkedHashMap便于按顺序写入表头*/
Map<String, String> hearMap = new LinkedHashMap<>();
hearMap.put("name", "姓名");
hearMap.put("age", "年龄");
hearMap.put("mobile", "手机号");
hearMap.put("source", "数据类型");
return hearMap;
}
@Override
public String getContent(PolicyLeads policyLeads, String headKey) {
String data = "";
try {
if ("source".equals(headKey)) {
/*做了特别判断的,如source,代表是自定义的字段,通过各字段值组合拼接而成*/
String dataSourceName = policyLeads.getCompanyDataSource() != null ? policyLeads.getCompanyDataSource().getDataSourceName() : "";
String dataType = policyLeads.getDataPipe().getDataType().getTypeName();
data = dataSourceName + "-" + dataType;
} else {
/*没有做特别判断的表示该字段是policyleads实体中的字段,通过反射获取字段值*/
data = StringUtil.safeToString(MethodUtil.getGetMethod(policyLeads, headKey), "");
}
return data;
} catch (Exception e) {
e.printStackTrace();
logger.info(e.getStackTrace().toString());
logger.info(e.getMessage().toString());
return "";
}
}
@Override
public String getSplitSymbol() {
return ",";
}
}
5,以上代码用到的工具类,主要是反射的工具类。
import java.lang.reflect.Method;
import java.math.BigDecimal;
public class MethodUtil {
/**
* 根据属性,获取get方法
* @param ob 对象
* @param name 属性名
* @return
* @throws Exception
*/
public static Object getGetMethod(Object ob , String name)throws Exception{
Method[] m = ob.getClass().getMethods();
for(int i = 0;i < m.length;i++){
if(("get"+name).toLowerCase().equals(m[i].getName().toLowerCase())){
return m[i].invoke(ob);
}
}
return null;
}
/**
* 根据属性,拿到set方法,并把值set到对象中
* @param obj 对象
* @param clazz 对象的class
* @param typeClass
* @param value
*/
public static void setValue(Object obj,Class<?> clazz,String filedName,Class<?> typeClass,Object value){
filedName = removeLine(filedName);
String methodName = "set" + filedName.substring(0,1).toUpperCase()+filedName.substring(1);
try{
Method method = clazz.getDeclaredMethod(methodName, new Class[]{typeClass});
method.invoke(obj, new Object[]{getClassTypeValue(typeClass, value)});
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* 通过class类型获取获取对应类型的值
* @param typeClass class类型
* @param value 值
* @return Object
*/
private static Object getClassTypeValue(Class<?> typeClass, Object value){
if(typeClass == int.class || value instanceof Integer){
if(null == value){
return 0;
}
return value;
}else if(typeClass == short.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == byte.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == double.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == long.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == String.class){
if(null == value){
return "";
}
return value;
}else if(typeClass == boolean.class){
if(null == value){
return true;
}
return value;
}else if(typeClass == BigDecimal.class){
if(null == value){
return new BigDecimal(0);
}
return new BigDecimal(value+"");
}else {
return typeClass.cast(value);
}
}
/**
* 处理字符串 如: abc_dex ---> abcDex
* @param str
* @return
*/
public static String removeLine(String str){
if(null != str && str.contains("_")){
int i = str.indexOf("_");
char ch = str.charAt(i+1);
char newCh = (ch+"").substring(0, 1).toUpperCase().toCharArray()[0];
String newStr = str.replace(str.charAt(i+1), newCh);
String newStr2 = newStr.replace("_", "");
return newStr2;
}
return str;
}
}
6,调用。
6.1,spring的been获取方法
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Created by dearx on 2019/12/19.
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
// 获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
// 通过name获取Bean
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
// 通过class获取Bean
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
// 通过name以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
6.2,调用
/*SampleTxt是bean的名称,就当做是模板code,就是上面的SampleTxtGenerater类通过@Component注解注入
*SampleTxt可以自定义,比如A模板,就可以叫ATxt,B模板可以交BTxt。
*通过模板code获取到相应的文件生成类/
TxtBaseGenerater txtgenerater = (TxtBaseGenerater) SpringUtils.getBean("SampleTxt");
/* 调用生成方法,第一个参数传数据list,第二个参数传文件名称*/
txtgenerater.generate(entityList, filename);
完结------