手動通過,java通過反射和自定義註解實現後台參數值的驗證

首先關於反射的知識就不說了因為網上的資源實在是太多了,註解的基本知識也不說了,網上同樣有很多,好像都是廢話,咱們迴歸正題,今天的內容是通過自定義註解和反射實現參數值的自動驗證,那麼我們為什麼要做這個驗證呢?其實我們前端會驗證,數據庫也會驗證,那麼我們為什麼還要在後臺代碼中驗證呢?個人認為這是一個嚴謹的問題,首先前端是可以驗證,但是如果前端安全驗證做的不好,那麼你的數據接口會被人分析抓取,當然如果你用的是velocity/jsp/freemaker等一些模板引擎的話是沒法抓取接口的,這時候你的接口被抓我就可通過模擬你的接口參數隨便提交數據了。這時候有些參數可能不是在接口裡攜帶,這個參數就可以從session中獲取,這樣可以避免直接訪問數據接口被竊取。數據庫的話比如建表時如果設置了主外鍵不為空最大長度類型等,寫入數據時數據表也會報錯。那麼這個算起來的話也算有兩次驗證了,我們為什麼還要在代碼裡進行驗證呢,個人認為第一,還是那句話嚴謹,要不然這就是bug,哈哈,第二,雖然前端和數據庫算是兩次驗證,但是這樣的驗證不安全,比如有人寫一段注入攻擊的js代碼提交,第三,這裡的驗證可以減少數據庫的交互壓力……

那麼問題來了,我們為什麼要“手動通過java通過反射和自定義註解實現後臺參數值的驗證”?,個人原因,第一,為了少寫代碼,第二,為了能夠學習一些知識,第三,就像裝會兒逼,當然這也不是多厲害的技術。那麼進入正題,以前我們是怎麼驗證的呢?

 1、struts2的valid可以通過配置xml,xml中描述規則和返回的信息,這種方式比較麻煩、開發效率低,不推薦

2、validation bean 是基於JSR-303標準開發出來的,使用註解方式實現,及其方便,但是這只是一個接口,沒有具體實現.Hibernate Validator是一個hibernate獨立的包,可以直接引用,他實現了validation bean同時有做了擴展,比較強大 ,實現圖如下:

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

點此查看中文官方手冊

3、oval 是一個可擴展的Java對象數據驗證框架,驗證的規則可以通過配置文件、Annotation、POJOs 進行設定。可以使用純 Java 語言、JavaScript 、Groovy 、BeanShell 等進行規則的編寫,本次不過多講解

4、 Springboot validator實際集成了Hibernatevalidator。主要是校驗用戶提交的數據的合理性的,比如是否為空了,密碼長度是否大於6位,是否是純數字的,等等。方便後臺的數據合法性的校驗。

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

代碼基本都長這樣

那麼一下咱們自己實現一下這個東東


1.第一,創建自定義註解,如下圖,咱們先做一個email驗證的,其他的基本步驟都一樣,舉一反三啦

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

2.第二,編寫驗證的反射類

/**

* 註解驗證方法

*

* @param bean 驗證的實體

* @return

*/

@SuppressWarnings("unchecked")

public static Map validate(Object bean) {

Map result = new HashMap();

result.put("message", "驗證通過");

result.put("result", true);

Class> cls = bean.getClass();

// 檢測field是否存在

try {

// 獲取實體字段集合

Field[] fields = cls.getDeclaredFields();

for (Field f : fields) {

// 通過反射獲取該屬性對應的值

f.setAccessible(true);

// 獲取字段值

Object value = f.get(bean);

// 獲取字段上的註解集合

Annotation[] arrayAno = f.getAnnotations();

for (Annotation annotation : arrayAno) {

// 獲取註解類型(註解類的Class)

Class> clazz = annotation.annotationType();

// 獲取註解類中的方法集合

Method[] methodArray = clazz.getDeclaredMethods();

for (Method method : methodArray) {

// 獲取方法名

String methodName = method.getName();

// 過濾錯誤提示方法的調用

if(methodName.equals("message")) {

continue;

}

// 初始化註解驗證的方法處理類 (我的處理方法卸載本類中)

Object obj = ValidateUtil.class.newInstance();

// 獲取方法

try {

// 根據方法名獲取該方法

Method m = obj.getClass().getDeclaredMethod(methodName, Object.class, Field.class);

// 調用該方法

result = (Map)m.invoke(obj, value, f);

/* 驗證結果 有一處失敗則退出 */

if(result.get("result").equals(false)) {

result.put(f.getName(), value);

return result;

}

} catch (Exception e) {

e.printStackTrace();

log.info("找不到該方法:"+methodName);

}

}

}

}

} catch (Exception e) {

e.printStackTrace();

log.info("驗證出錯");

}

return result;

}

3.第三我們編寫驗證方法,這裡我用一個正則來實現

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

4.編寫一個實體類,用於驗證,這裡是測試我們隨便寫

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

5.我們直接在main函數中進行測試。

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

6.輸出結果,我傳的是手機號,所以驗證失敗了

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

那麼這個流程就算完了,那麼現在這個是最簡單的一個驗證,完了之後我們還可以擴展很多出來,比如我們要封裝一個mvc框架,我們可以在controller層實現參數的接收封裝,參數驗證如下圖

手動通過,java通過反射和自定義註解實現後臺參數值的驗證

這樣就可以實現參數自動接受封裝和驗證,當然通過註解和反射也可以做其他事情如,路由映射,權限驗證,xss攻擊過濾,數據處理,實現aop,數據表結構實體映射等等,大家自己動手試試吧


分享到:


相關文章: