Java利用EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出實(shí)現(xiàn)過程
前言
excel文件導(dǎo)入及導(dǎo)出,是日常開發(fā)中經(jīng)常遇到的需求。本次筆者以EasyExcel為例,針對(duì)在項(xiàng)目中遇到的動(dòng)態(tài)表頭解析及導(dǎo)出的場(chǎng)景,詳細(xì)介紹具體的代碼實(shí)現(xiàn)過程。
參考地址
https://github.com/alibaba/easyexcel
前端下載
const download = () => { axios({ method: 'GET', url: config.http.baseUrl + '/templateDownload', responseType: 'blob', }) .then(function (res) { const content = res.data const blob = new Blob([content], { type: "application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }) const downloadElement = document.createElement("a"); const href = window.URL.createObjectURL(blob); downloadElement.href = href; downloadElement.download = decodeURI(res.headers['filename']); document.body.appendChild(downloadElement); downloadElement.click(); document.body.removeChild(downloadElement); // 下載完成移除元素 window.URL.revokeObjectURL(href); // 釋放掉blob對(duì)象 }) }
模板下載
excel文件導(dǎo)入功能,常常需要進(jìn)行模板下載,在springboot項(xiàng)目中,程序是以jar包的形式運(yùn)行的,所以有很多小伙伴常常
遇到在本地開發(fā)中能夠?qū)崿F(xiàn)下載功能,但部署到服務(wù)器的時(shí)候,找不到模板文件的問題。
@Override public void templateDownload(HttpServletResponse response, HttpServletRequest request) { //獲取要下載的模板名稱 String fileName = "批量導(dǎo)入模板.xlsx"; //獲取文件下載路徑 String filePath = "/template/template.xlsx"; TemplateDownloadUtil.download(response, request, fileName, filePath); }
import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ClassPathResource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; /** * 模板文件下載工具類 * @author * @date 2021/05/20 9:20 */ @Slf4j public class TemplateDownloadUtil { public static void download(HttpServletResponse response, HttpServletRequest request,String fileName,String filePath){ try { response.setContentType("application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 這里URLEncoder.encode可以防止中文亂碼 當(dāng)然和easyexcel沒有關(guān)系 response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setHeader("filename", URLEncoder.encode(fileName, "UTF-8")); response.setHeader("Access-Control-Expose-Headers", "filename,Content-Disposition"); //獲取文件的路徑,此方式本地開發(fā)可以運(yùn)行,服務(wù)器無法獲取文件 // String filePath = getClass().getResource("/template/template.xlsx").getPath(); // FileInputStream input = new FileInputStream(filePath); //在服務(wù)器中能夠讀取到模板文件 ClassPathResource resource = new ClassPathResource(filePath); InputStream input = resource.getInputStream(); OutputStream out = response.getOutputStream(); byte[] b = new byte[2048]; int len; while ((len = input.read(b)) != -1) { out.write(b, 0, len); } //修正 Excel在“xxx.xlsx”中發(fā)現(xiàn)不可讀取的內(nèi)容。是否恢復(fù)此工作薄的內(nèi)容?如果信任此工作簿的來源,請(qǐng)點(diǎn)擊"是" // response.setHeader("Content-Length", String.valueOf(input.getChannel().size())); input.close(); } catch (Exception e) { log.error("下載模板失敗 :", e); } } }
EasyExcel動(dòng)態(tài)表頭解析
EasyExcel簡(jiǎn)單的讀文件,官網(wǎng)中已經(jīng)有詳細(xì)的說明,本文不再贅述。
本文主要針對(duì)筆者遇到的復(fù)雜表頭及動(dòng)態(tài)表頭進(jìn)行講解。
模板示例
解析
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 發(fā)薪單上傳excel讀取類 * * @author yupf * @description Listener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構(gòu)造方法傳進(jìn)去 */ @Slf4j @Data public class BatchReadListener extends AnalysisEventListener<Map<Integer, String>> { /** * 每隔500條存儲(chǔ)數(shù)據(jù)庫,然后清理list ,方便內(nèi)存回收 */ private static final int BATCH_COUNT = 500; //Excel數(shù)據(jù)緩存結(jié)構(gòu) private List<Map<Integer, Map<Integer, String>>> list = new ArrayList<>(); //Excel表頭(列名)數(shù)據(jù)緩存結(jié)構(gòu) private Map<Integer, String> headTitleMap = new HashMap<>(); /** * 假設(shè)這個(gè)是一個(gè)DAO,當(dāng)然有業(yè)務(wù)邏輯這個(gè)也可以是一個(gè)service。當(dāng)然如果不用存儲(chǔ)這個(gè)對(duì)象沒用。 */ private DbFileBatchService dbFileBatchService; private DbFileContentService dbFileContentService; private FileBatch fileBatch; private int total = 0; /** * 如果使用了spring,請(qǐng)使用這個(gè)構(gòu)造方法。每次創(chuàng)建Listener的時(shí)候需要把spring管理的類傳進(jìn)來 */ public BatchReadListener(DbFileBatchService dbFileBatchService, DbFileContentService dbFileContentService, FileBatch fileBatch) { this.dbFileBatchService = dbFileBatchService; this.dbFileContentService = dbFileContentService; this.fileBatch = fileBatch; } /** * 這個(gè)每一條數(shù)據(jù)解析都會(huì)來調(diào)用 * * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ @Override public void invoke(Map<Integer, String> data, AnalysisContext context) { log.info("解析到一條數(shù)據(jù):{}", JSON.toJSONString(data)); total++; Map<Integer, Map<Integer, String>> map = new HashMap<>(); map.put(context.readRowHolder().getRowIndex(), data); list.add(map); // 達(dá)到BATCH_COUNT了,需要去存儲(chǔ)一次數(shù)據(jù)庫,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內(nèi)存,容易OOM if (list.size() >= BATCH_COUNT) { saveData(); // 存儲(chǔ)完成清理 list list.clear(); } } /** * 所有數(shù)據(jù)解析完成了 都會(huì)來調(diào)用 * * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫 saveData(); log.info("所有數(shù)據(jù)解析完成!"); } /** * 解析表頭數(shù)據(jù) **/ @Override public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { log.info("表頭數(shù)據(jù):{}", JSONObject.toJSONString(headMap)); headTitleMap = headMap; } /** * 加上存儲(chǔ)數(shù)據(jù)庫 */ private void saveData() { log.info("{}條數(shù)據(jù),開始存儲(chǔ)數(shù)據(jù)庫!", list.size()); FileContent fileContent = null; List<FileContent> fileContentList = list.stream().flatMap( integerMap -> integerMap.entrySet().stream().map(entrySet -> { //entrySet.getKey()獲取的是內(nèi)容的RowIndex,實(shí)際的行數(shù)需要根據(jù)表頭數(shù)進(jìn)行處理 Integer rowIndex = entrySet.getKey(); Map<Integer, String> value = entrySet.getValue(); log.info(JSONObject.toJSONString(value)); fileContent = new FileContent(); fileContent.setBatchId(fileBatch.getId()); fileContent.setBatchNo(fileBatch.getBatchNo()); //固定字段入庫 fileContent.setName(value.get(0) != null ? value.get(0).trim() : ""); fileContent.setCertNo(value.get(1) != null ? value.get(1).trim() : ""); fileContent.setRealAmount(value.get(2) != null ? value.get(2).trim() : ""); //所有動(dòng)態(tài)表頭數(shù)據(jù)轉(zhuǎn)為JSON串入庫 fileContent.setFieldsValue(JSONObject.toJSONString(value)); //取實(shí)際的內(nèi)容rowIndex fileContent.setRowNum(rowIndex + 1); fileContent.setCreateTime(LocalDateTime.now()); return xcSalaryFileContent; } )).collect(Collectors.toList()); log.info(JSONObject.toJSONString(fileContentList)); dbFileContentService.saveBatch(fileContentList); log.info("存儲(chǔ)數(shù)據(jù)庫成功!"); } }
BatchReadListener listener = new BatchReadListener(dbFileBatchService, dbFileContentService, fileBatch); try { //注:headRowNumber默認(rèn)為1,現(xiàn)賦值為2,即從第三行開始讀取內(nèi)容 EasyExcel.read(fileInputStream, listener).headRowNumber(2).sheet().doRead(); } catch (Exception e) { log.info("EasyExcel解析文件失敗,{}", e); throw new CustomException("文件解析失敗,請(qǐng)重新上傳"); } //獲取表頭信息進(jìn)行處理 Map<Integer, String> headTitleMap = listener.getHeadTitleMap(); //獲取動(dòng)態(tài)表頭信息 List<String> headList = headTitleMap.keySet().stream().map(key -> { String head = headTitleMap.get(key); log.info(head); return head == null ? "" : head.replace("*", ""); }).collect(Collectors.toList()); //可以對(duì)表頭進(jìn)行入庫保存,方便后續(xù)導(dǎo)出
綜上,動(dòng)態(tài)表頭即可完成解析。
EasyExcel動(dòng)態(tài)表頭導(dǎo)出
導(dǎo)出示例
獲取動(dòng)態(tài)頭
private List<List<String>> getFileHeadList( FileBatch fileBatch) { String head = fileBatch.getFileHead(); List<String> headList = Arrays.asList(head.split(",")); List<List<String>> fileHead = headList.stream().map(item -> concatHead(Lists.newArrayList(item))).collect(Collectors.toList()); fileHead.add(concatHead(Lists.newArrayList("備注"))); return fileHead; }
/** * 填寫須知 * @param headContent * @return */ private List<String> concatHead(List<String> headContent) { String remake = "填寫須知: \n" + "1.系統(tǒng)自動(dòng)識(shí)別Excel表格,表頭必須含有“企業(yè)賬戶號(hào)”、“企業(yè)賬戶名”、“實(shí)發(fā)金額”;\n" + "2.帶 “*” 為必填字段,填寫后才能上傳成功;\n" + "3.若需上傳其他表頭,可自行在“實(shí)發(fā)金額”后添加表頭,表頭最多可添加20個(gè),表頭名稱請(qǐng)控制在8個(gè)字以內(nèi);\n" + "4.填寫的表頭內(nèi)容不可超過30個(gè)字;\n" + "5.實(shí)發(fā)金額支持填寫到2位小數(shù);\n" + "6.每次導(dǎo)入數(shù)據(jù)不超過5000條。\n" + "\n" + "注:請(qǐng)勿刪除填寫須知,刪除后將導(dǎo)致文件上傳失敗\n" + "\n" + "表頭示例:"; headContent.add(0, remake); return headContent; }
獲取數(shù)據(jù)
List<FileContent> fileContentList = dbFileContentService.list( Wrappers.<FileContent>lambdaQuery() .eq(FileContent::getBatchId, fileBatch.getId()) .orderByAsc(FileContent::getRowNum) ); List<List<Object>> contentList = fileContentList.stream().map(fileContent -> { List<Object> rowList = new ArrayList<>(); String fieldsValue = fileContent.getFieldsValue(); JSONObject contentObj = JSONObject.parseObject(fieldsValue); for (int columnIndex = 0 , length = headList.size(); columnIndex < length; columnIndex++) { Object content = contentObj.get(columnIndex); rowList.add(content == null ? "" : content); } rowList.add(fileContent.getCheckMessage()); return rowList; }).collect(Collectors.toList());
單元格格式設(shè)置
import com.alibaba.excel.metadata.data.DataFormatData; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; import java.util.List; /** * 設(shè)置表頭和填充內(nèi)容的樣式 */ public class CellStyleStrategy extends HorizontalCellStyleStrategy { private final WriteCellStyle headWriteCellStyle; private final WriteCellStyle contentWriteCellStyle; /** * 操作列 */ private final List<Integer> columnIndexes; public CellStyleStrategy(List<Integer> columnIndexes,WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) { this.columnIndexes = columnIndexes; this.headWriteCellStyle = headWriteCellStyle; this.contentWriteCellStyle = contentWriteCellStyle; } //設(shè)置頭樣式 @Override protected void setHeadCellStyle( CellWriteHandlerContext context) { // 獲取字體實(shí)例 WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontName("宋體"); //表頭不同處理 if (columnIndexes.get(0).equals(context.getRowIndex())) { headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT); headWriteFont.setFontHeightInPoints((short) 12); headWriteFont.setBold(false); headWriteFont.setFontName("宋體"); }else{ headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); headWriteFont.setFontHeightInPoints((short) 11); headWriteFont.setBold(false); headWriteFont.setFontName("微軟雅黑"); } headWriteCellStyle.setWriteFont(headWriteFont); DataFormatData dataFormatData = new DataFormatData(); dataFormatData.setIndex((short)49); headWriteCellStyle.setDataFormatData(dataFormatData); if (stopProcessing(context)) { return; } WriteCellData<?> cellData = context.getFirstCellData(); WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle()); } //設(shè)置填充數(shù)據(jù)樣式 @Override protected void setContentCellStyle(CellWriteHandlerContext context) { WriteFont contentWriteFont = new WriteFont(); contentWriteFont.setFontName("宋體"); contentWriteFont.setFontHeightInPoints((short) 11); //設(shè)置數(shù)據(jù)填充后的實(shí)線邊框 contentWriteCellStyle.setWriteFont(contentWriteFont); contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); contentWriteCellStyle.setBorderTop(BorderStyle.THIN); contentWriteCellStyle.setBorderRight(BorderStyle.THIN); contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); DataFormatData dataFormatData = new DataFormatData(); dataFormatData.setIndex((short)49); contentWriteCellStyle.setDataFormatData(dataFormatData); contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); WriteCellData<?> cellData = context.getFirstCellData(); WriteCellStyle.merge(contentWriteCellStyle, cellData.getOrCreateStyle()); } }
行高設(shè)置
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy; import org.apache.poi.ss.usermodel.Row; /** * 設(shè)置表頭的自動(dòng)調(diào)整行高策略 */ public class CellRowHeightStyleStrategy extends AbstractRowHeightStyleStrategy { @Override protected void setHeadColumnHeight(Row row, int relativeRowIndex) { //設(shè)置主標(biāo)題行高為17.7 if(relativeRowIndex == 0){ //如果excel需要顯示行高為15,那這里就要設(shè)置為15*20=300 row.setHeight((short) 3240); } } @Override protected void setContentColumnHeight(Row row, int relativeRowIndex) { } }
列寬度自適應(yīng)
如果是簡(jiǎn)單表頭,可以使用EasyExcel中的LongestMatchColumnWidthStyleStrategy()來實(shí)現(xiàn)。
EasyExcel.write(fileName, LongestMatchColumnWidthData.class) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());
如果是復(fù)雜表頭,就需要自己來實(shí)現(xiàn),代碼如下:
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.CellData; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.poi.ss.usermodel.Cell; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author yupf * @description * @date 2022/9/7 18:48 */ @Slf4j public class CellWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>(); @Override protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo()); if (maxColumnWidthMap == null) { maxColumnWidthMap = new HashMap<>(); CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); } if (isHead) { if(relativeRowIndex.intValue() == 1){ Integer length = cell.getStringCellValue().getBytes().length; Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex()); if (maxColumnWidth == null || length > maxColumnWidth) { maxColumnWidthMap.put(cell.getColumnIndex(), length); writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), length * 300); } } }else{ Integer columnWidth = this.dataLength(cellDataList, cell, isHead); if (columnWidth >= 0) { if (columnWidth > 255) { columnWidth = 255; } Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex()); if (maxColumnWidth == null || columnWidth > maxColumnWidth) { maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth); writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256); } } } } private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) { if (isHead) { return cell.getStringCellValue().getBytes().length; } else { CellData cellData = cellDataList.get(0); CellDataTypeEnum type = cellData.getType(); if (type == null) { return -1; } else { switch (type) { case STRING: return cellData.getStringValue().getBytes().length; case BOOLEAN: return cellData.getBooleanValue().toString().getBytes().length; case NUMBER: return cellData.getNumberValue().toString().getBytes().length; default: return -1; } } } } }
寫入文件
EasyExcel.write(response.getOutputStream()) .head(head) .registerWriteHandler(new CellRowHeightStyleStrategy()) //設(shè)置行高的策略 .registerWriteHandler(new CellStyleStrategy(Arrays.asList(0,1),new WriteCellStyle(), new WriteCellStyle())) .registerWriteHandler(new CellWidthStyleStrategy()) .sheet(sheetName) .doWrite(list);
總結(jié)
以上便是EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出的整個(gè)過程。
在使用過程中,筆者的感受是,上手難度很低,很適合新手去做簡(jiǎn)單的表格解析,當(dāng)然,如果你的需求有復(fù)雜的格式,EasyExcel也提供了api,能夠很好的滿足需要。
到此這篇關(guān)于Java利用EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例
- Java使用EasyExcel動(dòng)態(tài)添加自增序號(hào)列
- Java中Easyexcel?實(shí)現(xiàn)批量插入圖片功能
- Java利用EasyExcel實(shí)現(xiàn)合并單元格
- Java使用EasyExcel進(jìn)行單元格合并的問題詳解
- Java?easyExcel的復(fù)雜表頭多級(jí)表頭導(dǎo)入
- Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式
- Java?EasyExcel實(shí)現(xiàn)合并相同內(nèi)容單元格與動(dòng)態(tài)標(biāo)題功能
- Java實(shí)現(xiàn)讀取Excel文件功能(EasyExcel初使用)
相關(guān)文章
Springboot視圖解析器ViewResolver使用實(shí)例
這篇文章主要介紹了Springboot視圖解析器ViewResolver使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04SpringBoot基于AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源動(dòng)態(tài)切換
本文主要介紹了SpringBoot基于AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源動(dòng)態(tài)切換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05springboot實(shí)現(xiàn)excel表格導(dǎo)出幾種常見方法
在日常的開發(fā)中避免不了操作Excel,下面這篇文章主要給大家介紹了關(guān)于springboot實(shí)現(xiàn)excel表格導(dǎo)出的幾種常見方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11eclipse配置tomcat10的詳細(xì)步驟總結(jié)
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著eclipse配置tomcat10的詳細(xì)步驟展開,文中有非常詳細(xì)的介紹及圖文示例,需要的朋友可以參考下2021-06-06Java自帶的Http?Server實(shí)現(xiàn)設(shè)置返回值的類型(content-type)
這篇文章主要介紹了Java自帶的Http?Server實(shí)現(xiàn)設(shè)置返回值的類型(content-type),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題
這篇文章主要介紹了關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識(shí)別的解決
這篇文章主要介紹了IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識(shí)別的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04新手小白看過來學(xué)JAVA必過IO流File字節(jié)流字符流
這篇文章主要介紹了新手小白學(xué)JAVA到IO流File字節(jié)流字符流的重點(diǎn),對(duì)流不清楚的新手同學(xué)快進(jìn)來學(xué)習(xí)吧,大佬也可以進(jìn)來溫故一下2021-08-08