SpringMVC自定义注解实现接口调用

环境:springboot2.2.10.RELEASE


开发步骤:

  1. 自定义的注解类
@Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomEndpoint {
}

@CustomEndpoint注解标识自定义的类(Bean)在该注解中添加了@Component注解为了让容器管理我们的类(生成Bean)。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackMapping {
	// 请求URL
	String[] value() default {};
	// 请求的方法
	RequestMethod[] method() default {};
}

该注解就相当于@RequestMapping注解,定义请求接口。

  1. 自定义HandlerMapping

自定义HandlerMapping的作用是让HandlerMapping与我们自定义的@CustomEndpoint类相关联,简单说就是能够处理标有@CustomEndpoint注解的类。

public class CustomPackRequestHandlerMapping extends RequestMappingHandlerMapping {

  // 该方法是必须重写的,使得自定义的HandlerMapping能够处理标有@CustomEndpoint注解的类
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return AnnotatedElementUtils.hasAnnotation(beanType, CustomEndpoint.class);
	}
	
  // 该方法也必须重写不然你的这个自定义HandlerMapping将轮不到就被(SimpleUrlHandlerMapping)处理了。
	@Override
    public void afterPropertiesSet() {
        super.setOrder(0); // 这里很重要使得我们的HandlerMapping能够排到最前面
        super.afterPropertiesSet();
    }
	
  // 该方法必须重写因为你要针对标有自定义@PackMapping注解的方法能够处理你的请求。
	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo requestMappingInfo = createRequestMappingInfo(method) ;
		return requestMappingInfo ;
	}
	
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		PackMapping packMapping = AnnotatedElementUtils.findMergedAnnotation(element, PackMapping.class);
		return (packMapping != null ? builderMapping(packMapping) : null);
	}
	
	private RequestMappingInfo builderMapping(PackMapping packMapping) {
		RequestMappingInfo.Builder builder = RequestMappingInfo
				.paths(packMapping.value())
				.methods(packMapping.method())
				.params(new String[] {})
				.headers(new String[] {})
				.consumes(new String[] {})
				.produces(new String[] {})
				.mappingName("") ;
		return builder.build() ;
	}

}

以上自定义的HandlerMapping重要的方法已经说明了。

  1. 配置HandlerMapping
@Configuration
public class CustomEndpointConfig {
	
	@Bean
	public CustomPackRequestHandlerMapping customPackRequestHandlerMapping() {
		CustomPackRequestHandlerMapping handlerMapping = new CustomPackRequestHandlerMapping() ;
		return handlerMapping ;
	}
	
}
  1. 测试
@CustomEndpoint
@ResponseBody
public class CustomWebController {

	@PackMapping("/custom/index")
	public Object index(String key) {
		return key ;
	}
	
}

 

SpringMVC自定义注解实现接口调用

 

到此开发一个自定义的HandlerMapping就完成了。

真正实际的调用(Controller方法)其实是HandlerAdapter。


AbstractHandlerMethodAdapter类中定义了如下方法,是专门为让子类来实现的,我们可以根据自己的需要作相应的重写。

protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

查看
RequestMappingHandlerAdapter类的实现。

@Override
	protected boolean supportsInternal(HandlerMethod handlerMethod) {
		return true;
	}

这里在说下一些核心类之间的关系:

所有的拦截器也是与HandlerMapping关联的:

@Bean
	@SuppressWarnings("deprecation")
	public RequestMappingHandlerMapping requestMappingHandlerMapping(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setContentNegotiationManager(contentNegotiationManager);
		mapping.setCorsConfigurations(getCorsConfigurations());

		...

		return mapping;
	}

mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));

消息转换与HandlerAdapter相关联

@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcValidator") Validator validator) {

		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
		adapter.setContentNegotiationManager(contentNegotiationManager);
		adapter.setMessageConverters(getMessageConverters());
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

		if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}

		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

		return adapter;
	}

adapter.setMessageConverters(getMessageConverters());

 

好心人给个关注+转发谢谢啊

SpringBoot项目查看线上日志

 

SpringBoot项目查看线上日志

 

SpringBoot项目查看线上日志

 

SpringBoot项目查看线上日志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值