1. 程式人生 > 程式設計 >使用EasyPoi根據許可權動態匯出列——反射實現

使用EasyPoi根據許可權動態匯出列——反射實現

前言: 前段時間,因為業務需求需要根據使用者角色動態匯出excel,不同角色看到的列不同。以前用到的方法基本是(或者有其他土方法),建立多個實體類,每個實體類對應的列不同,以此來實現動態匯出,但顯然這是個笨方法,雖然省時省力,但好像總覺得哪裡不對。正片開始


easypoi連結: EasyPoi官方檔案

我們使用的註解版的匯出 @Excel,官方檔案中說明很詳細,預設大家都會用,不會用的,copy一下官網的,跑一下,調一下就行了。

舉個栗子:

@Data
@ExcelTarget("TestExcle")
public class TestExcle implements Serializable
{ private static final long serialVersionUID = 4152437113488964399L; @Excel(name = "名稱") private String name; @Excel(name = "年齡",isColumnHidden = true)) private String age; @Excel(name = "學校") private String school; @Excel(name = "狀態",replace = { "畢業_1","在校_2" }) private
Integer status; } 複製程式碼

我們需要用到的是EasyPoi官方提供的這個屬性 isColumnHidden

屬性 型別 預設值 功能
isColumnHidden boolean false 匯出隱藏列
// 點選@Excel註解進去看到原始碼
/**
 *  是否需要隱藏該列
 * @return
 */
public boolean isColumnHidden() default  false;
複製程式碼

可以看到,isColumnHidden中提供的預設值是false,也就是預設全部匯出,不隱藏。假如我的許可權是學生(ST),在登入教務系統時,匯出班級學生資訊時,不想讓學生看到各班同學的年齡情況,可以把它設定成 true

,不要問我為什麼不能看到年齡???這樣所有匯出都沒有學生列,但是如果教師(TC)(你們可怕的班主任或者往上的教導主任)匯出時是可以看到年齡資訊的。

思路:

JAVA反射機制是在執行狀態中,對於任意一個實體類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。——百度百科

根據反射我們可以拿到一個類的所有屬性和方法,同理,註解也是一個類,也是可以拿到它的屬性和方法,拿到之後就好辦了,直接修改它的預設值,然後根據每個角色調整,就可以達到一個類實現動態匯出的目的

以上面 TestExcle 為例: 先建立一個工具類,傳入TestExcle物件,獲取註解值,並修改

/**
 * 動態顯示Excel匯出列
 *
 * @param <T>
 * @author young
 */
public class EasyPoiUtil<T> {

/**
 * 需要被反射的物件,使用泛型規範傳入物件
 */
public T t;

/**
 * 動態更改EasyPoi中控制列顯示的值
 *
 * @param columnName 需要轉換的列屬性名稱
 * @param target     預設true
 * @throws NoSuchFieldException
 * @throws IllegalAccessException
 */
public void hihdColumn(String columnName,Boolean target) throws Exception {
    if (t == null) {
        throw new ClassNotFoundException("TARGET OBJECT NOT FOUNT");
    }
    if (StringUtils.isEmpty(columnName)) {
        throw new NullPointerException("COLUMN NAME NOT NULL");
    }
    if (target == null) {
        target = true;
    }
    //獲取目標物件的屬性值
    Field field = t.getClass().getDeclaredField(columnName);
    //獲取註解反射物件
    Excel excelAnnon = field.getAnnotation(Excel.class);
    //獲取代理
    InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnon);
    Field excelField = invocationHandler.getClass().getDeclaredField("memberValues");
    excelField.setAccessible(true);
    Map memberValues = (Map) excelField.get(invocationHandler);
    memberValues.put("isColumnHidden",target);
}
複製程式碼

然後在需要匯出的資料中更改對應角色能看到的列


//資料集合,一般都是從資料庫中獲取,這裡仿造資料
List<TestExcle> list = new ArrayList<>();
list.add(...);
...

for (TestExcle item : list){
    // roles 為當前使用者登入的許可權列表,各個系統都不一樣,但都能獲得
    // 如果是學生 ST 則隱藏 easyPoiUtil.hihdColumn("age",true);
    if (roles.contains('ST')) {
        EasyPoiUtil<ProductOrder> easyPoiUtil = new EasyPoiUtil<>();
        easyPoiUtil.t = item;
        try {
            easyPoiUtil.hihdColumn("age",true);
        } catch (Exception e) {
            log.info("列隱藏轉換失敗:{}",e.getMessage());
            e.printStackTrace();
        }
    } 
    // 如果是教師 TC 則顯示 easyPoiUtil.hihdColumn("age",false);
    if (roles.contains('TC')) {
        EasyPoiUtil<ProductOrder> easyPoiUtil = new EasyPoiUtil<>();
        easyPoiUtil.t = item;
        try {
            easyPoiUtil.hihdColumn("age",false);
        } catch (Exception e) {
            log.info("列隱藏轉換失敗:{}",e.getMessage());
            e.printStackTrace();
        }
    } 
}
複製程式碼

匯出之後,對應的角色就可以看到對應的列。如果有多個列表的話就多次呼叫即可

easyPoiUtil.hihdColumn("age",true);
easyPoiUtil.hihdColumn("school",true);
複製程式碼

大大的完結!

日常記錄開發小技巧