簡體   English   中英

Spring AOP自定義注釋

[英]Spring AOP custom annotation

我正在嘗試實現自定義注釋和方面,它將在驗證之前將路徑變量插入請求主體。 現在它看起來像這樣......

@Aspect
@Component
public class AddParameterToFormAspect {

@Before("@annotation(addParameterToForm)")
public void addParameterToForm(JoinPoint joinPoint, AddParameterToForm addParameterToForm) {
    String form = addParameterToForm.form();
    String pathVariable = addParameterToForm.pathVariable();
    CodeSignature methodSignature = (CodeSignature) joinPoint.getSignature();
    List<String> methodParamNames = Arrays.asList(methodSignature.getParameterNames());
    int formIndex = 0;
    int pathVariableIndex = 0;

    for(String s : methodSignature.getParameterNames()) {
        if(s.equals(form)) {
            formIndex = methodParamNames.indexOf(s);
        }
        if(s.equals(pathVariable)) {
            pathVariableIndex = methodParamNames.indexOf(s);
        }
    }

    Object[] methodArgs = joinPoint.getArgs();
    Object formObject = methodArgs[formIndex];
    Field pathVariableObject;

    try {
        pathVariableObject = formObject.getClass().getDeclaredField(pathVariable);
        pathVariableObject.setAccessible(true);
        pathVariableObject.set(formObject, methodArgs[pathVariableIndex]);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

}

工作注釋的控制器示例...

@PostMapping("/test/{username}")
@AddParameterToForm(pathVariable = "username", form = "user")
public String test(@PathVariable String username, @RequestBody User user) {
    return user.getUsername();
}

控制器驗證示例不起作用......

@PostMapping("/{domainCode}")
@AddParameterToForm(pathVariable = "domainCode", form = "userAddForm")
public ResponseEntity<UserDto> saveUserForDomain(@PathVariable(name="domainCode") String domainCode, @RequestBody @Valid  final UserAddForm userAddForm, BindingResult results) {...}

添加路徑變量以形成工作但似乎@Valid不再起作用,問題可能在連接點表達式中...如何在驗證之前使其做出建議然后驗證?

@Before建議中更改方法參數並不適用。 在調用thisJoinPoint.proceed()之前,您應該使用@Around建議來更改參數。 這是因為當調用thisJoinPoint.getArgs()您獲得了基本類型參​​數的副本,您無法在before-advice中操作原始文件。 你很幸運,你想在這種情況下操縱對象類型,這就是它工作的原因。 使用around-advice可以將全新的參數傳遞給方法,或者只是操作原始對象,您可以自由選擇。

此外,您應該 - 盡可能 - 使用args()將您感興趣的方法參數綁定到通知參數,以便能夠以非神秘且類型安全的方式與它們進行交互。 創建局部變量並為其分配一些值不會影響相同類型的方法參數。 為什么要這樣?

如果這個解釋不夠全面,請隨時提出后續問題。 然后我也可以為你添加一些示例代碼。


問題編輯后更新:

在仔細檢查了您的代碼之后,除了我今天早些時候在您的問題中的評論中的評論之外,忽略了方面代碼的內容,您的實際問題是在方法之前執行了@Valid注釋的驗證檢查原因被執行。 即所驗證的不是方面完成其工作(填充目標對象中的成員字段)之后的狀態,而是方面運行之前的狀態。 這實際上是這個問題中討論的問題 ,另見M. Deinum和我的建議如何解決它:

  • 也許你想通過LTW(加載時編織)嘗試完整的AspectJ ,看看是否有一個call()切入點而不是Spring AOP使用的隱式execution()切入點解決了這個問題。 您將編織到調用代碼(方法調用)而不是被調用者(方法執行)本身。 有可能在執行驗證之前發生這種情況。

  • 更像Spring的解決方法是使用Spring攔截器(M. Deinum提到HandlerInterceptor )而不是方面。 其他人也有一個示例鏈接。

話雖如此,我仍然建議重構您的代碼,以免在方法參數名稱或類成員名稱上使用反射和匹配字符串。 我認為您還可以通過將方法參數的切入點與@RequestBody@PathVariable注釋相匹配來擺脫自定義注釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM