Source: blog.csdn.net/qq_35387940/article/details/129062470
As in the title, this gadget does not limit which table you are looking up and what type you are using. I just swipe the shuttle and give you a good meal. I know, this is what many people have thought about, at least I have received a lot of people asking me this similar question. I also told them, but they just don't do it, it's really very simple.
What if you don't do it? I'll do it. Let's not talk too much.
text
The gameplay is very simple. The effect to be achieved:
The class is undefined, User? Student? District? Not sure.
However, the functions we encapsulate must be sufficient to support different classes. We automatically read and traverse the list, and then export the generated file.
What is the core idea?
In fact, we still use the essence of the content format of the csv file, look at these two pictures:
We want to achieve a universal class export excel
What is the idea:
① We take out the classes in the set list of uncertain classes.
Reflexively, take out the attribute name inside, and do the splicing of the title name of the first row of the table.
② Splicing content
Because the class is uncertain, then we use reflection to throw all the field attributes of the class as keys into the map, and at the same time throw the value into the value.
In this way, when we stitch the content, we only need to traverse the stitching according to the map.
Recommend an open source and free Spring Boot most complete tutorial:
https://github.com/dyc87112/SpringBoot-Learning
1. Dependence
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.69</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
2. I have encapsulated the core tool classes and functions
MyCsvFileUtil.java
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author JCccc
* @Remark 是我
*/
@Slf4j
public class MyCsvFileUtil {
public static final String FILE_SUFFIX = ".csv";
public static final String CSV_DELIMITER = ",";
public static final String CSV_TAIL = "\r\n";
protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS";
/**
* 将字符串转成csv文件
*/
public static void createCsvFile(String savePath, String contextStr) throws IOException {
File file = new File(savePath);
//创建文件
file.createNewFile();
//创建文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(file);
//将指定字节写入此文件输出流
fileOutputStream.write(contextStr.getBytes("gbk"));
fileOutputStream.flush();
fileOutputStream.close();
}
/**
* 写文件
*
* @param fileName
* @param content
*/
public static void writeFile(String fileName, String content) {
FileOutputStream fos = null;
OutputStreamWriter writer = null;
try {
fos = new FileOutputStream(fileName, true);
writer = new OutputStreamWriter(fos, "GBK");
writer.write(content);
writer.flush();
} catch (Exception e) {
log.error("写文件异常|{}", e);
} finally {
if (fos != null) {
IOUtils.closeQuietly(fos);
}
if (writer != null) {
IOUtils.closeQuietly(writer);
}
}
}
/**
* 构建文件名称
* @param dataList
* @return
*/
public static String buildCsvFileFileName(List dataList) {
return dataList.get(0).getClass().getSimpleName() + new SimpleDateFormat(DATE_STR_FILE_NAME).format(new Date()) + FILE_SUFFIX;
}
/**
* 构建excel 标题行名
* @param dataList
* @return
*/
public static String buildCsvFileTableNames(List dataList) {
Map<String, Object> map = toMap(dataList.get(0));
StringBuilder tableNames = new StringBuilder();
for (String key : map.keySet()) {
tableNames.append(key).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
}
/**
* 构建excel内容
* @param dataLists
* @return
*/
public static String buildCsvFileBodyMap(List dataLists) {
//不管你传什么玩意,我都给你反射一手,搞成Map
List<Map<String, Object>> mapList = new ArrayList<>();
for (Object o : dataLists) {
mapList.add(toMap(o));
}
//然后利用csv格式,对着map嘎嘎一顿拼接数据
StringBuilder lineBuilder = new StringBuilder();
for (Map<String, Object> rowData : mapList) {
for (String key : rowData.keySet()) {
Object value = rowData.get(key);
if (Objects.nonNull(value)) {
lineBuilder.append(value).append(MyCsvFileUtil.CSV_DELIMITER);
} else {
lineBuilder.append("--").append(MyCsvFileUtil.CSV_DELIMITER);
}
}
lineBuilder.append(MyCsvFileUtil.CSV_TAIL);
}
return lineBuilder.toString();
}
/**
* 类转map
* @param entity
* @param <T>
* @return
*/
public static<T> Map<String, Object> toMap(T entity){
Class<? extends Object> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, Object> map = new HashMap<>(fields.length);
for(Field field:fields){
try {
if(!"serialVersionUID".equals(field.getName())){
String methodName = "get"+field.getName().substring(0, 1).toUpperCase()+field.getName().substring(1);
Method method = bean.getDeclaredMethod(methodName);
Object fieldValue = method.invoke(entity);
map.put(field.getName(),fieldValue);
}
} catch (Exception e) {
log.warn("toMap() Exception={}",e.getMessage());
}
}
return map;
}
}
Code attention points (various small packages):
① class to map
② Reflection to map, take the field attribute name and stitch the title
③ For list<不确定类>
conversion list<map>
, and then splicing excel content
Test code:
@RequestMapping("/createCsvFileJcTest")
public void createCsvFileJcTest() {
//类不确定 随便怎么传都行
List<District> districts = districtService.queryByParentCodes(Arrays.asList("110100"));
//存放地址&文件名
String fileName = "D:\\mycsv\\"+MyCsvFileUtil.buildCsvFileFileName(districts);
//创建表格行标题
String tableNames = MyCsvFileUtil.buildCsvFileTableNames(districts);
//创建文件
MyCsvFileUtil.writeFile(fileName, tableNames);
//写入数据
String contentBody = MyCsvFileUtil.buildCsvFileBodyMap(districts);
//调用方法生成
MyCsvFileUtil.writeFile(fileName, contentBody);
}
Take a look at the effect:
Exported excel file content:
Next, change the class to play:
Then export to see the effect:
You can see that the data export is also OK:
That’s right, it’s as simple as that, and of course it’s a throwback. I hope that after reading this article, you can learn from these reflection function methods and do more fun encapsulation, such as adding some custom annotation analysis, such as adding Some front and rear interceptor extensions and so on.
We have created a high-quality technical exchange group. When you are with excellent people, you will become excellent yourself. Hurry up and click to join the group and enjoy the joy of growing together.
expand
The header exported in the above example is the attribute name. If the formal export usually requires a custom header name, we can use custom annotations to do it here.
JcExcelName.java
/**
* @Author : JCccc
* @CreateTime : 2020/5/14
* @Description :
**/
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JcExcelName {
String name() default "";
}
Then in the class that you want to export, add the name you want to understand, and take the attribute name if you don’t add it:
Write another one casually, the new reflection analysis takes the field attribute annotation value function:
public static <T> List<String> resolveExcelTableName(T entity) {
List<String> tableNamesList = new ArrayList<>();
Class<? extends Object> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, Object> map = new HashMap<>(fields.length);
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String tableTitleName = field.getName();
JcExcelName myFieldAnn = field.getAnnotation(JcExcelName.class);
String annName = myFieldAnn.name();
if (StringUtils.hasLength(annName)) {
tableTitleName = annName;
}
tableNamesList.add(tableTitleName);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return tableNamesList;
}
Then splice the table title name format according to the parsed annotation value column name:
public static String buildCsvFileTableNamesNew(List<String> dataList) {
StringBuilder tableNames = new StringBuilder();
for (String name : dataList) {
tableNames.append(name).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
}
Test to see the effect:
public static void main(String[] args) {
User user = new User();
List<String> nameList = MapUtils.resolveExcelTableName(user);
System.out.println(nameList.toString());
String tableNames = buildCsvFileTableNamesNew(nameList);
System.out.println(tableNames);
}
The effect rattles well:
Then backhanded it into the usage example of our previous article:
String tableNames = MyCsvFileUtil.buildCsvFileTableNamesNew( MyCsvFileUtil.resolveExcelTableName(dataList.get(0)));
Execute the sample interface to see the effect:
The file came out:
Open it to see the effect:
Alright, here we go, it's perfect.
------
We have created a high-quality technical exchange group. When you are with excellent people, you will become excellent yourself. Hurry up and click to join the group and enjoy the joy of growing together. In addition, if you want to change jobs recently, I spent 2 weeks a year ago collecting a wave of face-to-face experience from big factories. If you plan to change jobs after the festival, you can click here to claim it !
recommended reading
Alibaba cloud disk major adjustment, began to clean up the external link sharing
Java's 8 asynchronous implementation methods make performance explode~
Summary of several outsourcing companies with the highest wages at present! (2023 latest version)
··································
Hello, I am DD, a programmer. I have been developing a veteran driver for 10 years, MVP of Alibaba Cloud, TVP of Tencent Cloud. From general development to architect to partner. Along the way, my deepest feeling is that we must keep learning and pay attention to the frontier. As long as you can persevere, think more, complain less, and work hard, it will be easy to overtake on corners! So don't ask me if it's too late to do what I do now. If you are optimistic about something, you must persevere to see hope, not to persevere only when you see hope. Believe me, as long as you stick to it, you will be better than now! If you have no direction yet, you can follow me first, and I will often share some cutting-edge information here to help you accumulate capital for cornering and overtaking.