反射動態操做類+註解靈活打標籤 | 反射註解結合靈活高效實戰

這是我參與更文挑戰的第29天,活動詳情查看: 更文挑戰java

前言

  • 以前兩篇文章咱們分別介紹了反射和註解的入門,其中也有同窗給到建議是從具體應用場景出發更容易理解精髓!今天筆者就結合下本身實際項目中使用到的功能!這裏算是拋磚引玉了

功能需求

  • 針對一張表作一個表單查詢功能!這個功能十分的簡單沒有技術難點無非就是咱們在寫查詢時注入條件寫成動態條件判斷!其餘就沒啥了

image-20210628142137773

  • 涉及公司內部數據,這裏關鍵數據已經被我換掉了!
  • 除了查詢之外,咱們還有生成數據的功能。結合對數據的管理咱們來看看如何註解反射左右開弓

數聽說明

  • 首先數據存儲在mongo中,查詢是經過MongoTemplate來實現數據的查詢
  • 存儲的數據時間數據是時間戳,頁面展現時須要格式化。這部分由接口處理
  • 關於數據狀態已驗收未驗收實際存儲的是一、2
  • 條件查詢時目前是上面幾種!每隔一段時間須要根據使用頻率及用戶反饋進行隨意調節

實體定義

@Data
public class DangersBook implements Serializable {
    @TimeSequence
    @Ignore
    @Id
    @Query
    private Long id;
    @DangersNo
    @Ignore
    @Query
    @LikeQuery
    private String dangersNo;
    @Ids
    private String instance_id;
    @DangersType
    @Ids
    private String app_id;
    @Ids
    @Query
    @DangersEntId
    @OrQuery
    private String entId;
    private String created_by;
    @Query
    @Ids
    private String zuoyeleixing;
    @Date
    @Query
    private String pizhunkaishi;
    @Date
    @Query
    private String pizhunjieshu;
    @UpdateItem(value = "已驗收")
    @Query
    @OrQuery
    private String yanshouStatus;
    @Query
    @Date
    @UpdateItem(value = "")
    private String finishTime;
    private String jianweixiuxukezheng;
    private String zuoyedengji;
    @Query
    @LikeQuery
    private String zuoyeneirong;
    /** * @Description 用於判斷是否應該生成編號 */
    @Ignore
    @Query
    private String createDangerNo;
    private String laowubanzu;
    @Query
    private String test;
    @Query
    private String interrupt;
    @Query
    @OrQuery
    private String year;
}
複製代碼

註解說明

  • 首先咱們須要先經過反射獲取到DangersBook中的全部屬性!這是咱們對反射的第一處運用!實際上在項目中凡是須要寫活屬性的獲取的都是經過反射進行獲取結合註解進行屬性過濾!

TimeSequence

  • 在生成數據是數據的惟一id每每都是後端自行生成的這樣才能保證真正的惟一!而TimeSequence註解就是對字段進行標註,這樣咱們在程序中只要識別到屬性中存在該註解就會進行惟一id生成
TimeSequence annotation = declaredField.getAnnotation(TimeSequence.class);
if (annotation!=null) {
    //雪花算法
    long generatorId = DistributedIDUtils.getInstance().getGeneratorId(1l, 2l, 3l);
    declaredField.setAccessible(true);
    declaredField.set(object, generatorId);
}
複製代碼
  • 獲取到TimeSequence以後咱們就能夠經過雪花算法生成id而後經過屬性將生成的id賦值進去!

Ignore

  • 還有一種狀況是有些數據咱們不能進行任何操做,那麼在反射中咱們經過註解進行獲取來進行更新數據時就須要將這些數據過濾掉。Ignore就是這個做用
Ignore ignore = declaredField.getAnnotation(Ignore.class);
if (ignore != null) {
    continue;
}
複製代碼

Query & Date & LikeQuery&OrQuery

  • 這三個都是在查詢是涉及的。後面兩個也是在Query基礎上進行擴展的
com.ay.sdksm.custom.components.expose.annation.Query queryField = declaredField.getAnnotation(com.ay.sdksm.custom.components.expose.annation.Query.class);
if (queryField != null) {
    //須要添加查詢條件
    try {
        declaredField.setAccessible(true);
        Object o = declaredField.get(dangersBook);
        if (null != o&&!"".equals(o.toString())) {
            String svalue = o.toString();
            Date dateAnnotation = declaredField.getAnnotation(Date.class);
            LikeQuery likeQuery = declaredField.getAnnotation(LikeQuery.class);
            if (dateAnnotation != null) {
                String dateValue = svalue;
                if (StringUtils.isEmpty(dateValue)) {
                    continue;
                }
                String[] dateSplit = dateValue.split(",");
                String start = dateSplit[0];
                String end = start;
                if (dateSplit.length >= 2) {
                    end = dateSplit[1];
                }
                criteria.and(declaredField.getName()).gte(start).lte(end);

            } else if(likeQuery != null){
                Pattern pattern = Pattern.compile(String.format(".*%s.*", svalue), Pattern.CASE_INSENSITIVE);
                criteria.and(declaredField.getName()).regex(pattern);
            }else {
                OrQuery orQuery = declaredField.getAnnotation(OrQuery.class);
                if (null != orQuery) {
                    String[] split = svalue.split(",");
                    String start = split[0];
                    String end = split[0];
                    if (split.length > 1) {
                        end = split[1];
                    }
                    criteria.and(declaredField.getName()).in(start, end);
                } else {
                    if (svalue.contains("$ne")&& JsonUtils.getInstance().isJson(svalue)) {
                        JSONObject jsonObject = JSONObject.parseObject(svalue);
                        String $ne = jsonObject.getString("$ne");
                        criteria.and(declaredField.getName()).ne($ne);
                    }else if(svalue.contains("$like")&& JsonUtils.getInstance().isJson(svalue)){
                        //模糊查詢
                        JSONObject jsonObject = JSONObject.parseObject(svalue);
                        String $like = jsonObject.getString("$like");
                        criteria.and(declaredField.getName()).is(String.format("/%s/",$like));
                    } else {
                        Class<?> type = declaredField.getType();
                        if (type == Long.class) {
                            criteria.and(declaredField.getName()).is(Long.valueOf(svalue));
                        } else {
                            criteria.and(declaredField.getName()).is(svalue);
                        }
                    }
                }
            }
        }
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}
複製代碼
  • 首先須要配合Query註解表示須要對字段進行條件組裝。當遇到Date咱們就須要將條件值進行定製處理咱們約定的條件值是已逗號間隔的時間段。這樣咱們就能夠動態的支持時間點、時間段的查詢。
  • 而後遇到LikeQuery表示是模糊查詢。
  • 還有部分狀況是取反查詢!總之咱們全部的需求均可以在註解Query基礎後進行擴展。上面是初期版本其中沒有通過設計表現出來就是有些if else榮譽代碼!筆者這裏也僅是展現註解的使用場景。
  • 後續或者說讀者有時間能夠本身根據設計模式中策略模式進行代碼優化就會很簡潔易懂!關於策略模式能夠參考這篇文章就夠了

DangersNo

DangersNo annotation = declaredField.getAnnotation(DangersNo.class);
if (annotation != null) {
    //根據業務生成指定格式的數據ID;這裏比較複雜。代碼省略。。。。。。
}
複製代碼

註解總結

  • 總的來講咱們能夠根據本身不一樣的業務需求開發出不一樣的註解表示不一樣的做用。而後在反射中所有同人對待!當遇到指定的註解時咱們就進行對應的業務開發!這點很適合策略模式在代碼中咱們也能夠簡化咱們的if else 。

反射應用場景

  • 上面註解的使用場景也能夠理解成是反射的使用場景。可是那個主要是說註解的。反射大可能是在框架中使用的比較多,由於框架須要高可調節性因此內部不少都是進行配置生效的。
  • 對於後端程序員來講Spring應該不會是很陌生的。在Spring中咱們常見的也是必備的兩個技能知識點是IOC+AOP。

IOC

  • IOC 依賴注入,在Spring中咱們須要哪一個對象再也不須要向傳統方式那樣New了,而是經過Spring的注入功能就能夠輕鬆獲取一個對象,這不只僅是方式的改變動是對咱們操做的簡化,咱們不在須要爲新建立的一個對象進行復雜的屬性初始化了這些都被Spring完成了。他完成的主要手段就是經過反射。在項目初始化時spring會根據反射獲取屬性並進行屬性填充!這是一個複雜的過程咱們今天僅需牢記在項目初期會經過反射進行屬性初始化!在咱們使用到類的時候就能夠直接經過類對象進行操做

AOP

  • AOP切面編程。你的項目中必定有日誌功能,在每一個接口處都須要對接口進行記錄包括入參出參已經其中耗時等基本信息。若是讓你實現是否須要在每一個地方進行開發。這種方式咱們能夠理解成埋點操做。這種方式是不可取的。由於相似日誌功能這種通用性的功能咱們沒法在每一處進行開發這非常耗費時間!
  • 在IOC的時候不只僅是經過反射初始化屬性還會生成代理對象。這個代理對象的生成過程筆者這裏是將它理解成一次反射生成的代理對象。不知道這裏理解是否正確?若是錯誤忘指出。

總結

  • 反射有的人說影響性能。這的確是影響性能,可是它提升咱們程序的靈活性。我以前說過這事一個時間和空間的問題!魚和熊掌不可兼得
  • 註解存在任何一個框架中。凡是一個成熟的框架必須有註解這樣才能提升生產力

點贊,XDM程序員

相關文章
相關標籤/搜索