java反射的一次应用

前阵子吧 用阿里的 easyexcel 做了导出。这阵子吧 ,人改需求了
前阵子需求导出的列是固定的。现在新需求是要做成可以选择导出的。比方说前台打钩了 id,title ,name,就导出这些数据。

所以 在使用阿里的 easyexcel 做导出的时候遇到了问题。阿里的是根据注解,有注解的列都导出了。暂时没发现有自定义这一说。

所以就使用poi自己做导出,觉得这个需求简单。直接让前台传递一个需要导出的字符串list 这样的。完事我拆分循环,判断、取值、导出。。。。所以就有了下边 的代码

 public String getExcelData(MemberPoints points,String title){
        switch (title){
            case "ID":
                return points.getId()+"";
            case "会员ID":
                return points.getMemberId() + "";
            case "会员昵称":
                return points.getMemberNickname();
            case "会员手机号":
                return points.getMemberPhone();
            case "会员姓名":
                return points.getMemberName();
            case "类型":
                if(points.getType()==1){
                    return "获得";
                }else{
                    return "支出";
                }
            case "积分数量":
                return points.getPoints()+"";
            case "标题":
                return points.getTitle();
            case "详情":
                return points.getContent();

            default:
                return "";
        }
    }

写一半 太累。 现在导出这个类 属性还是少的。那要是需求导出别的 那岂不是得写好多了。
所以就想 能不能根据用户传递给我的。需要导出的属性 直接get 到值了。
所以就有了下边的测试代码

        MemberPoints points = new MemberPoints();
        points.setId(1L);
        points.setTitle("测试标题");
        points.setContent("测试内容");
        points.setAddtime(new Date());
        //取得Class
        Class classs = points.getClass();
        String str = "Id,Title,Content,Addtime";
        //反射 获得方法
        Method method = classs.getMethod("getId" );
        //执行方法
        System.err.println(method.invoke(points));

大概就是 先写个模拟数据。 完事 反射 拿到 方法执行方法 获得值,测试类跑通了。说明方法可行,但是呢 还有 一般导出 表格 都是要有个表头的 。项目有用到 swagger 里的注解 所以就有了下边反射 拿注解 循环表头了

        //获得属性
        Field field = classs.getDeclaredField("title");
        //获得属性的注解
        ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
        //获得注解的方法
        Method method1 = apiModelProperty.getClass().getMethod("value");
        System.err.println(method1.invoke(apiModelProperty));

到这里基本 测试类已经实现了,然后给封装成帮助类
这个里直接用了 swagger 的注解 实际可以自定义注解的

所以 有了下边的帮助类

import io.swagger.annotations.ApiModelProperty;
import org.apache.poi.hssf.usermodel.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;

/**
 * @author YaoShiHang
 * @title: ExcelUtil
 * @projectName js-coupon
 * @description: 表格导出 帮助类
 * @date 2019/7/9  11:15
 */
public class ExcelUtil {


    public  static   HSSFWorkbook export(List list, String excelHeader, Class clazz) throws Exception {
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("sheet");
        HSSFRow row = sheet.createRow((int) 0);
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
        String[] headerArry = excelHeader.split(",");
        //先反射设置表头
        for (int i = 0; i < headerArry.length; i++) {
            //反射拿到类属性
            Field field = clazz.getDeclaredField(headerArry[i]);
            //获得属性注解
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            //获得注解方法
            Method method1 = apiModelProperty.getClass().getMethod("value");
            HSSFCell cell = row.createCell(i);
            //执行注解方法  获得注解值
            cell.setCellValue(method1.invoke(apiModelProperty)+"");
            cell.setCellStyle(style);
            sheet.autoSizeColumn(i);
        }
        //设置内容
        for (int i = 0; i < list.size(); i++) {
            Object obj = list.get(i);
            Class clas = obj.getClass();
            row = sheet.createRow(i+1);
            for (int j = 0; j < headerArry.length; j++) {
                Method method = clas.getMethod("get"+getMethodName(headerArry[j]) );
                Type type = method.getGenericReturnType();// 获取返回值类型
                HSSFCell cell = row.createCell(j);
                if(type.getTypeName().equals("java.util.Date")){
                    //时间类型格式化 非时间类型 直接输出
                    cell.setCellValue(DateUtils.getCurrentDateTimeMilliSecond((Date) method.invoke(obj)));
                }else{
                    cell.setCellValue(method.invoke(obj)+"");
                }
                cell.setCellStyle(style);
            }
        }
        setSizeColumn(sheet);
        return wb;
    }

    //首字母转大写
    private static String getMethodName(String fildeName) throws Exception{
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }


    //设置poi 导出行自适应
    private static void setSizeColumn(HSSFSheet sheet) {
        for (int columnNum = 0; columnNum <= 8; columnNum++) {
            int columnWidth = sheet.getColumnWidth(columnNum) / 256;
            for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
                HSSFRow currentRow;
                //当前行未被使用过
                if (sheet.getRow(rowNum) == null) {
                    currentRow = sheet.createRow(rowNum);
                } else {
                    currentRow = sheet.getRow(rowNum);
                }
                if (currentRow.getCell(columnNum) != null) {
                    HSSFCell currentCell = currentRow.getCell(columnNum);
                    if (currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
                        int length = currentCell.getStringCellValue().getBytes().length;
                        if (columnWidth < length) {
                            columnWidth = length;
                        }
                    }
                }
            }
            sheet.setColumnWidth(columnNum, columnWidth * 256);
        }
    }


}

这样直接在controller里调用就好了

    @RequestMapping(value = "points/download", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
    @ApiOperation("用户积分 导出表格")
    //@RequiresPermissions(value={"points:download"},logical= Logical.OR  )
    public void  downloadPointsList(@RequestParam(defaultValue = "0",required = false) int type ,
                                    @RequestParam(defaultValue = "",required = false) String  begintime,
                                    @RequestParam(defaultValue = "",required = false) String  endtime,
                                    @RequestParam(defaultValue = "",required = false) String  headerStr, HttpServletResponse response) throws Exception {
        List downLoads = memberPointsService.downloadBytime(type,begintime,endtime);
        HSSFWorkbook wb = ExcelUtil.export(downLoads,headerStr,MemberPoints.class);
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=MemberPoints.xlsx");
        OutputStream ouputStream = response.getOutputStream();
        wb.write(ouputStream);
        ouputStream.flush();
        ouputStream.close();
    }

可以肯定的是以上代码 性能相对比较低,也未经过测试。只是刚好拿来学习java反射。

关于反射的一些学习
优点:

(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能

缺点:
(1)使用反射的性能较低
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性

你可能感兴趣的:(Java)