Spring中关于@ModelAttribute用于注解请求方法参数的问题

Spring中关于@ModelAttribute用于注解请求方法参数的问题,第1张

@ModelAttribute可以用于注解方法参数

@ModelAttribute可以用于注解方法和参数。

1、注解Controller中的方法时,返回的参数是一个属性值,@ModelAttribute注解的方法在Controller中每个URL处理方法调用之前,都会按照先后顺序执行。

2、注解Controller方法的参数,用于从model、Form表单或者URL请求参数中获取属性值。

例子如下,已在Spring30中验证通过。

@Controller

public class TestAction {

/---------------------@ModelAttribute注解一个方法---------------------/

/方法返回值为:void,没有什么意义/

@ModelAttribute

public void populateModel(ModelMap model) {

Systemoutprintln("---populateModel---");

modeladdAttribute("attributeName", "111");

}

/不指定指定属性名称,方法返回一个对象,相当于modeladdAttribute("user", user)/

@ModelAttribute

public User addUser() {

Systemoutprintln("---addUser---");

User user = new User();

usersetId(1);

usersetUsername("alan");

usersetPassword("1234");

return user;

}

/指定属性名称,方法返回一个字符串,相当于modeladdAttribute("string1-key", "string1-value")/

@ModelAttribute("string1-key")

public String addString() {

Systemoutprintln("---addString---");

return "string1-value";

}

/返回一个model属性,而不是视图名称/

@RequestMapping(value = "helloWorld1")

@ModelAttribute("attributeName")

public String helloWorld1() {

Systemoutprintln("---helloWorld1---");

return "hi";

}

/---------------------@ModelAttribute注解方法的参数---------------------/

/从模型中获取一个属性值,将其转换到对应类型的变量中/

@RequestMapping(value = "helloWorld")

public String helloWorld(@ModelAttribute("user") User user,

@ModelAttribute("attributeName") String aName,

@ModelAttribute("string1-value") String svalue) {

Systemoutprintln("---helloWorld---"+usergetUsername()+", "+usergetPassword());

Systemoutprintln("aName="+aName+", svalue="+svalue);

return "helloWorld";

}

/从Form表单或者URL参数中获取属性参数值,放到对应类型的参数中,注意:此时表单中的组件名和参数属性名称一致,如User对象有两个属性,分别为username,password,则表单中input的名称必须为username,password,才能实现属性值注入。

注意这个User类必须要有无参数的构造函数或者是setter方法

此时@ModelAttribute可以不用显式写/

@RequestMapping(value = "helloWorld2")

public String helloWorld2(@ModelAttribute("user") User user) {

Systemoutprintln("---helloWorld---"+usergetUsername()+", "+usergetPassword());

return "helloWorld";

}

}

注解:

该注解主要是用于rest风格的搭配使用,在请求路径中不再以k : v的形式给出请求参数与值;而是直接给定一个值。如果方法参数是一个Map<String, String>将会包含路径中所有的变量与值。

访问 :浏览器输入路径变量即可,以下是rest风格的get请求的展示,直接在地址栏发起请求就是一个get请求

获取所有访问路径上的请求参数:localhost:8080/ car/{id}/owner/{username}age=19&inters=

该注解主要用于获取请求头header中的数据,客户端请求之后可以拿到一些头部携带的参数。支持传统的SpringMVC,也支持WebFlux响应式。如果方法参数是一个Map<String, String>将会包含所有的请求头与值

测试:

主要用于获取请求参数名称,设置参数是否可有可无以及默认值。

@RequestParam注解详解地址: blogcsdnnet/weixin_4380 …

主要用于获取Cookie值

主要用在 请求转发 时,如果页面无法直接跳转(如WEB-INF下的success页面)可以使用转发的手段。当进行转发时可以在请求中携带上请求的参数,转发会携带上一次请求的参数(一次完整的请求包括转发)

由于是同一次请求,因此也可以直接拿到原生的>

此处的method可以取两个值,一个是RequestMethodGET,一个是RequestMethodPOST,

这样写的话你应该就能够看出是什么意思了把,就是请求该方法使用的模式,是get还是post

众所周知, spring 从 25 版本以后开始支持使用注解代替繁琐的 xml 配置,到了 springboot 更是全面拥抱了注解式配置。平时在使用的时候,点开一些常见的等注解,会发现往往在一个注解上总会出现一些其他的注解,比如 @Service :

大部分情况下,我们可以将 @Service 注解等同于 @Component 注解使用,则是因为 spring 基于其 JDK 对 元注解的机制 进行了扩展。

在 java 中,元注解是指可以注解在其他注解上的注解,spring 中通过对这个机制进行了扩展,实现了一些原生 JDK 不支持的功能,比如允许在注解中让两个属性互为别名,或者将一个带有元注解的子注解直接作为元注解看待,或者在这个基础上,通过 @AliasFor 或者同名策略让子注解的值覆盖元注解的值。

本文将基于 spring 源码 52x 分支,解析 spring 如何实现这套功能的。

这是系列的第三篇文章,将详细介绍 Spring 是如何在经过搜索与属性映射后,将处理后的注解合成为合并注解的。

相关文章:

我们在前文了解用于搜索注解的合并注解聚合 MergedAnnotations 与用于完成注解属性映射的 AnnotationTypeMappings 和 AnnotationTypeMapping ,现在我们需要知道在 MergedAnnotations 这个容器中, AnnotationTypeMappings 和 AnnotationTypeMapping 是如何转为一个我们所需要的合并注解 MergedAnnotation 的。

与前文一样,我们以 AnnotatedElementUtilsfindMergedAnnotations 方法作为入口:

我们在上文顺着 MergedAnnotationsget 一路找到 TypeMappedAnnotationsMergedAnnotationFinder 的 process 方法,在这里我们目睹了一个普通的注解的元注解被解析为 AnnotationTypeMappings 与 AnnotationTypeMapping 的过程:

该方法是 AnnotationTypeMapping 转为 MergedAnnotation 的关键。

TypeMappedAnnotation 是 MergedAnnotation 一个通用实现,在大部分情况下,我们所说的合并注解其实指的就是这个类。

通过它的构造方法我们得以了解其创建过程:

可以看得出, TypeMappedAnnotation 基本可以认为是 AnnotationTypeMapping 的包装类,它以一个 AnnotationTypeMapping 实例作为数据源,从而提供一些关于映射后的属性的相关功能。

回到 AnnotatedElementUtilsfindMergedAnnotations ,我们可以看到,在通过 MergedAnnotations 获得了一个 MergedAnnotation 对象——实际上是 TypeMappedAnnotation 对象——之后,又调用了 MergedAnnotationsynthesize 方法,将 MergedAnnotation 转成了一个调用方指定类型的注解对象。

该方法先调用了 AbstractMergedAnnotation 的 synthesize 方法:

随后再调用了实现类 TypeMappedAnnotation 的 synthesize 方法:

继续点开 createSynthesized :

而 SynthesizedMergedAnnotationInvocationHandler 是一个用于 JDK 动态代理的 InvocationHandler ,我们不需要完全站看,仅需看看它的构造函数与 InvocationHandlerinvoke 就能明白它的运作机制了:

至此,合并注解的合成机制已经很明确了:

承接上文,当我们使用 MergedAnnotationsynthesize 方法时,我们可能会得到两种对象:

而通过注解代理对象取值时,这些方法会被代理到 SynthesizedMergedAnnotationInvocationHandler 中存放的 MergedAnnotation 对象上,从而让这个代理对象通过原始注解的属性,获得与原始注解不一样的属性值。

当我们调用代理对象的属性值时,它会在 SynthesizedMergedAnnotationInvocationHandler 中,通过 invoke 代理到对应的方法上:

这里我们代理对象是如何获取注解属性值的:

这里的 MergedAnnotationgetValue 最终在经过多次跳转后,调到 TypeMappedAnnotationgetAttributeValue 上:

而这边的 getValue 方法就是真正要获取属性值的地方。

这一步有点复杂,主要是根据不同的情况,通过 AnnotationTypeMapping 中的几个属性映射数组,包括 aliasMappings 、 conventionMappings , annotationValueMappings 与 annotationValueSource 来确定最终用于取值的 AnnotationTypeMapping 对象与调用的方法在 AttributeMethods 中的下标:

至此,获取属性值的方法流程也走完了。

在这一章,我们了解了当通过 MergedAnnotations 获得注解并解析得到 AnnotationTypeMapping 后, AnnotationTypeMapping 是如何再转为我们所需的 MergedAnnotation ,以及在此之后, MergedAnnotation 又是如何生成我们最终所需要的代理注解的。

简而言之,当解析注解的元注解获得所需的 AnnotationTypeMapping 后, MergedAnnotation 会判断 AnnotationTypeMapping 是否发生过属性映射,如果没有则返回该映射对象对应的原始注解,否则就通过 SynthesizedMergedAnnotationInvocationHandler 生成一个对应类型的 JDK 动态代理对象。

当我们通过代理对象去调用注解的方法,获取注解的属性的时候, SynthesizedMergedAnnotationInvocationHandler 会把方法代理到对应的内部方法中,而获取属性时,还会通过 MergedAnnotationgetValue ,最终绕到 AnnotationTypeMapping 中获取被映射后的属性值。

在SpringBoot项目读取配置文件中读取值,我们会用到@Value注解来读取配置值,例如我们在配置文件中配置了服务器web域名为xxxcom的配置:

serverwebdomain=xxxcom

1

1

在代码中读取其配置项:

@Value("${serverwebdomain}")

private String domain;

1

2

1

2

如果这个配置项在配置文件中忘记配置或者有的场景中我们不需要配置这项的时候,在项目启动的时候就会报错。

报错信息如下:

Caused by: javalangIllegalArgumentException: Could not resolve placeholder 'serverwebdomain' in value "${serverwebdomain}"

at orgspringframeworkutilPropertyPlaceholderHelperparseStringValue(PropertyPlaceholderHelperjava:178)

at orgspringframeworkutilPropertyPlaceholderHelperreplacePlaceholders(PropertyPlaceholderHelperjava:124)

at orgspringframeworkcoreenvAbstractPropertyResolverdoResolvePlaceholders(AbstractPropertyResolverjava:239)

at orgspringframeworkcoreenvAbstractPropertyResolverresolveRequiredPlaceholders(AbstractPropertyResolverjava:210)

at orgspringframeworkcontextsupportPropertySourcesPlaceholderConfigurerlambda$processProperties$0(PropertySourcesPlaceholderConfigurerjava:175)

at orgspringframeworkbeansfactorysupportAbstractBeanFactoryresolveEmbeddedValue(AbstractBeanFactoryjava:918)

at orgspringframeworkbeansfactorysupportDefaultListableBeanFactorydoResolveDependency(DefaultListableBeanFactoryjava:1248)

at orgspringframeworkbeansfactorysupportDefaultListableBeanFactoryresolveDependency(DefaultListableBeanFactoryjava:1227)

at orgspringframeworkbeansfactoryannotationAutowiredAnnotationBeanPostProcessor$AutowiredFieldElementinject(AutowiredAnnotationBeanPostProcessorjava:640)

at orgspringframeworkbeansfactoryannotationInjectionMetadatainject(InjectionMetadatajava:119)

at orgspringframeworkbeansfactoryannotationAutowiredAnnotationBeanPostProcessorpostProcessProperties(AutowiredAnnotationBeanPostProcessorjava:399)

18 common frames omitted

1

2

3

4

5

6

7

8

9

10

11

12

13

1

2

3

4

5

6

7

8

9

10

11

12

13

这个时候就需要我们给@Value注解配置项给个默认值。

解决方法如下:

@Value("${serverwebdomain:#{null}}")

private String domain;

1

2

1

2

或者

@Value("${serverwebdomain:xxx}")

private String domain;

1

2

1

2

不过如果默认值我们要设置为null时,我们使用${serverwebdomain:null}时,拿到domain的默认值会是“null" null的字符串,所以这种情况下,我们使用 ${serverwebdomain:#{null}} 这种方式进行赋予默认值

在java中,可以通过反射获取到类、字段、方法签名等相关的信息,像方法名、返回值类型、参数类型、泛型类型参数等,但是不能够获取方法的参数名。在实际开发场景中,有时需要根据方法的参数名做一些 *** 作,比如像spring-mvc中,@RequestParam、@PathVariable注解,如果不指定相应的value属性,默认就是使用方法的参数名做为>

以上就是关于Spring中关于@ModelAttribute用于注解请求方法参数的问题全部的内容,包括:Spring中关于@ModelAttribute用于注解请求方法参数的问题、烧脑巨作,Spring Boot请求处理(常用参数注解使用)、@RequestMapping中value参数的值怎么能从注释的方法中获取等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/10176123.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-06
下一篇2023-05-06

发表评论

登录后才能评论

评论列表(0条)

    保存