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