SpringBoot整合POI导出通用Excel

目录

  • 一、准备工作
    • 1、pom依赖
    • 2、自定义注解
    • 3、定义需要导出的实体
    • 4、定义导出辅助类
  • 二、具体的导出方法
    • 1、导出主要方法
    • 2、通过反射获取excel标题和列宽
    • 3、创建CellStyle
    • 4、通过反射获取对象信息并处理成String字符串
    • 5、枚举的定义
    • 6、encodeFileName
  • 三、方法调用案例
    • 1、方法调用
    • 2、导出效果

一、准备工作

1、pom依赖

在pom.xml中加入POI的依赖

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.11-beta1</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml-schemas</artifactId>
	<version>3.11-beta1</version>
</dependency>

2、自定义注解

自定义注解,用于定义excel单元格的相关信息,用在需要导出的类上。
大家可以根据自己的实际需求来定义更多的内容。

@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelResources {
     
	
	int order() default 9999;//定义字段在excel的单元格列坐标位置

	String title() default "";//定义列坐标对应的标题

	int cloumn() default 100;//定义列宽

	String pattern() default "";//定义日期显示格式

}

3、定义需要导出的实体

举例说明@ExcelResources 的应用场景,我们创建一个demoModel,包含姓名、年龄、性别、日期。
后边的excel导出例子也采用这个实体类来举例。

@Data
public class ExcelDemoModel {
     

    @ExcelResources(order=0,title = "姓名",cloumn = 10)
    private String name;

    @ExcelResources(order=1,title = "年龄",cloumn = 10)
    private Integer age;

    @ExcelResources(order=2,title = "创建时间",cloumn = 24,pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    @ExcelResources(order=3,title = "性别",cloumn = 10)
    private SexType sex;//枚举
    
}

4、定义导出辅助类

用于存放导出的excel对应标题和列宽

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TitleAndCloumn {
     

    private String title;//标题
    private int cloumn;//列宽

}

二、具体的导出方法

1、导出主要方法

@Service
public class ExcelService {
     

    private static float title_row_height=30;//标题行高
    private static float data_row_height=25;//数据行高

	public void exportExcel(HttpServletRequest request, HttpServletResponse response, String fileName ,List<?> excelDatas,Class<?> clz ) {
     
	
        try {
     

            HSSFWorkbook resultWb=new HSSFWorkbook();
            HSSFSheet sheet=resultWb.createSheet();//创建sheet

			//根据类类型信息获取导出的excel对应的标题和列宽  key-列号,value-标题和列宽
            HashMap<Integer, TitleAndCloumn> orderTitleAndCloumnMap=getTitleAndCloumnMap(clz);

            //设置列宽
            orderTitleAndCloumnMap.forEach((k,v) -> {
     
                sheet.setColumnWidth(k, v.getCloumn()*256);
            });

            HSSFRow row0=sheet.createRow(0);
            //设置标题行高
            row0.setHeightInPoints(title_row_height);

			//创建标题单元格格式
            HSSFCellStyle titleCellStyle=getCellStyle(resultWb,11,true,HSSFColor.BLACK.index);
            //填充标题行内容
            orderTitleAndCloumnMap.forEach((k,v) -> {
     
                HSSFCell row0Cell=row0.createCell(k);
                row0Cell.setCellValue(v.getTitle());
                row0Cell.setCellStyle(titleCellStyle);
            });

			//创建正文单元格格式
            HSSFCellStyle dataStyle = getCellStyle(resultWb,11,false,HSSFColor.BLACK.index);

			//将正文转换为excel数据
            int rowNum=1;
            for(Object data:excelDatas){
     

                HSSFRow row=sheet.createRow(rowNum++);
                row.setHeightInPoints(data_row_height);
				//获取对象值 key-列号 value-String值
                HashMap<Integer,String> orderValueMap=getValueMap(data);
                orderValueMap.forEach((k,v) ->{
     
                    HSSFCell cell=row.createCell(k);
                    cell.setCellValue(v);
                    cell.setCellStyle(dataStyle);
                        }
                );
            }

            String downFileName=fileName+".xls";
            response.setContentType("application/vnd.ms-excel; charset=UTF-8");// application/x-download
            response.setHeader("Content-Disposition", "attachment; "
                    +encodeFileName(request, downFileName));

            OutputStream outputStream = response.getOutputStream();
            resultWb.write(outputStream);
            outputStream.flush();
            outputStream.close();
            resultWb.close();

        }catch (Exception e1) {
     
            e1.printStackTrace();
        }

    }
}

2、通过反射获取excel标题和列宽

/**
     * 获取类的属性对应单元格标题和列宽
     * @param
     * @return
     */
    private static HashMap<Integer, TitleAndCloumn> getTitleAndCloumnMap(Class<?> clz) {
     

        HashMap<Integer, TitleAndCloumn> orderTitleAndCloumnMap=new HashMap<>();

        Field[] fs = clz.getDeclaredFields();
        for(Field f:fs) {
     
            f.setAccessible(true);
            if(f.isAnnotationPresent(ExcelResources.class)) {
     
                Integer order=f.getAnnotation(ExcelResources.class).order();
                String title=f.getAnnotation(ExcelResources.class).title();
                int cloumn=f.getAnnotation(ExcelResources.class).cloumn();

                TitleAndCloumn titleAndCloumn=new TitleAndCloumn(title,cloumn);
                orderTitleAndCloumnMap.put(order,titleAndCloumn);
            }
        }

        return orderTitleAndCloumnMap;

    }

3、创建CellStyle

通过传入参数定义简单地CellStyle

public HSSFCellStyle getCellStyle(HSSFWorkbook workbook,int fontSize,boolean isBoleaWeight,short color){
     

        HSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中

        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);

        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) fontSize);//字号
        font.setColor(color);//颜色
        font.setFontName("宋体");//字体

        if(isBoleaWeight){
     
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //字体加粗
        }

        style.setWrapText(true);
        style.setFont(font);

        return style;

    }

4、通过反射获取对象信息并处理成String字符串

我这里只涉及到基本数据类型和Date以及枚举的值获取和转换,小伙伴可以根据自己的实际情况进行修改。

/**
     * 获取对象的属性对应单元格坐标和值的键值对
     * @param obj
     * @return
     */
    private static HashMap<Integer, String> getValueMap(Object obj) throws IllegalAccessException {
     

        HashMap<Integer, String> result=new HashMap<>();

        Class<?> clz=obj.getClass();
        Field[] fs = clz.getDeclaredFields();
        for(Field f:fs) {
     
            f.setAccessible(true);
            if(f.isAnnotationPresent(ExcelResources.class)) {
     
                Integer order=f.getAnnotation(ExcelResources.class).order();
                String value="";

                Object valueObj=f.get(obj);
                if(valueObj!=null) {
     
					//日期格式进行特殊处理
                    if(f.getType()==Date.class){
     

                        String pattern=f.getAnnotation(ExcelResources.class).pattern();
                        if(StringUtils.isEmpty(pattern)){
     
                            pattern="yyyy-MM-dd HH:mm:ss";
                        }
                        SimpleDateFormat sdf=new SimpleDateFormat(pattern);
                        value=sdf.format(valueObj);
                    }else{
     
                        value=valueObj.toString();//其他格式调用toString方法,这里枚举就需要定义自己的toString方法
                    }

                }

                result.put(order, value);

            }
        }

        return result;
    }

5、枚举的定义

如果有用到枚举存储在数据库的小伙伴,可以自定义枚举的toString方法来实现excel导出时候相应的内容

public enum SexType {
     
	
	male("男"),
	female("女"),
	;

	private String typeName;

	SexType(String typeName) {
     
		this.typeName = typeName;
	}

	@Override
	public String toString() {
     
		return typeName;
	}

}

6、encodeFileName

 /**
     * 根据不同的浏览器生成不同类型中文文件名编码
     *
     * @param request
     * @param fileName
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String encodeFileName(HttpServletRequest request, String fileName)
            throws UnsupportedEncodingException
    {
     

        String new_filename = URLEncoder.encode(fileName, "UTF8").replaceAll("\\+", "%20");

        String agent = request.getHeader("USER-AGENT").toLowerCase();
        if (null != agent && -1 != agent.indexOf("msie"))
        {
     
            /**
             * IE浏览器,只能采用URLEncoder编码
             */
            return "filename=\"" + new_filename +"\"";
        }else if (null != agent && -1 != agent.indexOf("applewebkit")){
     
            /**
             * Chrome浏览器,只能采用ISO编码的中文输出
             */
            return "filename=\"" + new String(fileName.getBytes("UTF-8"),"ISO8859-1") +"\"";
        } else if (null != agent && -1 != agent.indexOf("opera")){
     
            /**
             * Opera浏览器只可以使用filename*的中文输出
             * RFC2231规定的标准
             */
            return "filename*=" + new_filename ;
        }else if (null != agent && -1 != agent.indexOf("safari")){
     
            /**
             * Safani浏览器,只能采用iso编码的中文输出
             */
            return "filename=\"" + new String(fileName.getBytes("UTF-8"),"ISO8859-1") +"\"";
        }else if (null != agent && -1 != agent.indexOf("firefox"))
        {
     
            /**
             * Firfox浏览器,可以使用filename*的中文输出
             * RFC2231规定的标准
             */
            return "filename*=" + new_filename ;
        } else
        {
     
            return "filename=\"" + new_filename +"\"";
        }
    }

三、方法调用案例

1、方法调用

public void exportExcelDemo(HttpServletRequest request, HttpServletResponse response) {
     

 		//一系列查询处理
        List<ExcelDemoModel> demoList=new ArrayList<>();
       
        excelService.exportExcel(request,response,"人员信息demo",demoList,ExcelDemoModel.class);

    }

2、导出效果

SpringBoot整合POI导出通用Excel_第1张图片

你可能感兴趣的:(spring,boot,poi,excel)