怎么做新聞網(wǎng)站網(wǎng)站友情鏈接購買
雖然最之前是在其他地方看到的,但最終因緣巧合下找到了原文,還是尊重一下原作者。
參考引用了這位佬的博客,確實方便使用。
https://blog.csdn.net/qq_45914616/article/details/137200688?spm=1001.2014.3001.5502
這是一個基于Easyexcel通過注解的方式,
在巨人的肩膀上,對相關(guān)方法進行了一定的調(diào)整和說明注釋,方便使用與定制調(diào)整為自己所需要的內(nèi)容格式。
能做到的事情有:
- 通過注解實現(xiàn)自定義字典值映射,滿足數(shù)字、英文等符合格式的導出字典映射,導入也支持。
- 支持字典值映射的單選或多選模式
- 支持對滿足某些條件的內(nèi)容,在輸出時添加一些樣式,比如字體顏色。
以下正文:
1.定義了一個枚舉類
/*** @Description: 符號枚舉類* @author: CloverAn* @email: * @created: 2023/02/27 21:01*/
public class SymbolConstant {private SymbolConstant() {}public static final String SPE1 = ",";/*** 豎線*/public static final String SPE9 = "\\|";}
多余出來的已經(jīng)做了刪除,這兩個使用了所以保留,各位可以自行替換修改。
2.添加自定義注解
import com.data.utils.constant.SymbolConstant;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Description: 枚舉數(shù)值的自定義注解* @author: CloverAn* @email:* @created: 2024/06/25 15:57*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumFiledConvert {/*** 枚舉映射map key-value,key-value,key-value,key-value* <p>* key|value,key|value* <p>* 注意,這里的key和value都是英文字符串,所以實際上他可以是數(shù)字,也可以是英文,也可以是否個字符串* 例如:0|滿勤,0-1|特殊,Y|是,n|error** @return*/String enumMap() default "未匹配到映射字典";/*** 枚舉類導入、導出在excel中的分隔符號** @return*/String spiteChar() default SymbolConstant.SPE1;/*** 枚舉類導入導出字典分隔符*/String dictChar() default SymbolConstant.SPE9;/*** 單選 or 多選* <p>* 即多個枚舉映射,都會比對輸出,例如** @return* @EnumFiledConvert(enumMap = "1-籃球,2-足球,3-乒乓球,4-羽毛球",single = false)* <p>* 字段值是"1,2,3,4"* 則最終輸出的是"籃球,足球,乒乓球,羽毛球"* <p>* 字典值是"1,2"* 則最終輸出的是"籃球,足球"*/boolean single() default true;/*** 條件樣式,對滿足條件的字符串,設(shè)置紅色字體*/String fontColorMap() default "";
}
1.這里將原作者的直接使用符號,以及符合使用的 逗號和橫杠 調(diào)整了以下,因為個人有這一塊的需求,最終使用的是 逗號和豎線。
2.修改了默認值,添加了部分注釋,更通俗易懂。
3.在作者原有的基礎(chǔ)上,增加了字體顏色的注解屬性,用于接收指定的判斷條件和顏色要求
3.重寫EasyExcel轉(zhuǎn)換器接口,對excel讀和寫方法都進行自定義
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.data.keepriskexport.utils.constant.SymbolConstant;
import org.springframework.util.StringUtils;import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** 導入導出針對枚舉類型的轉(zhuǎn)換器** @author CloverAn*/
public class EasyExcelConvert implements Converter<Object> {/*** 枚舉列表*/private Map<String, String> enumMap = new HashMap<>();/*** 條件列表*/private Map<String, String> fontColorMap = new HashMap<>();/*** excel轉(zhuǎn)化后的類型** @return*/@Overridepublic Class<?> supportJavaTypeKey() {return Object.class;}/*** excel中的數(shù)據(jù)類型,統(tǒng)一設(shè)置字符串** @return*/@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}/*** 導入轉(zhuǎn)換** @param cellData 當前單元格對象* @param contentProperty 當前單元格屬性* @param globalConfiguration* @return* @throws Exception*/@Overridepublic Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {String cellMsg = cellData.getStringValue();Field field = contentProperty.getField();EnumFiledConvert enumFiledConvert = field.getAnnotation(EnumFiledConvert.class);if (enumFiledConvert == null) {return null;}String enumStr = enumFiledConvert.enumMap();// 解析枚舉映射關(guān)系getEnumMap(enumStr, true);// 是否為單選boolean single = enumFiledConvert.single();// 如果是單選,默認Java屬性為integerif (single) {String res = enumMap.get(cellMsg);return StringUtils.hasText(res) ? Integer.valueOf(res) : null;} else {// 多選分隔符String spiteChar = enumFiledConvert.spiteChar();// 多選枚舉,默認Java屬性為字符串,格式為 key1,key2,key3List<String> strStr = Arrays.asList(cellMsg.split(spiteChar)).stream().map(s -> String.valueOf(enumMap.get(s))).collect(Collectors.toList());String str = String.join(spiteChar, strStr);return str;}}/*** 導出轉(zhuǎn)化** @param value 當前值* @param contentProperty 當前單元格屬性* @param globalConfiguration* @return* @throws Exception*/@Overridepublic WriteCellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {Field field = contentProperty.getField();EnumFiledConvert enumFiledConvert = field.getAnnotation(EnumFiledConvert.class);if (enumFiledConvert == null) {return new WriteCellData();}// 解析枚舉字符串String enumStr = enumFiledConvert.enumMap();getEnumMap(enumStr, false);// 是否為單選boolean single = enumFiledConvert.single();//條件樣式String conditions = enumFiledConvert.fontColorMap();//解析條件樣式getConditionsMap(conditions);// 如果是單選,默認Java屬性為integerif (single) {//輸出內(nèi)容原始值String valueOf = String.valueOf(value);//輸出內(nèi)容轉(zhuǎn)換,字典值String orDefault = enumMap.getOrDefault(valueOf, "");//創(chuàng)建輸出內(nèi)容WriteCellData writeCellData = new WriteCellData(orDefault);setWriteCellStyle(writeCellData, orDefault);return writeCellData;} else {// 多選分隔符String spiteChar = enumFiledConvert.spiteChar();// 多選枚舉,默認Java屬性為字符串,格式為 key1,key2,key3List<String> strStr = Arrays.asList(String.valueOf(value).split(spiteChar)).stream().map(s -> String.valueOf(enumMap.get(s))).collect(Collectors.toList());String str = String.join(spiteChar, strStr);WriteCellData writeCellData = new WriteCellData(str);return writeCellData;}}/*** 根據(jù)注解配置的枚舉映射字符串進行解析到map中** @param mapStr* @param readOrWrite 讀excel 、 寫excel*/private void getEnumMap(String mapStr, boolean readOrWrite) {String[] enumS = mapStr.split(SymbolConstant.SPE1);for (String anEnum : enumS) {String[] data = anEnum.split(SymbolConstant.SPE9);if (readOrWrite) {// 讀excel excel中的數(shù)據(jù)都是value,轉(zhuǎn)換成keyenumMap.put(data[1], data[0]);} else {// 寫excel Java中的數(shù)據(jù)都是key,轉(zhuǎn)換成valueenumMap.put(data[0], data[1]);}}}/*** 根據(jù)注解配置的枚舉映射字符串進行解析到map中* 只有寫出的時候生效*/private void getConditionsMap(String conditions) {if (conditions != null && !conditions.isEmpty()) {String[] conditionsMaps = conditions.split(SymbolConstant.SPE1);for (String condition : conditionsMaps) {String[] data = condition.split(SymbolConstant.SPE9);// 寫excel Java中的數(shù)據(jù)都是key,轉(zhuǎn)換成valuefontColorMap.put(data[0], data[1]);}}}/**** 取到什么顏色,填充什么顏色,沒有則不填充。** @param writeCellData*/private void setWriteCellStyle(WriteCellData writeCellData, String orDefault) {//輸出樣式轉(zhuǎn)換,顏色值,默認黑色short orDefaultStyle = 0;//條件,滿足條件則修改內(nèi)容,可以疊加更多的條件,只要符合k-v規(guī)則,即比較k,填充v//因為這里是中文k 和 顏色索引,這里比較的就是中文,如果能保障k不重復(fù),則k可以是數(shù)字、字符等,對應(yīng)的v也就可以是數(shù)字、字符等,//這樣就可以按照需求對單元格式進行一定的操作編輯//需要注意的是,這里用的轉(zhuǎn)換之后的輸出值進行的比較,有需要使用原始值的可以自行微調(diào)一下if (fontColorMap != null && fontColorMap.containsKey(orDefault)) {WriteFont writeFont = new WriteFont();WriteCellStyle writeCellStyle = new WriteCellStyle();orDefaultStyle = Short.parseShort(fontColorMap.getOrDefault(orDefault, ""));writeFont.setColor(orDefaultStyle);writeCellStyle.setWriteFont(writeFont);writeCellData.setWriteCellStyle(writeCellStyle);}}
}
1.這里面只是修改了部分直接引用字符的地方,將其使用字典值代替。
2.在作者原有的基礎(chǔ)上,增加和調(diào)整了滿足條件后,對字體顏色標記的功能。相關(guān)樣式可以自己做調(diào)整,比如添加背景色等。
邏輯也跟簡單,就是拿到轉(zhuǎn)換之后的值,通過這個值,與注解傳遞的值進行比較,滿足條件則添加樣式。
因為添加樣式只存在于導出的時候,所以只需要關(guān)注導出的方法體即可。多選的我暫時沒有場景,沒有添加,實際邏輯是一樣的。
4.測試實體類(因為我懶。不是,要尊重作者! )
import com.alibaba.excel.annotation.ExcelProperty;
import com.example.test.excel.EasyExcelConvert;
import com.example.test.excel.EnumFiledConvert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @Author 996* @Date 2024/3/20*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExcelDto {@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "性別",converter = EasyExcelConvert.class)@EnumFiledConvert(enumMap = "0|保密,1|男,2|女")private Integer sex;@ExcelProperty(value = "愛好",converter = EasyExcelConvert.class)@EnumFiledConvert(enumMap = "1|籃球,2|足球,3|乒乓球,4|羽毛球",, fontColorMap = "籃球|2",single = false)private String hobbies;
}
使用時,只需要 2個步驟 ,(1)在實體類上添加自定義注解,(2)在原生的 @ExcelProperty 注解中,指定自定義解析Convert。
這時導出,對應(yīng)字段列的值,就會被替換成對應(yīng)的數(shù)據(jù)項。
需要注意:
1.跟原作者不一樣,這里多個字典值之間使用的還是逗號,但是k-v的映射關(guān)系使用的是豎線。
2.這里的k-v不一定要符合現(xiàn)在的這種數(shù)字和中文的組合,只需要保證k-v分別為字符串,且內(nèi)容不含逗號豎線即可。比如其他字典映射:Y|是 ??? Y-1|特例1 ??? N|bushi ??? 是|正確的答案 ??? 只要符合對應(yīng)的格式即可,更加靈活。
3.可以修改自定義注解中的符號,以調(diào)整對應(yīng)的格式,但是需要注意,不是所有的都可以直接兼容,需要進行一定的轉(zhuǎn)義,這一點肯定難不倒聰明的你。
4.注意第三個屬性的注解,多加了fontColorMap,前面的是輸出的值,可以對應(yīng)enumMap里面的字典值轉(zhuǎn)換,后面的是顏色索引,這里的2標識為紅色,可以看org.apache.poi.ss.usermodel.IndexedColors; 中的IndexedColors.RED.getIndex()枚舉,顏色索引很全。
基于以上字體顏色修改的邏輯,我們能夠拿到所有輸出的值的內(nèi)容,包括原始值,那么我們就可以通過一系列的條件,來實現(xiàn)我們對某些特定內(nèi)容的數(shù)據(jù)進行樣式調(diào)整,包括但不限于字體調(diào)整、字體顏色調(diào)整、字體顏色調(diào)整、數(shù)據(jù)值調(diào)整、單元格背景顏色調(diào)整、單元格邊框調(diào)整等等等等。
5.輸出
這個大家都會,這里摘一部分代碼套用
//數(shù)據(jù)集合,這里是用的實體類
List<ClockCount> countList = new ArrayList<>();ExcelWriter excelWriterCount = EasyExcel.write("文件完整路徑,含后綴").build();
WriteSheet writeSheetCount = EasyExcel.writerSheet("表格中sheet名稱").build();//我這是用實體類進行的文件輸出
writeSheetCount.setClazz(ClockCount.class);
//寫出數(shù)據(jù)
excelWriterCount.write(countList , writeSheetCount);
excelWriterCount.finish();
執(zhí)行導出即可完成。通過循環(huán),或者針對同一文件名,相同sheet名稱或者不相同名稱,可以實現(xiàn)對同一表格相同sheet頁或多個sheet頁數(shù)據(jù)寫出,這個就和原生一致了。