Spring MVC 测试和 AOP:周围的建议没有按照 rest 控制器的预期执行(仅针对无效数据)
Spring MVC Test & AOP: Around advice is not executed how is expected for rest controller (just for invalid data)
我正在与
合作
- Spring 框架 4.3.3
- AspectJ 1.8.9
我有两个 @Controllers
,一个用于 mvc
,另一个用于 rest
。每一个使用如何依赖一个@Service
。
我有以下的休息方法
package com.manuel.jordan.controller.persona;
@Controller
@RequestMapping(value="/personas")
public class PersonaRestController {
@PutMapping(value="/{id}", consumes={MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<Void> updateOne(@PathVariable String id, @Validated @RequestBody Persona persona){
persona = personaService.updateOne(persona);
return ResponseEntity.noContent().build();
}
观察我使用的第二个参数@Validated
我有以下切入点:
@Pointcut(value=
"execution(* com.manuel.jordan.controller.persona.PersonaRestController.updateOne(..))")
public void updateOnePointcut(){}
以及以下 Around Advice:
@Around(value="PersonaRestControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={Some exceptions})
public Object aroundAdviceUpdateOne(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
logger.info("Beginning aroundAdviceUpdateOne - Class: {}, Method: {}",
proceedingJoinPoint.getTarget().getClass().getSimpleName(),
proceedingJoinPoint.getSignature().getName());
....
}
通过Spring MVC Test
当我发送有效数据时:
如:
resultActions = mockMvc.perform(put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.content(JsonTransformerSupport.objectToJson(personaValid))).andDo(print());
或
RequestEntity<Persona> requestEntity = RequestEntity.put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.body(personaValid);
通过 Gradle
报告,我可以确认 @Around
建议的效果符合预期。它只是观察报告中的 Beginning aroundAdviceUpdateOne - Class ....
文本,建议正文的其余部分如何按预期工作。
问题是当我通过@Validated
发送无效数据进行测试时
使用上面显示的两种方式,但只是将 personaValid
更改为 personaInvalid
(空字段,打破最小和最大边界等)我确实意识到 @Around
建议总是忽略。它确认 Beginning aroundAdviceUpdateOne - Class ....
never 出现。
注意:即使 @Around
建议不起作用,验证过程也会发生。我的意思是,有 none 个例外。 @Test
方法通过。
这里有一些注意事项。
- 我的行为与
@Before
的建议相同。
- 我假设在执行
PersonaRestController.updateOne
方法@Around
(甚至@Before
) 建议必须发挥作用。不管数据是否有效。
- 当我向 非 休息控制器
发送有效或无效数据时,我的这个场景完全有效
那个方法是:
@PutMapping(value="/update/{id}",
consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces=MediaType.TEXT_HTML_VALUE)
public String updateOne(@PathVariable String id,
@Validated @ModelAttribute Persona persona,
BindingResult result,
RedirectAttributes redirectAttributes){
相同 @Around
建议有效,只是有以下变化(注意 ||
):
@Around(value="PersonaRestControllerPointcut.updateOnePointcut() || PersonaControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={some exceptions })
public Object aroundAdviceUpdateOne(JoinPoint proceedingJoinPoint) throws Throwable {
更新 01
因此 @Around
建议应该起作用的 4 种情况:
- 具有有效数据的非 rest 方法(有效)
- 具有无效数据的非 rest 方法(有效)
- 具有有效数据的 rest 方法(有效)
- 具有无效数据的 rest 方法(失败或被忽略 -
@Around
不执行)
同样:@Validated
对休息和非休息方法的预期工作方式。 问题是关于@Around
建议的,它不起作用当 Rest
方法只是在无效数据时执行已发送。怎么了?还是失踪了?
更新 02
@Validated
是:
Variant of JSR-303's Valid, supporting the specification of validation
groups. Designed for convenient use with Spring's JSR-303 support but
not JSR-303 specific
它来自它的 API
似乎不是 AOP
注释。只是一个 Spring 注释。我的 @Pointcut
不关心或检查注释。它使用 updateOne(..)
更新 03
连加
@Aspect
@Component
@Transactional
@Order(0)
class PersonaRestControllerAspect {
没有按预期工作。
更新 04
我有
@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
@Override
public Validator getValidator() {
return validatorConfig.localValidatorFactoryBean();
}
...
Validator
的来源:
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(){
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(rrbms);
return localValidatorFactoryBean;
}
rrbms
是一个加载许多 .properties
文件的 ReloadableResourceBundleMessageSource
实例,其中之一是 "classpath:/com/manuel/jordan/validation/validation"
.
这是预期的行为。如果您使用 @Validated
而没有附带 BindingResult
参数,则永远不会调用该方法。如果数据无效,则会出现异常。毕竟这就是验证的全部意义所在。如果不调用该方法,那么你的建议也不会被执行。
我正在与
合作- Spring 框架 4.3.3
- AspectJ 1.8.9
我有两个 @Controllers
,一个用于 mvc
,另一个用于 rest
。每一个使用如何依赖一个@Service
。
我有以下的休息方法
package com.manuel.jordan.controller.persona;
@Controller
@RequestMapping(value="/personas")
public class PersonaRestController {
@PutMapping(value="/{id}", consumes={MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<Void> updateOne(@PathVariable String id, @Validated @RequestBody Persona persona){
persona = personaService.updateOne(persona);
return ResponseEntity.noContent().build();
}
观察我使用的第二个参数@Validated
我有以下切入点:
@Pointcut(value=
"execution(* com.manuel.jordan.controller.persona.PersonaRestController.updateOne(..))")
public void updateOnePointcut(){}
以及以下 Around Advice:
@Around(value="PersonaRestControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={Some exceptions})
public Object aroundAdviceUpdateOne(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
logger.info("Beginning aroundAdviceUpdateOne - Class: {}, Method: {}",
proceedingJoinPoint.getTarget().getClass().getSimpleName(),
proceedingJoinPoint.getSignature().getName());
....
}
通过Spring MVC Test
当我发送有效数据时:
如:
resultActions = mockMvc.perform(put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.content(JsonTransformerSupport.objectToJson(personaValid))).andDo(print());
或
RequestEntity<Persona> requestEntity = RequestEntity.put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.body(personaValid);
通过 Gradle
报告,我可以确认 @Around
建议的效果符合预期。它只是观察报告中的 Beginning aroundAdviceUpdateOne - Class ....
文本,建议正文的其余部分如何按预期工作。
问题是当我通过@Validated
使用上面显示的两种方式,但只是将 personaValid
更改为 personaInvalid
(空字段,打破最小和最大边界等)我确实意识到 @Around
建议总是忽略。它确认 Beginning aroundAdviceUpdateOne - Class ....
never 出现。
注意:即使 @Around
建议不起作用,验证过程也会发生。我的意思是,有 none 个例外。 @Test
方法通过。
这里有一些注意事项。
- 我的行为与
@Before
的建议相同。 - 我假设在执行
PersonaRestController.updateOne
方法@Around
(甚至@Before
) 建议必须发挥作用。不管数据是否有效。 - 当我向 非 休息控制器 发送有效或无效数据时,我的这个场景完全有效
那个方法是:
@PutMapping(value="/update/{id}",
consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces=MediaType.TEXT_HTML_VALUE)
public String updateOne(@PathVariable String id,
@Validated @ModelAttribute Persona persona,
BindingResult result,
RedirectAttributes redirectAttributes){
相同 @Around
建议有效,只是有以下变化(注意 ||
):
@Around(value="PersonaRestControllerPointcut.updateOnePointcut() || PersonaControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={some exceptions })
public Object aroundAdviceUpdateOne(JoinPoint proceedingJoinPoint) throws Throwable {
更新 01
因此 @Around
建议应该起作用的 4 种情况:
- 具有有效数据的非 rest 方法(有效)
- 具有无效数据的非 rest 方法(有效)
- 具有有效数据的 rest 方法(有效)
- 具有无效数据的 rest 方法(失败或被忽略 -
@Around
不执行)
同样:@Validated
对休息和非休息方法的预期工作方式。 问题是关于@Around
建议的,它不起作用当 Rest
方法只是在无效数据时执行已发送。怎么了?还是失踪了?
更新 02
@Validated
是:
Variant of JSR-303's Valid, supporting the specification of validation groups. Designed for convenient use with Spring's JSR-303 support but not JSR-303 specific
它来自它的 API
似乎不是 AOP
注释。只是一个 Spring 注释。我的 @Pointcut
不关心或检查注释。它使用 updateOne(..)
更新 03
连加
@Aspect
@Component
@Transactional
@Order(0)
class PersonaRestControllerAspect {
没有按预期工作。
更新 04
我有
@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
@Override
public Validator getValidator() {
return validatorConfig.localValidatorFactoryBean();
}
...
Validator
的来源:
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(){
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(rrbms);
return localValidatorFactoryBean;
}
rrbms
是一个加载许多 .properties
文件的 ReloadableResourceBundleMessageSource
实例,其中之一是 "classpath:/com/manuel/jordan/validation/validation"
.
这是预期的行为。如果您使用 @Validated
而没有附带 BindingResult
参数,则永远不会调用该方法。如果数据无效,则会出现异常。毕竟这就是验证的全部意义所在。如果不调用该方法,那么你的建议也不会被执行。