使用EasyExcel實現通用導出功能

来源:https://www.cnblogs.com/HotBoom/archive/2023/05/19/17415836.html
-Advertisement-
Play Games

## 一、環境介紹 * JDK 1.8+ * EasyExcel 2.2.7 ## 二、功能實現 此功能可以實現根據傳入自定義的 導出實體類或Map 進行excel文件導出。若根據Map導出,導出列的順序可以自定義。 **話不多說,直接看代碼** ### 導出實體類 點擊查看代碼 ``` impor ...


一、環境介紹

  • JDK 1.8+
  • EasyExcel 2.2.7

二、功能實現

此功能可以實現根據傳入自定義的 導出實體類或Map 進行excel文件導出。若根據Map導出,導出列的順序可以自定義。
話不多說,直接看代碼

導出實體類

點擊查看代碼
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.*;
import com.*.core.tool.utils.DateUtil;
import lombok.Data;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

import java.time.LocalDateTime;

/**
 * excel導出對象實體類
 *
 * @author 熱得快炸了
 * @since 2023-4-3
 */
@Data
@HeadStyle(
	borderBottom = BorderStyle.THIN,
	borderLeft = BorderStyle.THIN,
	borderRight = BorderStyle.THIN,
	borderTop = BorderStyle.THIN
)
@ContentStyle(
	borderBottom = BorderStyle.THIN,
	borderLeft = BorderStyle.THIN,
	borderRight = BorderStyle.THIN,
	borderTop = BorderStyle.THIN,
	wrapped = true,
	horizontalAlignment = HorizontalAlignment.LEFT
)
@HeadFontStyle(fontHeightInPoints = (short) 16)
@ContentFontStyle(fontHeightInPoints = (short) 14)
public class ExportDataDTO {

	private static final long serialVersionUID = 1L;
	/**
	 * 序號
	 */
	@ColumnWidth(8)
	@ExcelProperty({"文件登記簿", "序號"})
	private Integer rowNum;
	/**
	 * 標題
	 */
	@ColumnWidth(50)
	@ExcelProperty({"文件登記簿", "姓名"})
	private String name;
	/**
	 * 業務類型
	 */
	@ColumnWidth(20)
	@ExcelProperty({"文件登記簿", "年齡"})
	private String age;
	/**
	 * 業務類型
	 */
	@ColumnWidth(18)
	@ExcelProperty({"文件登記簿", "性別"})
	private String gender;
}

導出工具類

點擊查看代碼
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.integer.IntegerNumberConverter;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.*.core.excel.converter.BaseDateConverter;
import com.*.core.excel.listener.DataListener;
import com.*.core.excel.listener.ImportListener;
import com.*.core.excel.strategy.AdjustColumnWidthToFitStrategy;
import com.*.core.excel.support.ExcelException;
import com.*.core.excel.support.ExcelImporter;
import com.*.core.mp.support.Query;
import com.*.core.tool.utils.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.BiFunction;

/**
 * Excel工具類
 *
 * @author Chill
 * @apiNote https://www.yuque.com/easyexcel/doc/easyexcel
 */
@Slf4j
public class ExcelUtil {
        /**
	 * 導出excel
	 *
	 * @param response  響應類
	 * @param fileName  文件名
	 * @param sheetName sheet名
	 * @param dataList  數據列表
	 * @param clazz     class類
	 * @param <T>       泛型
	 */
	@SneakyThrows
	public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz) {
		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding(Charsets.UTF_8.name());
		fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
		response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
		EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
	}


	/**
	 * 根據分頁查詢導出excel,根據exportClazz類導出
	 *
	 * @param dto          DTO(分頁查詢對象)
	 * @param resp         響應對象
	 * @param exportClazz  需要導出的類
	 * @param fileName     文件名
	 * @param pageDataFunc 分頁查詢方法(須將字典值轉為中文,可調用wrapper方法)
	 * @param strategyList 寫入策略集合
	 * @param <D>          DTO類
	 * @param <V>          VO類
	 * @param <E>          導出類
	 */
	public static <D, V, E> void export(@NotNull D dto,
					    @NotNull HttpServletResponse resp,
					    @NotNull Class<E> exportClazz,
					    @Nullable String fileName,
					    @NotNull BiFunction<D, Query, ? extends IPage<V>> pageDataFunc,
					    @Nullable List<? extends WriteHandler> strategyList) {
		log.info("==================開始導出excel==================");
		fileName = fileName + ".xlsx";
		String filePath = FileUtil.getTempDirPath() + fileName;
		InputStream in = null;
		OutputStream outp = null;
		File file = new File(filePath);
		try {
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			if (!file.exists()) {
				file.createNewFile();
			}
			// 構造表格樣式
			List<WriteHandler> strategies = new ArrayList<>();
			if (ObjectUtil.isNotEmpty(strategyList)) {
				strategies.addAll(strategyList);
			} else {
				// 預設導出樣式
				strategies.addAll(getDefaultStrategy());
			}

			List<List<String>> content = new ArrayList<>();
			// 構建excel寫入對象
			ExcelWriterBuilder writerBuilder = EasyExcel.write(file, exportClazz);
			// 註冊寫入策略
			strategies.forEach(writerBuilder::registerWriteHandler);
			// 註冊對象轉換器
			writerBuilder.registerConverter(new BaseDateConverter.LocalDateTimeConverter());
			writerBuilder.registerConverter(new BaseDateConverter.LocalDateConverter());
			writerBuilder.registerConverter(new BaseDateConverter.LocalTimeConverter());
			writerBuilder.registerConverter(new IntegerNumberConverter());
			ExcelWriter excelWriter = writerBuilder.build();
			// 這裡註意 如果同一個sheet只要創建一次
			WriteSheet writeSheet = EasyExcel.writerSheet(DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATETIME_MINI)).build();
			// 分頁查詢數據
			Query query = new Query();
			query.setSize(500);  //mybatis-plus最大分頁500條
			query.setCurrent(0);
			IPage<V> dataPage = pageDataFunc.apply(dto, query);
			long total = dataPage.getTotal();
			if (total > 50000) {
				throw new ExcelException("數據量過大,請按條件篩選導出");
			} else if (total <= 0) {
				throw new ExcelException("沒有可以導出的數據");
			}
			long totalPage = (long) (Math.ceil(((double) total / dataPage.getSize())));
			for (int i = 1; i <= totalPage; i++) {
				List<E> exportList = new ArrayList<>();
				query.setCurrent(i);
				dataPage = pageDataFunc.apply(dto, query);
				List<V> dataList = new ArrayList<>(dataPage.getRecords());
				exportList = BeanUtil.copyProperties(dataList, exportClazz);
				for (int j = 0; j < exportList.size(); j++) {
					E e = exportList.get(j);
					List<Field> fields = getField(e);
					Optional<Field> rowNumField = fields.stream().filter(field -> field.getName().equalsIgnoreCase("rowNum")).findFirst();
					int rowNum = query.getSize() * (i - 1) + (j + 1);
					rowNumField.ifPresent(field -> {
						field.setAccessible(true);
						try {
							field.set(e, rowNum);
						} catch (IllegalAccessException illegalAccessException) {
							illegalAccessException.printStackTrace();
						}
					});
				}
				excelWriter.write(exportList, writeSheet);
			}
			// 千萬別忘記finish 會幫忙關閉流
			excelWriter.finish();

			in = new FileInputStream(filePath);
			outp = resp.getOutputStream();
			//設置請求以及響應的內容類型以及編碼方式
			resp.setContentType("application/vnd.ms-excel;charset=UTF-8");
			resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
			outp = resp.getOutputStream();
			//獲取文件輸入流
			byte[] b = new byte[1024];
			int i = 0;
			//將緩衝區的數據輸出到客戶瀏覽器
			while ((i = in.read(b)) > 0) {
				outp.write(b, 0, i);
			}
			outp.flush();
			log.info("============導出成功辣!!!!!!!!===========");
		} catch (IOException e) {
			e.printStackTrace();
			log.error("============導出失敗===========,異常信息:{}", e.getMessage());
		} finally {
			IoUtil.closeQuietly(in);
			IoUtil.closeQuietly(outp);
			FileUtil.deleteQuietly(file);
		}
	}


	/**
	 * 根據分頁查詢導出excel,導出列的順序由<code>exportFields</code>的順序決定
	 *
	 * @param dto          DTO(分頁查詢對象)
	 * @param resp         響應對象
	 * @param exportFields 需要導出的欄位列表(有序map)
	 * @param fileName     文件名
	 * @param columnWidth  自定義列寬map,key為列下標,value為寬度,單位:1000=1cm
	 * @param pageDataFunc 分頁查詢方法(須將字典值轉為中文,可調用wrapper方法)
	 * @param strategyList 寫入策略集合
	 * @param <D>          DTO泛型
	 * @param <V>          VO泛型
	 */
	public static <D, V> void export(@NotNull D dto,
					 @NotNull HttpServletResponse resp,
					 @NotNull LinkedHashMap<String, String> exportFields,
					 @Nullable String fileName,
					 @NotNull Map<Integer, Integer> columnWidth,
					 @NotNull BiFunction<D, Query, ? extends IPage<V>> pageDataFunc,
					 @Nullable List<? extends WriteHandler> strategyList) {
		log.info("==================開始導出excel==================");
		fileName = fileName + ".xlsx";
		String filePath = FileUtil.getTempDirPath() + fileName;
		InputStream in = null;
		OutputStream outp = null;
		File file = new File(filePath);
		try {
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			if (!file.exists()) {
				file.createNewFile();
			}
			// 構造表格樣式
			List<WriteHandler> strategies = new ArrayList<>();
			if (ObjectUtil.isNotEmpty(strategyList)) {
				strategies.addAll(strategyList);
			} else {
				// 預設導出樣式
				strategies.addAll(getDefaultStrategy());
			}

			List<List<String>> head = new ArrayList<>();
			List<List<String>> content = new ArrayList<>();
			exportFields.forEach((key, value) -> head.add(Collections.singletonList(value)));
			exportFields.forEach((key, value) -> content.add(Collections.singletonList(key)));
			// 構建excel寫入對象
			ExcelWriterBuilder writerBuilder = EasyExcel.write(file).head(head);
			// 註冊寫入策略
			strategies.forEach(writerBuilder::registerWriteHandler);
			// 註冊對象轉換器
			writerBuilder.registerConverter(new BaseDateConverter.LocalDateTimeConverter());
			writerBuilder.registerConverter(new BaseDateConverter.LocalDateConverter());
			writerBuilder.registerConverter(new BaseDateConverter.LocalTimeConverter());
			writerBuilder.registerConverter(new BaseDateConverter.IntegerConverter());
			ExcelWriter excelWriter = writerBuilder.build();
			// 這裡註意 如果同一個sheet只要創建一次
			WriteSheet writeSheet = EasyExcel.writerSheet(DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATETIME_MINI)).build();
			writeSheet.setColumnWidthMap(ObjectUtil.isNotEmpty(columnWidth) ? columnWidth : null);
			// 分頁查詢數據
			Query query = new Query();
			query.setSize(500);  //mybatis-plus最大分頁500條
			query.setCurrent(0);
			IPage<V> dataPage = pageDataFunc.apply(dto, query);
			long total = dataPage.getTotal();
			if (total > 50000) {
				throw new ExcelException("數據量過大,請按條件篩選導出");
			} else if (total <= 0) {
				throw new ExcelException("沒有可以導出的數據");
			}
			long totalPage = (long) (Math.ceil(((double) total / dataPage.getSize())));
			for (int i = 1; i <= totalPage; i++) {
				List<V> dataList = new ArrayList<>();
				List<List<Object>> exportList = new ArrayList<>();
				query.setCurrent(i);
				dataPage = pageDataFunc.apply(dto, query);
				dataList.addAll(dataPage.getRecords());

				for (int j = 0; j < dataList.size(); j++) {
					V dataVO = dataList.get(j);
					List<Object> exportMap = new ArrayList<>();
					for (List<String> s : content) {
						String str = s.get(0);
						List<Field> fieldList = getField(dataVO);
						Field field = fieldList.stream().filter(o -> o.getName().equalsIgnoreCase(str))
							.findFirst().orElseThrow(() -> new RuntimeException(StringUtil.format("找不到欄位:{}", str)));
						field.setAccessible(true);
						exportMap.add(Optional.ofNullable(field.get(dataVO)).orElse(""));
					}
					exportList.add(exportMap);
				}
				excelWriter.write(exportList, writeSheet);
			}
			// 千萬別忘記finish 會幫忙關閉流
			excelWriter.finish();

			in = new FileInputStream(filePath);
			outp = resp.getOutputStream();
			//設置請求以及響應的內容類型以及編碼方式
			resp.setContentType("application/vnd.ms-excel;charset=UTF-8");
			resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
			outp = resp.getOutputStream();
			//獲取文件輸入流
			byte[] b = new byte[1024];
			int i = 0;
			//將緩衝區的數據輸出到客戶瀏覽器
			while ((i = in.read(b)) > 0) {
				outp.write(b, 0, i);
			}
			outp.flush();
			log.info("============導出成功辣!!!!!!!!===========");
		} catch (IOException | IllegalAccessException e) {
			e.printStackTrace();
			log.error("============導出失敗===========,異常信息:{}", e.getMessage());
		} finally {
			IoUtil.closeQuietly(in);
			IoUtil.closeQuietly(outp);
			FileUtil.deleteQuietly(file);
		}
	}

	/**
	 * 預設導出樣式
	 *
	 * @return
	 */
	private static List<WriteHandler> getDefaultStrategy() {
		List<WriteHandler> writeHandlers = new ArrayList<>();
		/* 預設樣式 */
		// 頭的策略
		WriteCellStyle headStyle = new WriteCellStyle();
		WriteFont headFont = new WriteFont();
		headFont.setFontHeightInPoints((short) 12);
		headStyle.setWriteFont(headFont);

		// 內容的策略
		WriteCellStyle contentStyle = new WriteCellStyle();
		WriteFont contentFont = new WriteFont();
		contentFont.setFontHeightInPoints((short) 12);
		contentStyle.setWriteFont(contentFont);
		// 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現
		HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);
		writeHandlers.add(horizontalCellStyleStrategy);

		/* 列寬自適應 */
		writeHandlers.add(new AdjustColumnWidthToFitStrategy());
		return writeHandlers;
	}

	/**
	 * 獲取對象所有欄位(包括父類)
	 *
	 * @param o
	 * @return
	 */
	private static List<Field> getField(Object o) {
		Class c = o.getClass();
		List<Field> fieldList = new ArrayList<>();
		while (c != null) {
			fieldList.addAll(new ArrayList<>(Arrays.asList(c.getDeclaredFields())));
			c = c.getSuperclass();
		}
		return fieldList;
	}
}

列寬自適應策略類

點擊查看代碼

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description EasyExcel列寬自適應策略類
 * @date: 2023-5-17 10:06
 * @author: 熱得快炸了
 */
public class AdjustColumnWidthToFitStrategy extends AbstractColumnWidthStyleStrategy {
	private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

	@Override
	protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
		boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
		if (needSetWidth) {
			Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
			if (maxColumnWidthMap == null) {
				maxColumnWidthMap = new HashMap<>();
				CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
			}

			Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
			if (columnWidth >= 0) {
				if (columnWidth > 254) {
					columnWidth = 254;
				}

				Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
				if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
					maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
					Sheet sheet = writeSheetHolder.getSheet();
					sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 200);
				}

				//設置單元格類型
				cell.setCellType(CellType.STRING);
				// 數據總長度
				int length = cell.getStringCellValue().length();
				// 換行數
				int rows = cell.getStringCellValue().split("\n").length;
				// 預設一行高為20
				cell.getRow().setHeightInPoints(rows * 20);
			}
		}
	}

	/**
	 * 計算長度
	 *
	 * @param cellDataList
	 * @param cell
	 * @param isHead
	 * @return
	 */
	private Integer dataLength(List<CellData> 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:
						// 換行符(數據需要提前解析好)
						int index = cellData.getStringValue().indexOf("\n");
						return index != -1 ?
							cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
					case BOOLEAN:
						return cellData.getBooleanValue().toString().getBytes().length;
					case NUMBER:
						return cellData.getNumberValue().toString().getBytes().length;
					default:
						return -1;
				}
			}
		}
	}
}

分頁查詢工具類

點擊查看代碼
package com.*.core.mp.support;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 分頁工具
 *
 * @author 熱得快炸了
 */
@Data
@Accessors(chain = true)
@ApiModel(description = "查詢條件")
public class Query {

	/**
	 * 當前頁
	 */
	@ApiModelProperty(value = "當前頁")
	private Integer current;

	/**
	 * 每頁的數量
	 */
	@ApiModelProperty(value = "每頁的數量")
	private Integer size;

	/**
	 * 正排序規則
	 */
	@ApiModelProperty(hidden = true)
	private String ascs;

	/**
	 * 倒排序規則
	 */
	@ApiModelProperty(hidden = true)
	private String descs;

}

三、如何使用

1、簡單導出excel(需要定義導出實體類)

點擊查看代碼
	public void export(UserDTO userDTO, HttpServletResponse response) {
		List<User> userList = userService.getList(userDTO);
		String fileName = "導出數據_" + System.currentTimeMillis();
		ExcelUtil.export(response, fileName, "導出數據", userList, ExportDataDTO.class);
	}

2、根據分頁查詢導出excel(需要定義導出實體類)

點擊查看代碼
	public void export(UserDTO userDTO, HttpServletResponse response) {
		String fileName = "導出數據_" + System.currentTimeMillis();
		ExcelUtil.export(userDTO, response, ExportDataDTO.class, fileName,
			// 將分頁查詢方法作為參數傳入
			(dto, query) -> getPage(query, dto), 
                        // 此處可自定義excel寫入策略
                        null);
	}

3、根據分頁查詢導出excel,導出列順序可調整(不需要定義導出實體類)

點擊查看代碼
	public void export(UserDTO userDTO, HttpServletResponse response) {
		String fileName = "導出數據_" + System.currentTimeMillis();
                /* exportFields欄位由用戶在前端操作傳入,欄位順序可自由調整
                以下是前端傳入參數樣例
                {            		
                    exportFields: 
                    [
			{rowNum: "序號"},
			{name: "姓名"},
			{age: "年齡"},
			{gender: "性別"}
		    ]
                }
                也可自定義為如下結構
		LinkedHashMap<String, String> exportFields = new LinkedHashMap<>();
		exportFields.put("subject","標題");
		exportFields.put("businessTypeName","業務類型");
		exportFields.put("instantLevel","緊急程度");
		exportFields.put("operator","承辦人");
		exportFields.put("draftTime","擬稿時間");
		exportFields.put("sendOrgName","發文單位");

                自定義列寬示例
		LinkedHashMap<Integer, Integer> columnWidth = new LinkedHashMap<>();
		columnWidth.put(0, 20 * 1000);
		columnWidth.put(1, 8 * 1000);
		columnWidth.put(2, 5 * 1000);
		columnWidth.put(3, 8 * 1000);
		columnWidth.put(4, 8 * 1000);
		columnWidth.put(5, 10 * 1000);
		*/
		List<Map<String, String>> exportFields = userDTO.getExportFields();
		LinkedHashMap<String, String> exports = new LinkedHashMap<>();
		exportFields.forEach(exports::putAll);
		ExcelUtil.export(userDTO, resp, exports, fileName, 
                        // 此參數為自定義列寬時使用, 若傳入null則啟用自適應列寬
                        null,
			this::getPage, null);
	}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 loading的展示和取消可以說是每個前端對介面的時候都要關心的一個問題。這篇文章將要幫你解決的就是如何結合axios更加簡潔的處理loading展示與取消的邏輯。 首先在我們平時處理業務的時候loading一般分為三種:按鈕loadin ...
  • 馬上就要520了,也許你能用到這款《文生圖》工具!把字藏在圖裡,發給女神,大膽去表白吧~,文末附源碼喲!預覽地址:https://dombro.site/tools#/text-image ...
  • 當定義和調用函數時,JavaScript 函數對象會自動具有一些特定的屬性,以下是一些常見的屬性和方法。 1. arguments : arguments 是一個類數組對象,它包含了函數調用時傳遞的參數。它允許你在函數內部訪問傳遞給函數的參數列表,即使在函數定義時未明確聲明這些參數。可以通過索引訪問 ...
  • 關於JWT,可以說是分散式系統下的一個利器,我在我的很多項目實踐中,認證系統的第一選擇都是JWT。它的優勢會讓你欲罷不能,就像你領優惠券一樣。 ...
  • 有很多人問過我,學習開源項目消息推送平臺austin需要有什麼基礎,我往往會回答:**有`SpringBoot`基礎就夠了**。 我在幾年前總結過從零學習`Java`的路線,現在看來也沒有很過時: - `Java`基礎:流程式控制制-->面向對象(包括語法)-->集合-->`IO`流-->異常-->多線 ...
  • # C++ 如何快速實現一個容器的迭代器 ## 引言 C++的標準庫中的容器都會提供迭代器,如果一個容器滿足forward_range,那麼這個容器一般會提供以下成員類型和函數: - iterator - const_iterator - begin - end - begin - cend 如果該 ...
  • pom引入:有MP了就不要再引入mybatis了,會出bug的 ```xml com.baomidou mybatis-plus-boot-starter 3.5.3.1 com.baomidou mybatis-plus-generator 3.5.3.1 junit junit 4.13.2 ` ...
  • - [c++函數參數和返回值](#c函數參數和返回值) - [函數存儲位置](#函數存儲位置) - [函數參數入棧順序](#函數參數入棧順序) - [初始化列表](#初始化列表) - [函數的返回值](#函數的返回值) - [用參數引用來返回](#用參數引用來返回) - [返回一個參數指針](#返回 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...