[英]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.