JAVA使用自定义注解,在项目中实现EXCEL文件的导出

首先定义一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel {/*** 导出时在excel中排序*/int sort() default Integer.MAX_VALUE;/*** 导出到Excel中的名字.*/String name() default "";/*** 首行字段的批注*/String comment() default "";/*** 日期格式, 如: yyyy-MM-dd*/String dateFormat() default "";/*** 如果是字典类型,请设置字典的type值 (如: sys_user_sex)*/String dictType() default "";/*** 读取内容转表达式 (如: 0=男,1=女,2=未知)*/String readConverterExp() default "";/*** 分隔符,读取字符串组内容*/String separator() default ",";/*** BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)*/int scale() default -1;/*** BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN*/int roundingMode() default BigDecimal.ROUND_HALF_EVEN;/*** 导出类型(0数字 1字符串)*/ColumnType cellType() default ColumnType.STRING;/*** 导出时在excel中每个列的高度 单位为字符*/double height() default 14;/*** 导出时在excel中每个列的宽 单位为字符*/double width() default 16;/*** 文字后缀,如% 90 变成90%*/String suffix() default "";/*** 当值为空时,字段的默认值*/String defaultValue() default "";/*** 提示信息*/String prompt() default "";/*** 设置只能选择不能输入的列内容.*/String[] combo() default {};/*** 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.*/boolean isExport() default true;/*** 另一个类中的属性名称,支持多级获取,以小数点隔开*/String targetAttr() default "";/*** 是否自动统计数据,在最后追加一行统计数据总和*/boolean isStatistics() default false;/*** 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)*/Align align() default Align.AUTO;/*** 自定义数据处理器*/Class<?> handler() default ExcelHandlerAdapter.class;/*** 自定义数据处理器参数*/String[] args() default {};enum Align {AUTO(0), LEFT(1), CENTER(2), RIGHT(3);private final int value;Align(int value) {this.value = value;}public int value() {return this.value;}}/*** 字段类型(0:导出导入;1:仅导出;2:仅导入)*/Type type() default Type.ALL;/*** 字段类型(0:导出导入;1:仅导出;2:仅导入)*/enum Type {ALL(0), EXPORT(1), IMPORT(2);private final int value;Type(int value) {this.value = value;}public int value() {return this.value;}}enum ColumnType {NUMERIC(0), STRING(1), IMAGE(2);private final int value;ColumnType(int value) {this.value = value;}public int value() {return this.value;}}
}

 定义Excel工具类   里面自动写各种各样的导出方法   excel列名的格式  顺序  字体格式等等

public class ExcelUtil<T> {private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);/*** Excel sheet最大行数* Excel2007开始的版本最大行数是1048576行* 满足六个月的订单量下载,现在改为1000000*/public static final int sheetSize = 1000000;/*** 工作表名称*/private String sheetName;/*** 导出类型(EXPORT:导出数据;IMPORT:导入模板)*/private Type type;/*** 工作薄对象*/private Workbook wb;/*** 工作表对象*/private Sheet sheet;/*** 样式列表*/private Map<String, CellStyle> styles;/*** 导入导出数据列表*/private List<T> list;/*** 注解列表*/private List<Object[]> fields;/*** 当前行号*/private int rownum;/*** 标题*/private String title;/*** 最大高度*/private short maxHeight;/*** 统计列表*/private final Map<Integer, Double> statistics = new HashMap<>();/*** 数字格式*/private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");/*** 实体对象*/public Class<T> clazz;public ExcelUtil(Class<T> clazz) {this.clazz = clazz;}public void init(List<T> list, String sheetName, String title, Type type) {if (list == null) {list = new ArrayList<>();}this.list = list;this.sheetName = sheetName;this.type = type;this.title = title;createExcelField();createWorkbook();createTitle();}/*** 创建excel第一行标题*/public void createTitle() {if (StringUtils.isNotEmpty(title)) {Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);titleRow.setHeightInPoints(30);Cell titleCell = titleRow.createCell(0);titleCell.setCellStyle(styles.get("title"));titleCell.setCellValue(title);sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),this.fields.size() - 1));}}/*** 对excel表单默认第一个索引名转换成list** @param is 输入流* @return 转换后集合*/public List<T> importExcel(InputStream is) throws Exception {return importExcel(is, 0);}/*** 对excel表单默认第一个索引名转换成list** @param is       输入流* @param titleNum 标题占用行数* @return 转换后集合*/public List<T> importExcel(InputStream is, int titleNum) throws Exception {return importExcel(StringUtils.EMPTY, is, titleNum);}/*** 对excel表单指定表格索引名转换成list** @param sheetName 表格索引名* @param titleNum  标题占用行数* @param is        输入流* @return 转换后集合*/public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception {this.type = Type.IMPORT;this.wb = WorkbookFactory.create(is);List<T> list = new ArrayList<>();// 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheetSheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);if (sheet == null) {throw new IOException("文件sheet不存在");}boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);Map<String, PictureData> pictures;if (isXSSFWorkbook) {pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);} else {pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);}// 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1int rows = sheet.getLastRowNum();if (rows > 0) {// 定义一个map用于存放excel列的序号和field.Map<String, Integer> cellMap = new HashMap<>();// 获取表头Row heard = sheet.getRow(titleNum);for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) {Cell cell = heard.getCell(i);if (StringUtils.isNotNull(cell)) {String value = this.getCellValue(heard, i).toString();cellMap.put(value, i);} else {cellMap.put(null, i);}}// 有数据时才处理 得到类的所有field.List<Object[]> fields = this.getFields();Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();for (Object[] objects : fields) {Excel attr = (Excel) objects[1];Integer column = cellMap.get(attr.name());if (column != null) {fieldsMap.put(column, objects);}}for (int i = titleNum + 1; i <= rows; i++) {// 从第2行开始取数据,默认第一行是表头.Row row = sheet.getRow(i);// 判断当前行是否是空行if (isRowEmpty(row)) {continue;}T entity = null;for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet()) {Object val = this.getCellValue(row, entry.getKey());// 如果不存在实例则新建.entity = (entity == null ? clazz.newInstance() : entity);// 从map中得到对应列的field.Field field = (Field) entry.getValue()[0];Excel attr = (Excel) entry.getValue()[1];// 取得类型,并根据对象类型设置值.Class<?> fieldType = field.getType();if (String.class == fieldType) {String s = Convert.toStr(val);if (StringUtils.endsWith(s, ".0")) {val = StringUtils.substringBefore(s, ".0");} else {String dateFormat = field.getAnnotation(Excel.class).dateFormat();if (StringUtils.isNotEmpty(dateFormat)) {val = DateUtils.parseDateToStr(dateFormat, (Date) val);} else {val = Convert.toStr(val);}}} else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {val = Convert.toInt(val);} else if (Long.TYPE == fieldType || Long.class == fieldType) {val = Convert.toLong(val);} else if (Double.TYPE == fieldType || Double.class == fieldType) {val = Convert.toDouble(val);} else if (Float.TYPE == fieldType || Float.class == fieldType) {val = Convert.toFloat(val);} else if (BigDecimal.class == fieldType) {val = Convert.toBigDecimal(val);} else if (Date.class == fieldType) {if (val instanceof String) {val = DateUtils.parseDate(val);} else if (val instanceof Double) {val = DateUtil.getJavaDate((Double) val);}} else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {val = Convert.toBool(val, false);}if (StringUtils.isNotNull(fieldType)) {String propertyName = field.getName();if (StringUtils.isNotEmpty(attr.targetAttr())) {propertyName = field.getName() + "." + attr.targetAttr();} else if (StringUtils.isNotEmpty(attr.readConverterExp())) {val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());} else if (StringUtils.isNotEmpty(attr.dictType())) {val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());} else if (!attr.handler().equals(ExcelHandlerAdapter.class)) {val = dataFormatHandlerAdapter(val, attr);} else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) {PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());if (image == null) {val = "";} else {byte[] data = image.getData();val = FileUtils.writeImportBytes(data);}}ReflectUtils.invokeSetter(entity, propertyName, val);}}list.add(entity);}}return list;}/*** 对list数据源将其里面的数据导入到excel表单** @param list      导出数据集合* @param sheetName 工作表的名称* @return 结果*/public AjaxResult exportExcel(List<T> list, String sheetName) {return exportExcel(list, sheetName, StringUtils.EMPTY);}/*** 对list数据源将其里面的数据导入到excel表单** @param list      导出数据集合* @param sheetName 工作表的名称* @param title     标题* @return 结果*/public AjaxResult exportExcel(List<T> list, String sheetName, String title) {this.init(list, sheetName, title, Type.EXPORT);return exportExcel();}/*** 对list数据源将其里面的数据导入到excel表单** @param response  返回数据* @param list      导出数据集合* @param sheetName 工作表的名称* @return 结果* @throws IOException*/public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) {exportExcel(response, list, sheetName, StringUtils.EMPTY);}/*** 对list数据源将其里面的数据导入到excel表单** @param outputStream  outputStream* @param list      导出数据集合* @param sheetName 工作表的名称*/public void exportExcel(OutputStream outputStream, List<T> list, String sheetName) {this.init(list, sheetName, title, Type.EXPORT);try {writeSheet();wb.write(outputStream);} catch (Exception e) {log.error("导出Excel异常{}", e.getMessage());} finally {IOUtils.closeQuietly(wb);}}/*** 对list数据源将其里面的数据导入到excel表单** @param response  返回数据* @param list      导出数据集合* @param sheetName 工作表的名称* @param title     标题* @return 结果* @throws IOException*/public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");this.init(list, sheetName, title, Type.EXPORT);exportExcel(response);}/*** 对list数据源将其里面的数据导入到excel表单** @param sheetName 工作表的名称* @return 结果*/public AjaxResult importTemplateExcel(String sheetName) {return importTemplateExcel(sheetName, StringUtils.EMPTY);}/*** 对list数据源将其里面的数据导入到excel表单** @param sheetName 工作表的名称* @param title     标题* @return 结果*/public AjaxResult importTemplateExcel(String sheetName, String title) {this.init(null, sheetName, title, Type.IMPORT);return exportExcel();}/*** 对list数据源将其里面的数据导入到excel表单** @param sheetName 工作表的名称* @return 结果*/public void importTemplateExcel(HttpServletResponse response, String sheetName) {importTemplateExcel(response, sheetName, StringUtils.EMPTY);}/*** 对list数据源将其里面的数据导入到excel表单** @param sheetName 工作表的名称* @param title     标题* @return 结果*/public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");this.init(null, sheetName, title, Type.IMPORT);exportExcel(response);}/*** 对list数据源将其里面的数据导入到excel表单** @return 结果*/public void exportExcel(HttpServletResponse response) {try {writeSheet();wb.write(response.getOutputStream());} catch (Exception e) {log.error("导出Excel异常{}", e.getMessage());} finally {IOUtils.closeQuietly(wb);}}/*** 对list数据源将其里面的数据导入到excel表单** @return 结果*/public AjaxResult exportExcel() {OutputStream out = null;try {writeSheet();String filename = encodingFilename(sheetName);out = new FileOutputStream(getAbsoluteFile(filename));wb.write(out);return AjaxResult.success(filename);} catch (Exception e) {log.error("导出Excel异常{}", e.getMessage());throw new UtilException("导出Excel失败,请联系网站管理员!");} finally {IOUtils.closeQuietly(wb);IOUtils.closeQuietly(out);}}/*** 创建写入数据到Sheet*/public void writeSheet() {// 取出一共有多少个sheet.int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));for (int index = 0; index < sheetNo; index++) {createSheet(sheetNo, index);// 产生一行Row row = sheet.createRow(rownum);int column = 0;// 写入各个字段的列头名称for (Object[] os : fields) {Excel excel = (Excel) os[1];this.createCell(excel, row, column++);}if (Type.EXPORT.equals(type)) {fillExcelData(index, row);addStatisticsRow();}}}/*** 填充excel数据** @param index 序号* @param row   单元格行*/public void fillExcelData(int index, Row row) {int startNo = index * sheetSize;int endNo = Math.min(startNo + sheetSize, list.size());for (int i = startNo; i < endNo; i++) {row = sheet.createRow(i + 1 + rownum - startNo);// 得到导出对象.T vo = list.get(i);int column = 0;for (Object[] os : fields) {Field field = (Field) os[0];Excel excel = (Excel) os[1];this.addCell(excel, row, vo, field, column++);}}}/*** 创建表格样式** @param wb 工作薄对象* @return 样式列表*/private Map<String, CellStyle> createStyles(Workbook wb) {// 写入各条记录,每条记录对应excel表中的一行Map<String, CellStyle> styles = new HashMap<>();CellStyle style = wb.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);Font titleFont = wb.createFont();titleFont.setFontName("Arial");titleFont.setFontHeightInPoints((short) 16);titleFont.setBold(true);style.setFont(titleFont);styles.put("title", style);style = wb.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);style.setBorderRight(BorderStyle.THIN);style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderLeft(BorderStyle.THIN);style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderTop(BorderStyle.THIN);style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderBottom(BorderStyle.THIN);style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());Font dataFont = wb.createFont();dataFont.setFontName("Arial");dataFont.setFontHeightInPoints((short) 10);style.setFont(dataFont);styles.put("data", style);style = wb.createCellStyle();style.cloneStyleFrom(styles.get("data"));style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);Font headerFont = wb.createFont();headerFont.setFontName("Arial");headerFont.setFontHeightInPoints((short) 10);headerFont.setBold(true);headerFont.setColor(IndexedColors.WHITE.getIndex());style.setFont(headerFont);styles.put("header", style);style = wb.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);Font totalFont = wb.createFont();totalFont.setFontName("Arial");totalFont.setFontHeightInPoints((short) 10);style.setFont(totalFont);styles.put("total", style);style = wb.createCellStyle();style.cloneStyleFrom(styles.get("data"));style.setAlignment(HorizontalAlignment.LEFT);styles.put("data1", style);style = wb.createCellStyle();style.cloneStyleFrom(styles.get("data"));style.setAlignment(HorizontalAlignment.CENTER);styles.put("data2", style);style = wb.createCellStyle();style.cloneStyleFrom(styles.get("data"));style.setAlignment(HorizontalAlignment.RIGHT);styles.put("data3", style);return styles;}/*** 创建单元格*/public Cell createCell(Excel attr, Row row, int column) {// 创建列Cell cell = row.createCell(column);// 写入列信息cell.setCellValue(attr.name());setDataValidation(attr, row, column);cell.setCellStyle(styles.get("header"));return cell;}/*** 设置单元格信息** @param value 单元格值* @param attr  注解相关* @param cell  单元格信息*/public void setCellVo(Object value, Excel attr, Cell cell) {if (ColumnType.STRING == attr.cellType()) {cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());} else if (ColumnType.NUMERIC == attr.cellType()) {if (StringUtils.isNotNull(value)) {cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));}} else if (ColumnType.IMAGE == attr.cellType()) {ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);String imagePath = Convert.toStr(value);if (StringUtils.isNotEmpty(imagePath)) {byte[] data = ImageUtils.getImage(imagePath);getDrawingPatriarch(cell.getSheet()).createPicture(anchor,cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));}}}/*** 获取画布*/public static Drawing<?> getDrawingPatriarch(Sheet sheet) {if (sheet.getDrawingPatriarch() == null) {sheet.createDrawingPatriarch();}return sheet.getDrawingPatriarch();}/*** 获取图片类型,设置图片插入类型*/public int getImageType(byte[] value) {String type = FileTypeUtils.getFileExtendName(value);if ("JPG".equalsIgnoreCase(type)) {return Workbook.PICTURE_TYPE_JPEG;} else if ("PNG".equalsIgnoreCase(type)) {return Workbook.PICTURE_TYPE_PNG;}return Workbook.PICTURE_TYPE_JPEG;}/*** 创建表格样式*/public void setDataValidation(Excel attr, Row row, int column) {if (attr.name().indexOf("注:") >= 0) {sheet.setColumnWidth(column, 6000);} else {// 设置列宽sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));}// 如果设置了提示信息则鼠标放上去提示.if (StringUtils.isNotEmpty(attr.prompt())) {// 这里默认设了2-101列提示.setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);}// 如果设置了combo属性则本列只能选择不能输入if (attr.combo().length > 0) {// 这里默认设了2-101列只能选择不能输入.setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);}}/*** 添加单元格*/public Cell addCell(Excel attr, Row row, T vo, Field field, int column) {Cell cell = null;try {// 设置行高row.setHeight(maxHeight);// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.if (attr.isExport()) {// 创建cellcell = row.createCell(column);int align = attr.align().value();cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : "")));// 用于读取对象中的属性Object value = getTargetValue(vo, field, attr);String dateFormat = attr.dateFormat();String readConverterExp = attr.readConverterExp();String separator = attr.separator();String dictType = attr.dictType();if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) {if (value instanceof Date) {cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));} else {cell.setCellValue(DateUtils.parseDateTimeToStr(dateFormat, (LocalDateTime) value));}} else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) {cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));} else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) {cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));} else if (value instanceof BigDecimal && -1 != attr.scale()) {cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());} else if (!attr.handler().equals(ExcelHandlerAdapter.class)) {cell.setCellValue(dataFormatHandlerAdapter(value, attr));} else {// 设置列类型setCellVo(value, attr, cell);}addStatisticsData(column, Convert.toStr(value), attr);}} catch (Exception e) {log.error("导出Excel失败", e);}return cell;}/*** 设置 POI XSSFSheet 单元格提示** @param sheet         表单* @param promptTitle   提示标题* @param promptContent 提示内容* @param firstRow      开始行* @param endRow        结束行* @param firstCol      开始列* @param endCol        结束列*/public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,int firstCol, int endCol) {DataValidationHelper helper = sheet.getDataValidationHelper();DataValidationConstraint constraint = helper.createCustomConstraint("DD1");CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);DataValidation dataValidation = helper.createValidation(constraint, regions);dataValidation.createPromptBox(promptTitle, promptContent);dataValidation.setShowPromptBox(true);sheet.addValidationData(dataValidation);}/*** 设置某些列的值只能输入预制的数据,显示下拉框.** @param sheet    要设置的sheet.* @param textlist 下拉框显示的内容* @param firstRow 开始行* @param endRow   结束行* @param firstCol 开始列* @param endCol   结束列* @return 设置好的sheet.*/public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) {DataValidationHelper helper = sheet.getDataValidationHelper();// 加载下拉列表内容DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);// 数据有效性对象DataValidation dataValidation = helper.createValidation(constraint, regions);// 处理Excel兼容性问题if (dataValidation instanceof XSSFDataValidation) {dataValidation.setSuppressDropDownArrow(true);dataValidation.setShowErrorBox(true);} else {dataValidation.setSuppressDropDownArrow(false);}sheet.addValidationData(dataValidation);}/*** 解析导出值 0=男,1=女,2=未知** @param propertyValue 参数值* @param converterExp  翻译注解* @param separator     分隔符* @return 解析后值*/public static String convertByExp(String propertyValue, String converterExp, String separator) {StringBuilder propertyString = new StringBuilder();String[] convertSource = converterExp.split(",");for (String item : convertSource) {String[] itemArray = item.split("=");if (StringUtils.containsAny(separator, propertyValue)) {for (String value : propertyValue.split(separator)) {if (itemArray[0].equals(value)) {propertyString.append(itemArray[1]).append(separator);break;}}} else {if (itemArray[0].equals(propertyValue)) {return itemArray[1];}}}return StringUtils.stripEnd(propertyString.toString(), separator);}/*** 反向解析值 男=0,女=1,未知=2** @param propertyValue 参数值* @param converterExp  翻译注解* @param separator     分隔符* @return 解析后值*/public static String reverseByExp(String propertyValue, String converterExp, String separator) {StringBuilder propertyString = new StringBuilder();String[] convertSource = converterExp.split(",");for (String item : convertSource) {String[] itemArray = item.split("=");if (StringUtils.containsAny(separator, propertyValue)) {for (String value : propertyValue.split(separator)) {if (itemArray[1].equals(value)) {propertyString.append(itemArray[0]).append(separator);break;}}} else {if (itemArray[1].equals(propertyValue)) {return itemArray[0];}}}return StringUtils.stripEnd(propertyString.toString(), separator);}/*** 解析字典值** @param dictValue 字典值* @param dictType  字典类型* @param separator 分隔符* @return 字典标签*/public static String convertDictByExp(String dictValue, String dictType, String separator) {return DictUtils.getDictLabel(dictType, dictValue, separator);}/*** 反向解析值字典值** @param dictLabel 字典标签* @param dictType  字典类型* @param separator 分隔符* @return 字典值*/public static String reverseDictByExp(String dictLabel, String dictType, String separator) {return DictUtils.getDictValue(dictType, dictLabel, separator);}/*** 数据处理器** @param value 数据值* @param excel 数据注解* @return*/public String dataFormatHandlerAdapter(Object value, Excel excel) {try {Object instance = excel.handler().newInstance();Method formatMethod = excel.handler().getMethod("format", Object.class, String[].class);value = formatMethod.invoke(instance, value, excel.args());} catch (Exception e) {log.error("不能格式化数据{}", excel.handler(), e);}return Convert.toStr(value);}/*** 合计统计信息*/private void addStatisticsData(Integer index, String text, Excel entity) {if (entity != null && entity.isStatistics()) {Double temp = 0D;if (!statistics.containsKey(index)) {statistics.put(index, temp);}try {temp = Double.valueOf(text);} catch (NumberFormatException e) {log.error("数据格式化异常{}", temp, e);}statistics.put(index, statistics.get(index) + temp);}}/*** 创建统计行*/public void addStatisticsRow() {if (statistics.size() > 0) {Row row = sheet.createRow(sheet.getLastRowNum() + 1);Set<Integer> keys = statistics.keySet();Cell cell = row.createCell(0);cell.setCellStyle(styles.get("total"));cell.setCellValue("合计");for (Integer key : keys) {cell = row.createCell(key);cell.setCellStyle(styles.get("total"));cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));}statistics.clear();}}/*** 编码文件名*/public String encodingFilename(String filename) {filename = UUID.randomUUID() + "_" + filename + ".xlsx";return filename;}/*** 获取下载路径** @param filename 文件名称*/public String getAbsoluteFile(String filename) {String downloadPath = AusDrpConfig.getDownloadPath() + filename;File desc = new File(downloadPath);if (!desc.getParentFile().exists()) {desc.getParentFile().mkdirs();}return downloadPath;}/*** 获取bean中的属性值** @param vo    实体对象* @param field 字段* @param excel 注解* @return 最终的属性值* @throws Exception*/private Object getTargetValue(T vo, Field field, Excel excel) throws Exception {Object o = field.get(vo);if (StringUtils.isNotEmpty(excel.targetAttr())) {String target = excel.targetAttr();if (target.contains(".")) {String[] targets = target.split("[.]");for (String name : targets) {o = getValue(o, name);}} else {o = getValue(o, target);}}return o;}/*** 以类的属性的get方法方法形式获取值** @param o* @param name* @return value* @throws Exception*/private Object getValue(Object o, String name) throws Exception {if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) {Class<?> clazz = o.getClass();Field field = clazz.getDeclaredField(name);field.setAccessible(true);o = field.get(o);}return o;}/*** 得到所有定义字段*/private void createExcelField() {this.fields = getFields();this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());this.maxHeight = getRowHeight();}/*** 获取字段注解信息*/public List<Object[]> getFields() {List<Object[]> fields = new ArrayList<>();List<Field> tempFields = new ArrayList<>();tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));for (Field field : tempFields) {// 单注解if (field.isAnnotationPresent(Excel.class)) {Excel attr = field.getAnnotation(Excel.class);if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) {field.setAccessible(true);fields.add(new Object[]{field, attr});}}// 多注解if (field.isAnnotationPresent(Excels.class)) {Excels attrs = field.getAnnotation(Excels.class);Excel[] excels = attrs.value();for (Excel attr : excels) {if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) {field.setAccessible(true);fields.add(new Object[]{field, attr});}}}}return fields;}/*** 根据注解获取最大行高*/public short getRowHeight() {double maxHeight = 0;for (Object[] os : this.fields) {Excel excel = (Excel) os[1];maxHeight = Math.max(maxHeight, excel.height());}return (short) (maxHeight * 20);}/*** 创建一个工作簿*/public void createWorkbook() {this.wb = new SXSSFWorkbook();this.sheet = wb.createSheet();wb.setSheetName(0, sheetName);this.styles = createStyles(wb);}/*** 创建工作表** @param sheetNo sheet数量* @param index   序号*/public void createSheet(int sheetNo, int index) {// 设置工作表的名称.if (sheetNo > 1 && index > 0) {this.sheet = wb.createSheet();this.createTitle();wb.setSheetName(index, sheetName + index);}}/*** 获取单元格值** @param row    获取的行* @param column 获取单元格列号* @return 单元格值*/public Object getCellValue(Row row, int column) {if (row == null) {return null;}Object val = "";try {Cell cell = row.getCell(column);if (StringUtils.isNotNull(cell)) {if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) {val = cell.getNumericCellValue();if (DateUtil.isCellDateFormatted(cell)) {val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换} else {if ((Double) val % 1 != 0) {val = new BigDecimal(val.toString());} else {val = new DecimalFormat("0").format(val);}}} else if (cell.getCellType() == CellType.STRING) {val = cell.getStringCellValue();} else if (cell.getCellType() == CellType.BOOLEAN) {val = cell.getBooleanCellValue();} else if (cell.getCellType() == CellType.ERROR) {val = cell.getErrorCellValue();}}} catch (Exception e) {return val;}return val;}/*** 判断是否是空行** @param row 判断的行* @return*/private boolean isRowEmpty(Row row) {if (row == null) {return true;}for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {Cell cell = row.getCell(i);if (cell != null && cell.getCellType() != CellType.BLANK) {return false;}}return true;}/*** 获取Excel2003图片** @param sheet    当前sheet对象* @param workbook 工作簿对象* @return Map key:图片单元格索引(1_1)String,value:图片流PictureData*/public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) {Map<String, PictureData> sheetIndexPicMap = new HashMap<>();List<HSSFPictureData> pictures = workbook.getAllPictures();if (!pictures.isEmpty()) {for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) {HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();if (shape instanceof HSSFPicture) {HSSFPicture pic = (HSSFPicture) shape;int pictureIndex = pic.getPictureIndex() - 1;HSSFPictureData picData = pictures.get(pictureIndex);String picIndex = (anchor.getRow1()) + "_" + String.valueOf(anchor.getCol1());sheetIndexPicMap.put(picIndex, picData);}}return sheetIndexPicMap;} else {return sheetIndexPicMap;}}/*** 获取Excel2007图片** @param sheet    当前sheet对象* @param workbook 工作簿对象* @return Map key:图片单元格索引(1_1)String,value:图片流PictureData*/public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) {Map<String, PictureData> sheetIndexPicMap = new HashMap<>();for (POIXMLDocumentPart dr : sheet.getRelations()) {if (dr instanceof XSSFDrawing) {XSSFDrawing drawing = (XSSFDrawing) dr;List<XSSFShape> shapes = drawing.getShapes();for (XSSFShape shape : shapes) {if (shape instanceof XSSFPicture) {XSSFPicture pic = (XSSFPicture) shape;XSSFClientAnchor anchor = pic.getPreferredSize();CTMarker ctMarker = anchor.getFrom();String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();sheetIndexPicMap.put(picIndex, pic.getPictureData());}}}}return sheetIndexPicMap;}/*** 导出Excel(可以导出到本地文件系统,也可以导出到浏览器,可自定义工作表大小)** @param list      数据源* @param fieldMap  类的英文属性和Excel中的中文列名的对应关系 如果需要的是引用对象的属性,则英文属性使用类似于EL表达式的格式 如:list中存放的都是student,student中又有college属性,而我们需要学院名称,则可以这样写*                  fieldMap.put("college.collegeName","学院名称")* @param sheetName 工作表的名称* @param sheetSize 每个工作表中记录的最大个数* @param out       导出流*/public static <T> void listToExcel(List<T> list, LinkedHashMap<String, String> fieldMap, String sheetName, int sheetSize, OutputStream out) throws Exception {if (list == null) {throw new Exception("数据源中没有任何数据");}if (sheetSize > 65535 || sheetSize < 1) {sheetSize = 65535;}// 创建工作簿并发送到OutputStream指定的地方try {HSSFWorkbook workbook = new HSSFWorkbook();// 因为2003的Excel一个工作表最多可以有65536条记录,除去列头剩下65535条// 所以如果记录太多,需要放到多个工作表中,其实就是个分页的过程// 1.计算一共有多少个工作表double sheetNum = Math.ceil(list.size() / new Integer(sheetSize).doubleValue());if (sheetNum == 0) {sheetNum = 1;}// 2.创建相应的工作表,并向其中填充数据for (int i = 0; i < sheetNum; i++) {// 如果只有一个工作表的情况if (1 == sheetNum) {HSSFSheet sheet = null;if (null == sheetName) {sheet = workbook.createSheet();} else {sheet = workbook.createSheet(sheetName);}if (list.size() == 0) {fillSheetHeader(sheet, fieldMap);} else {fillSheet(sheet, list, fieldMap, 0, list.size() - 1);}// 有多个工作表的情况} else {HSSFSheet sheet = null;if (null == sheetName) {sheet = workbook.createSheet();} else {sheet = workbook.createSheet(sheetName + (i + 1));}// 获取开始索引和结束索引int firstIndex = i * sheetSize;int lastIndex = Math.min((i + 1) * sheetSize - 1, list.size() - 1);// 填充工作表fillSheet(sheet, list, fieldMap, firstIndex, lastIndex);}}workbook.write(out);workbook.close();} catch (Exception e) {log.error(e.getMessage(), e);//throw new BusinessException(ErrorCodeEnum.SYS_ERROR.getCode(),  "导出Excel失败");}}/*** 根据字段名获取字段值** @param fieldName 字段名* @param o         对象* @return 字段值*/private static Object getFieldValueByName(String fieldName, Object o) throws Exception {Object value = null;Field field = getFieldByName(fieldName, o.getClass());if (field != null) {field.setAccessible(true);value = field.get(o);// 实体类型,isAssignableFrom判断是否为父类
//            if (value == null && BaseEntity.class.isAssignableFrom(field.getType())) {
//                value = objenesis.newInstance(field.getType());
//                field.set(o, value);
//            }} else {// throw new BusinessException(ErrorCodeEnum.SYS_ERROR.getCode(), o.getClass().getSimpleName() + "类不存在字段名 " + fieldName);}return value;}/*** 根据字段名获取字段** @param fieldName 字段名* @param clazz     包含该字段的类* @return 字段*/private static Field getFieldByName(String fieldName, Class<?> clazz) {// 拿到本类的所有字段Field[] selfFields = clazz.getDeclaredFields();// 如果本类中存在该字段,则返回for (Field field : selfFields) {if (field.getName().equals(fieldName)) {return field;}}// 否则,查看父类中是否存在此字段,如果有则返回Class<?> superClazz = clazz.getSuperclass();if (superClazz != null && superClazz != Object.class) {return getFieldByName(fieldName, superClazz);}// 如果本类和父类都没有,则返回空return null;}/*** 根据带路径或不带路径的属性名获取属性值 即接受简单属性名,如userName等,又接受带路径的属性名,如student.department.name等** @param fieldNameSequence 带路径的属性名或简单属性名* @param o                 对象* @return 属性值*/private static Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception {Object value = null;// 将fieldNameSequence进行拆分String[] attributes = fieldNameSequence.split("\\.");if (attributes.length == 1) {value = getFieldValueByName(fieldNameSequence, o);if (value instanceof Calendar) {// Calendar 则转换成yyyy-MM-dd HH:mm:ss格式Calendar calendar = ((Calendar) value).getInstance();SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");value = sdf.format(calendar.getTime());}} else {// 根据属性名获取属性对象Object fieldObj = getFieldValueByName(attributes[0], o);String subFieldNameSequence = fieldNameSequence.substring(fieldNameSequence.indexOf(".") + 1);value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);}return value;}/*** 设置工作表自动列宽和首行加粗** @param ws sheet页*/private static void setColumnAutoSize(Sheet ws) {Row row = null;if (ws != null && ws.getLastRowNum() >= 0) {row = ws.getRow(0);}// 获取本列的最宽单元格的宽度for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {int colWith = 0;for (int j = 0; j <= ws.getLastRowNum(); j++) {Cell cell = ws.getRow(j).getCell(i);if (cell != null) {String content = cell.getStringCellValue();int cellWith = content.length();if (colWith < cellWith) {colWith = cellWith;}}}int columnWidth = (colWith + 1) * 512;// 设置最大列宽if (columnWidth > 12000) {columnWidth = 12000;}// 设置单元格的宽度为最宽宽度+额外宽度ws.setColumnWidth(i, columnWidth);}}/*** 向工作表中填充数据** @param sheet      工作表* @param list       数据源* @param fieldMap   中英文字段对应关系的Map* @param firstIndex 开始索引* @param lastIndex  结束索引*/private static <T> void fillSheet(Sheet sheet, List<T> list, Map<String, String> fieldMap, int firstIndex, int lastIndex) throws Exception {CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
//        // 设置垂直居中和自动换行
//        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//        // 设置水平居中
//        cellStyle.setAlignment(HorizontalAlignment.CENTER);// 字符串格式cellStyle.setWrapText(true);// 设置表头String[] enFields = fillSheetHeader(sheet, fieldMap);// 填充内容int rowNo = 1;for (int index = firstIndex; index <= lastIndex; index++) {Row row = sheet.createRow(rowNo);// 获取单个对象T item = list.get(index);// 添加序号addIndex(row, cellStyle, index);if (item instanceof Map) {// 处理Map@SuppressWarnings("unchecked") Map<String, String> itemMap = (Map<String, String>) item;for (int i = 1; i < enFields.length; i++) {String fieldValue = null;if (itemMap.containsKey(enFields[i])) {fieldValue = itemMap.get(enFields[i]);}if (fieldValue != null) {Cell cell = row.createCell(i);cell.setCellStyle(cellStyle);cell.setCellValue(fieldValue);}}} else {for (int i = 0; i < enFields.length; i++) {Object objValue = getFieldValueByNameSequence(enFields[i], item);String fieldValue = objValue == null ? "" : objValue.toString();Cell cell = row.createCell(i);cell.setCellStyle(cellStyle);cell.setCellValue(fieldValue);}}rowNo++;}// 设置自动列宽setColumnAutoSize(sheet);}/*** 功能描述: 添加序号列** @param row       : 行对象* @param cellStyle : 格式* @param index     : 序号* @author yansj* @date 2020/6/19 11:08**/private static void addIndex(Row row, CellStyle cellStyle, int index) {Cell cell = row.createCell(0);cell.setCellStyle(cellStyle);cell.setCellValue(String.valueOf(index + 1));}private static <T> String[] fillSheetHeader(Sheet sheet, Map<String, String> fieldMap) throws Exception {// 定义存放英文字段名和中文字段名的数组String[] enFields = new String[fieldMap.size()];String[] cnFields = new String[fieldMap.size()];// 填充数组int count = 0;for (Map.Entry<String, String> entry : fieldMap.entrySet()) {enFields[count] = entry.getKey();cnFields[count] = entry.getValue();count++;}CellStyle style = sheet.getWorkbook().createCellStyle();// 创建一个居中格式
//        style.setAlignment(HorizontalAlignment.CENTER);Font headFont = sheet.getWorkbook().createFont();//        headFont.setBold(true);headFont.setFontName("宋体");headFont.setFontHeightInPoints((short) 11);style.setFont(headFont);// 填充表头Row headerRow = sheet.createRow(0);for (int i = 0; i < cnFields.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellStyle(style);
//            if (i == 0) {
//                cell.setCellValue("序号");
//            } else {cell.setCellValue(cnFields[i]);//}}return enFields;}public void writeExcelSheets(Workbook workbook, Sheet sheet, List<T> recordList) {initSheet(recordList, Type.EXPORT, workbook, sheet);writeSingleSheet(sheet);}public void writeExcelSheetsField(Workbook workbook, Sheet sheet, List<T> recordList, List<String> filedList) {initSheetCustomize(recordList, Type.EXPORT, workbook, sheet, filedList);writeSingleSheet(sheet);}public void initSheet(List<T> list, Type type, Workbook workbook, Sheet sheet) {if (list == null) {list = new ArrayList<>();}this.list = list;this.type = type;this.sheet = sheet;createExcelField();this.styles = createStyles(workbook);}public void initSheetCustomize(List<T> list, Type type, Workbook workbook, Sheet sheet, List<String> filedList) {if (list == null) {list = new ArrayList<>();}this.list = list;this.type = type;this.sheet = sheet;createExcelCustomizeField(filedList);this.styles = createStyles(workbook);}/*** 得到所有定义字段*/private void createExcelCustomizeField(List<String> filedList) {this.fields = getCustomizeFields(filedList);this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());this.maxHeight = getRowHeight();}/*** 获取字段注解信息* 输出用户需要的列数据*/public List<Object[]> getCustomizeFields(List<String> filedList) {List<Object[]> fields = new ArrayList<>();List<Field> tempFields = new ArrayList<>();tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));for (Field field : tempFields) {// 单注解if (field.isAnnotationPresent(Excel.class)) {Excel attr = field.getAnnotation(Excel.class);if (attr != null && (attr.type() == Type.ALL || attr.type() == type) && filedList.contains(attr.name())) {field.setAccessible(true);fields.add(new Object[]{field, attr});}}// 多注解if (field.isAnnotationPresent(Excels.class)) {Excels attrs = field.getAnnotation(Excels.class);Excel[] excels = attrs.value();for (Excel attr : excels) {if (attr != null && (attr.type() == Type.ALL || attr.type() == type) && filedList.contains(attr.name())) {field.setAccessible(true);fields.add(new Object[]{field, attr});}}}}return fields;}/*** 创建写入数据到Sheet*/public void writeSingleSheet(Sheet sheet) {// 产生一行Row row = sheet.createRow(rownum);int column = 0;// 写入各个字段的列头名称for (Object[] os : fields) {Excel excel = (Excel) os[1];this.createCellWithComment(sheet, excel, row, column++);}if (Type.EXPORT.equals(type)) {fillExcelData(sheet, Constants.ZERO, row);}}public void fillExcelData(Sheet sheet, int index, Row row) {int startNo = index * sheetSize;int endNo = Math.min(startNo + sheetSize, list.size());for (int i = startNo; i < endNo; i++) {row = sheet.createRow(i + 1 + rownum - startNo);// 得到导出对象.T vo = list.get(i);int column = 0;for (Object[] os : fields) {Field field = (Field) os[0];Excel excel = (Excel) os[1];this.addCell(excel, row, vo, field, column++);}}}/*** 创建单元格*/public Cell createCellWithComment(Sheet sheet, Excel attr, Row row, int column) {// 创建列Cell cell = row.createCell(column);// 写入列信息cell.setCellValue(attr.name());if (ObjectUtil.isNotEmpty(attr.comment())) {// 创建批注并将其与单元格关联Drawing<?> drawing = sheet.createDrawingPatriarch();Comment comment = drawing.createCellComment(new XSSFClientAnchor());comment.setString(new XSSFRichTextString(attr.comment()));// 将批注添加到单元格cell.setCellComment(comment);}setDataValidation(attr, row, column);cell.setCellStyle(styles.get("header"));return cell;}
}

然后在你需要导出类的属性上加上该注解@Excel

@Data
public class DTO {@Excel(name = "Sales Platform")private String salesPlatform;@Excel(name = "Total Amount", comment = "Original total order amount provided by the sales platform")private String salesOrderTotal;@Excel(name = "Sales Order Type", comment = "standard order OR preorder order")private String salesOrderType;@Excel(name = "Sales Order Number")private String salesOrderNumber;}

最后我们修改完我们需要导出的list以后,就可以直接实现导出的excel文件给前端了

实现的效果  如图所示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68588.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据可视化大屏设计与实现

本文将带你一步步了解如何使用 ECharts 实现一个数据可视化大屏&#xff0c;并且如何动态加载天气数据展示。通过整合 HTML、CSS、JavaScript 以及后端接口请求&#xff0c;我们可以构建一个响应式的数据可视化页面。 1. 页面结构介绍 在此例中&#xff0c;整个页面分为几个主…

搭建Hadoop源代码阅读环境

个人博客地址:搭建Hadoop源代码阅读环境 | 一张假钞的真实世界 环境 Mac OS X EI Capitan 10.11.6java version “1.7.0_80”git version 2.7.4 (Apple Git-66)Apache Maven 3.3.9下载源代码 从Git上下载最新源代码: git clone git://git.apache.org/hadoop-common.git 构…

【2024年华为OD机试】 (B卷,100分)- 金字塔,BOSS的收入(Java JS PythonC/C++)

一、问题描述 微商模式收入计算 题目描述 微商模式中&#xff0c;下级每赚 100 元就要上交 15 元。给定每个级别的收入&#xff0c;求出金字塔尖上的人的收入。 输入描述 第一行输入 N&#xff0c;表示有 N 个代理商上下级关系。接下来输入 N 行&#xff0c;每行三个数&am…

光伏储能交直流微电网Matlab/Simulink仿真模型

博士毕业后项目和课题的交接工作也都基本上结束了&#xff0c;之前从20年我博一开始创作的博客&#xff0c;我也将从25年伊始重新进行更新&#xff0c;在保留原有内容的基础上&#xff0c;在对现如今的研究热点进行补充&#xff0c;希望能为各位校友提供一定的研究思路。首先是…

Windows中安装RabbitMQ

安装Erlang 下载地址&#xff1a;https://www.erlang.org/downloads 配置环境变量 变量名&#xff1a;ERLANG_HOME 变量值&#xff1a;D:\tools\Erlang-27.2 Path&#xff1a;%ERLANG_HOME%\bin 验证配置是否成功 erl 安装RabbitMQ 下载地址&#xff1a;https://www.rabbitm…

线性代数概述

矩阵与线性代数的关系 矩阵是线性代数的研究对象之一&#xff1a; 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合&#xff0c;是线性代数中的核心概念之一。矩阵的定义和性质构成了线性代数中矩阵理论的基础&#xff0c;而矩阵运算则简洁地表示和…

2024年度总结:从后端Java到全栈成长的蜕变

目录 前言1. 用数据与实践书写成长篇章2. 技术与生活的双重蜕变3. 技术的进阶与生活的绽放 前言 今年是我入行的第十年&#xff0c;也是记录在CSDN平台上的第五年。这五年来&#xff0c;我始终坚持记录成长的点滴&#xff0c;将个人事业与博客创作紧密相连。一路走来&#xff0…

关于new和delete的匹配问题

目录 引入 原理 引入 大家先看如下代码&#xff1a; class A { private:int _a 0; };int main() {A* arr1 new A[10];delete arr1;return 0; } 可以发现这里new了一个数组但却用delete释放。先看运行结果&#xff1a; 可以看到程序正常结束并没有崩 &#xff0c;别急我们…

蓝桥杯3526 子树的大小 | 数学规律

题目传送门 这个题目是一个数学题&#xff0c;比较好的方法是从上往下寻找子树的最左和最右的结点&#xff0c;每层统计子结点数&#xff0c;到树的底部时打印结果。 如何求最左、最右的子结点呢&#xff1f; 对于第i个结点,其前面有i-1个结点,每个结点各有m个孩子,再加上1号结…

计算机毕业设计Python+卷积神经网络租房推荐系统 租房大屏可视化 租房爬虫 hadoop spark 58同城租房爬虫 房源推荐系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Rust实现内网穿透工具:从原理到实现

目录 1.前言2.内网穿透原理3.丐版实现3.1 share3.2 server3.3 client3.4 测试4.项目优化4.1 工作空间4.2 代码合并4.3 无锁优化4.4 数据分离4.5 错误处理4.6 测试代码4.7 参数解析本篇原文为:Rust实现内网穿透工具:从原理到实现 更多C++进阶、rust、python、逆向等等教程,可…

Mysql 主从复制原理及其工作过程,配置一主两从实验

主从原理&#xff1a;MySQL 主从同步是一种数据库复制技术&#xff0c;它通过将主服务器上的数据更改复制到一个或多个从服务器&#xff0c;实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器&#xff0c;并在从服务器上执行这些日志中的操作…

【Vue3进阶】Pinia 中的 Store 组合式写法

Hey小伙伴们&#xff01;今天来给大家分享一个 Vue3 状态管理库 Pinia 中非常实用的功能——Store 的组合式写法。通过这种写法&#xff0c;我们可以将多个 store 进行组合和复用&#xff0c;使得代码更加模块化、清晰易读。 如果你对 Vue3 和 Pinia 感兴趣&#xff0c;或者想…

00_专栏《Redis 7.x企业级开发实战教程》介绍

大家好,我是袁庭新。Redis作为一款高性能、多用途的内存数据库,凭借其丰富的数据结构、高速读写能力、原子操作特性及发布订阅等功能,在缓存加速、分布式锁、消息队列等场景中不可或缺,极大提升了系统性能与开发效率,是现代互联网应用架构的关键组件。 你是否在学习Redis…

TensorFlow DAY3: 高阶 API(Keras,Estimator)(完)

TensorFlow 作为深度学习框架&#xff0c;当然是为了帮助我们更便捷地构建神经网络。所以&#xff0c;本次实验将会了解如何使用 TensorFlow 来构建神经网络&#xff0c;并学会 TensorFlow 构建神经网络的重要函数和方法。 知识点 Keras 顺序模型Keras 函数模型Keras 模型存储…

第14章:Python TDD应对货币类开发变化(一)

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…

macOS查看当前项目的 tree 结构

文章目录 使用 tree 命令 macOS 系统默认不包含 tree 命令 使用 tree 命令 使用homebrew自动安装脚本/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"安装 tree&#xff1a;brew install tree查看项目的 tree 结构&#…

Python自动化:基于faker批量生成模拟数据(以电商行业销售数据为例)

引言&#xff1a;个人认为&#xff0c;“造数据”是一个数据分析师的一项基本技能&#xff0c;当然啦&#xff0c;“造数据”不是说胡编乱造&#xff0c;而是根据自己的需求去构造一些模拟数据集&#xff0c;用于测试等用途&#xff0c;而且使用虚拟数据不用担心数据隐私和安全…

WPS数据分析000004

目录 一、表格阅读技巧 冻结窗格 拆分窗口 新建窗口 阅读模式 护眼模式 二、表格打印技巧 打印预览 打印缩放 打印区域 打印标题 分页打印 打印位置 页眉页脚 逐份打印 三、表格保护技巧 锁定单元格 隐藏公式 文档权限 文件加密 一、表格阅读技巧 冻结窗…

【前端】CSS学习笔记

目录 CSS的简介CSS的概念语法 CSS的引入方式内联样式&#xff08;行内样式&#xff09;内部样式外部样式&#xff08;推荐&#xff09; 选择器全局选择器元素选择器类选择器ID选择器合并选择器后代选择器子选择器相邻兄弟选择器通用兄弟选择器伪类选择器:link:visited:hover:ac…