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<MemberPoints> 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)破壞了類的封裝性,可以通過反射獲取這個類的私有方法和屬性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章