当前位置: 首页 > news >正文

南安建设局网站wordpress英文模版

南安建设局网站,wordpress英文模版,中国最大的手表网站,企业为什么建立企业网站1 概述通过上一篇了解请求和响应的流程,Spring在设计上留了不少扩展点。里面通过查找接口的方式获取的地方,都可以成为一种扩展点,因为只要实现这类接口就可以成为Spring加载的一部分。本文了解一下这些扩展点,方便后面进行扩展。…

1 概述

通过上一篇了解请求和响应的流程,Spring在设计上留了不少扩展点。里面通过查找接口的方式获取的地方,都可以成为一种扩展点,因为只要实现这类接口就可以成为Spring加载的一部分。本文了解一下这些扩展点,方便后面进行扩展。

2 原理

2.1 HandleInterceptor的扩展点

加载HandleInterceptor的方法getInterceptors是在各个HandlerMapping初始化的时候调用的,该方法的调用会加载所有实现了WebMvcConfigurer接口的类,通过WebMvcConfigurer提供的addInterceptors()可以自定义增加HandleInterceptor:

// 继承关系:EnableWebMvcConfiguration < DelegatingWebMvcConfiguration < WebMvcConfigurationSupport
// EnableWebMvcConfiguration在开启WebMvc后由Spring触发加载
// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
protected final Object[] getInterceptors(FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {if (this.interceptors == null) {InterceptorRegistry registry = new InterceptorRegistry();// 加载自定义HandleInterceptor,自定义的Interceptor在最前面addInterceptors(registry);registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));this.interceptors = registry.getInterceptors();}return this.interceptors.toArray();
}
// 源码位置:org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
protected void addInterceptors(InterceptorRegistry registry) {// configurers为WebMvcConfigurerCompositethis.configurers.addInterceptors(registry);
}
// org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite
public void addInterceptors(InterceptorRegistry registry) {// delegates里注入了所有实现了WebMvcConfigurer接口的类,// 也就是说如果希望自定义一个HandlerInterceptor,则可以通过实现WebMvcConfigurer接口来完成for (WebMvcConfigurer delegate : this.delegates) {delegate.addInterceptors(registry);}
}

2.2 HandlerMethodArgumentResolver扩展点

在初始化RequestMappingHandlerAdapter的时候,就把实现WebMvcConfigurer接口来增加的HandlerMethodArgumentResolver存放到了RequestMappingHandlerAdapter,在RequestMappingHandlerAdapter执行afterPropertiesSet()的时候,再把自定义的HandlerMethodArgumentResolver和默认的一起加到argumentResolvers中:

// RequestMappingHandlerAdapter初始化后,触发afterPropertiesSet()方法,在里面初始化HandlerMethodArgumentResolver
// 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers == null) {// 加载默认的HandlerMethodArgumentResolverList<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);// 创建了二十多个HandlerMethodArgumentResolverresolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ServletModelAttributeMethodProcessor(false));resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));resolvers.add(new RequestHeaderMapMethodArgumentResolver());resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new SessionAttributeMethodArgumentResolver());resolvers.add(new RequestAttributeMethodArgumentResolver());resolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());resolvers.add(new MapMethodProcessor());resolvers.add(new ErrorsMethodArgumentResolver());resolvers.add(new SessionStatusMethodArgumentResolver());resolvers.add(new UriComponentsBuilderMethodArgumentResolver());if (KotlinDetector.isKotlinPresent()) {resolvers.add(new ContinuationHandlerMethodArgumentResolver());}// 加载自定义的HandlerMethodArgumentResolver,注意自定义的Resolver是在中间偏后的位置if (getCustomArgumentResolvers() != null) {resolvers.addAll(getCustomArgumentResolvers());}resolvers.add(new PrincipalMethodArgumentResolver());resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));resolvers.add(new ServletModelAttributeMethodProcessor(true));return resolvers;
}
public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {// 自定义的HandlerMethodArgumentResolver是在之前赋值的return this.customArgumentResolvers;
}// 源码位置:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcValidator") Validator validator) {// 父类为WebMvcConfigurationSupportRequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());return adapter;
}// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
@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));// 设置自定义的HandlerMethodArgumentResolveradapter.setCustomArgumentResolvers(getArgumentResolvers());adapter.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();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;
}
protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {if (this.argumentResolvers == null) {this.argumentResolvers = new ArrayList<>();// addArgumentResolvers()接口由DelegatingWebMvcConfiguration实现addArgumentResolvers(this.argumentResolvers);}return this.argumentResolvers;
}// 源码位置:org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// configurers为WebMvcConfigurerCompositethis.configurers.addArgumentResolvers(argumentResolvers);
}// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// delegates里注入了所有实现了WebMvcConfigurer接口的类,// 也就是说如果希望自定义一个HandlerMethodArgumentResolver,则可以通过实现WebMvcConfigurer接口来完成for (WebMvcConfigurer delegate : this.delegates) {delegate.addArgumentResolvers(argumentResolvers);}
}

2.3 RequestMappingHandlerAdapter的扩展点

在初始化RequestMappingHandlerAdapter的时候,就把实现WebMvcConfigurer接口来增加的HandlerMethodReturnValueHandler存放到了RequestMappingHandlerAdapter,在RequestMappingHandlerAdapter执行afterPropertiesSet()的时候,再把自定义的HandlerMethodReturnValueHandler和默认的一起加到returnValueHandlers中:

// RequestMappingHandlerAdapter初始化后,触发afterPropertiesSet()方法,在里面初始化HandlerMethodReturnValueHandler
// 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {// 加载默认的HandlerMethodReturnValueHandlerList<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);handlers.add(new ModelAndViewMethodReturnValueHandler());handlers.add(new ModelMethodProcessor());handlers.add(new ViewMethodReturnValueHandler());handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));handlers.add(new StreamingResponseBodyReturnValueHandler());handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));handlers.add(new HttpHeadersReturnValueHandler());handlers.add(new CallableMethodReturnValueHandler());handlers.add(new DeferredResultMethodReturnValueHandler());handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));handlers.add(new ServletModelAttributeMethodProcessor(false));handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));handlers.add(new ViewNameMethodReturnValueHandler());handlers.add(new MapMethodProcessor());// 加载自定义的HandlerMethodReturnValueHandler,注意自定义的Handler是在中间偏后的位置if (getCustomReturnValueHandlers() != null) {handlers.addAll(getCustomReturnValueHandlers());}if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));}else {handlers.add(new ServletModelAttributeMethodProcessor(true));}return handlers;
}
public List<HandlerMethodReturnValueHandler> getCustomReturnValueHandlers() {// 自定义的HandlerMethodReturnValueHandler是在之前赋值的return this.customReturnValueHandlers;
}// 初始化RequestMappingHandlerAdapter的时候,加载自定义的HandlerMethodReturnValueHandler
// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
@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());// 设置自定义的RequestMappingHandlerAdapteradapter.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();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;
}
protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {if (this.returnValueHandlers == null) {this.returnValueHandlers = new ArrayList<>();// addReturnValueHandlers()接口由DelegatingWebMvcConfiguration实现addReturnValueHandlers(this.returnValueHandlers);}return this.returnValueHandlers;
}// 源码位置:org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {// configurers为WebMvcConfigurerCompositethis.configurers.addReturnValueHandlers(returnValueHandlers);
}// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {for (WebMvcConfigurer delegate : this.delegates) {// delegates里注入了所有实现了WebMvcConfigurer接口的类,// 也就是说如果希望自定义一个RequestMappingHandlerAdapter,则可以通过实现WebMvcConfigurer接口来完成delegate.addReturnValueHandlers(returnValueHandlers);}
}

2.4 MessageConverter的扩展点

在初始化RequestMappingHandlerAdapter的时候,就把实现WebMvcConfigurer接口来增加的MessageConverter存放到了RequestMappingHandlerAdapter,在RequestMappingHandlerAdapter执行afterPropertiesSet()的时候,再把自定义的MessageConverter加到messageConverters中:

// RequestMappingHandlerAdapter初始化后,触发afterPropertiesSet()方法,在里面初始化HandlerMethodReturnValueHandler
// 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {// 加载默认的HandlerMethodReturnValueHandlerList<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);handlers.add(new ModelAndViewMethodReturnValueHandler());handlers.add(new ModelMethodProcessor());handlers.add(new ViewMethodReturnValueHandler());// 有设置MessageConverterhandlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));handlers.add(new StreamingResponseBodyReturnValueHandler());// 有设置MessageConverterhandlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));handlers.add(new HttpHeadersReturnValueHandler());handlers.add(new CallableMethodReturnValueHandler());handlers.add(new DeferredResultMethodReturnValueHandler());handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));handlers.add(new ServletModelAttributeMethodProcessor(false));// 有设置MessageConverterhandlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));handlers.add(new ViewNameMethodReturnValueHandler());handlers.add(new MapMethodProcessor());if (getCustomReturnValueHandlers() != null) {handlers.addAll(getCustomReturnValueHandlers());}if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));}else {handlers.add(new ServletModelAttributeMethodProcessor(true));}return handlers;
}
public List<HttpMessageConverter<?>> getMessageConverters() {// 自定义的MessageConverter是在之前赋值的return this.messageConverters;
}// 初始化RequestMappingHandlerAdapter的时候,加载自定义的MessageConverter
// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcValidator") Validator validator) {RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();adapter.setContentNegotiationManager(contentNegotiationManager);// 设置自定义的MessageConverteradapter.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 = getAsyncSupportConfigurer();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;
}
protected final List<HttpMessageConverter<?>> getMessageConverters() {if (this.messageConverters == null) {this.messageConverters = new ArrayList<>();// 配置自定义的MessageConverterconfigureMessageConverters(this.messageConverters);if (this.messageConverters.isEmpty()) {addDefaultHttpMessageConverters(this.messageConverters);}extendMessageConverters(this.messageConverters);}return this.messageConverters;
}// 源码位置:org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// configurers为WebMvcConfigurerCompositethis.configurers.configureMessageConverters(converters);
}// 源码位置:org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {for (WebMvcConfigurer delegate : this.delegates) {// delegates里注入了所有实现了WebMvcConfigurer接口的类,// 也就是说如果希望自定义一个MessageConverter,则可以通过实现WebMvcConfigurer接口来完成delegate.configureMessageConverters(converters);}
}

3 架构一小步

  • Controller接口处理前后要预先或者做后处理时用HandleInterceptor扩展。
  • Controller接口处理特殊参数的时候用HandlerMethodArgumentResolver扩展。
  • 请求返回值格式处理可以通过MessageConverter扩展。
  • 整个请求的处理如果需要替换则用RequestMappingHandlerAdapter扩展,这个除非有特殊请求,否则不推荐。
上面这些扩展都通过继承WebMvcConfigurer来增加扩展类。
http://www.dtcms.com/a/458648.html

相关文章:

  • leaflow 部署openlist 部署教程
  • 成都网站空间创新互联网站建设与管理维护的答案李建青
  • photoprism开源去中心化网络的 AI 照片应用
  • 如何在记事本中做网站链接教务处网站建设方案
  • 管理系统网站模板下载上海国家企业信用网
  • 网站怎么优化关键词南京网站设计公司哪儿济南兴田德润怎么联系
  • 博白建设局网站游戏网站logo制作
  • Linux 命令:readlink
  • 三亚建设局网站网站建设上传视频教程
  • 怎样自己建设一个网站济南建设工程信息网官网
  • 买别人做的网站能盗回吗网站建设国家有补贴吗
  • 企业网站的公司和产品信息的介绍与网络营销关系wordpress使用教程书
  • 出版社网站建设方案宁波seo优化项目
  • 自建站电商外贸网站后台fpt
  • 上海医疗 网站制作建设工程人员押证在哪个网站查
  • 吴恩达机器学习课程(PyTorch 适配)学习笔记:3.1 无监督学习基础
  • 做移动类网站的书推荐2014个人网站备案
  • Trea国际版|海外版下载
  • 宝德科技专业嘉兴网站建设网站姐姐做床戏网站
  • 河池公司做网站最近在线观看免费完整版高清电影
  • 网站开发代理江苏如可建设淘宝链接网站
  • 长治网站运营百度seo学院
  • 如何在百度里建网站国内免备案
  • 中华山河诗卷:省域经纬,城乡弦歌
  • 响应式模板网站建设哪家好wordpress 底部友情链接
  • 深圳网站建设10强网站托管共享服务器费用一年多少钱
  • 中小企业建网站哪个好seo外链网站大全
  • 网站开发财务费用广东网站建设系统怎么样
  • cubemx f103c8t6 串口一 DMA 简单配置和实现
  • 哈尔滨专业做网站公司wordpress 是免费的嘛