Spring进阶(一):Springmvc常用注解标签详解_spring中的<mvn>标签的差别


URI 模板就是在URI 中给定一个变量,然后在映射的时候动态的给该变量赋值。如URI 模板http://localhost/app/{variable1}/index.html ,这个模板里面包含一个变量variable1 ,那么当我们请求http://localhost/app/hello/index.html 的时候,该URL 就跟模板相匹配,只是把模板中的variable1 用hello 来取代。这个变量在`SpringMVC`中是使用`@PathVariable`来标记的。在`SpringMVC`中,我们可以使用`@PathVariable`来标记一个`Controller` 的处理方法参数,表示该参数的值将使用URI 模板中对应的变量的值来赋值。


代码中我们定义了两个URI 变量,一个是控制器类上的variable1 ,一个是showView 方法上的variable2 ,然后在showView 方法的参数里面使用@PathVariable 标记使用了这两个变量。所以当我们使用/test/hello/showView/2.do 来请求的时候就可以访问到MyController 的showView 方法,这个时候variable1 就被赋予值hello ,variable2 就被赋予值2 ,然后我们在showView 方法参数里面标注了参数variable1 和variable2 是来自访问路径的path 变量,这样方法参数variable1 和variable2 就被分别赋予hello 和2。方法参数variable1 是定义为String 类型,variable2 是定义为int 类型,像这种简单类型在进行赋值的时候Spring是会帮我们自动转换的。


在上面的代码中我们可以看到在标记variable1 为path 变量的时候我们使用的是@PathVariable ,而在标记variable2 的时候使用的是`@PathVariable(“variable2”)` 。这两者有什么区别呢?第一种情况就默认去URI 模板中找跟参数名相同的变量,但是这种情况只有在使用debug 模式进行编译的时候才可以,而第二种情况是明确规定使用的就是URI 模板中的variable2 变量。当不是使用debug 模式进行编译,或者是所需要使用的变量名跟参数名不相同的时候,就要使用第二种方式明确指出使用的是URI 模板中的哪个变量。


除了在请求路径中使用URI 模板,定义变量之外,`@RequestMapping`中还支持通配符“`*`”。如下面的代码我就可以使用/myTest/whatever/wildcard.do 访问到Controller 的testWildcard 方法。如:



@Controller
@RequestMapping ( “/myTest” )
public class MyController {
@RequestMapping ( “*/wildcard” )
public String testWildcard() {
System. out .println( “wildcard------------” );
return “wildcard” ;
}
}


当`@RequestParam`中没有指定参数名称时,`Spring` 在代码debug 编译的情况下会默认取与方法参数同名的参数,如果不是debug 编译的就会报错。


#### 4.2 使用 @RequestMapping 的一些高级用法


(1)params属性



@RequestMapping (value= “testParams” , params={ “param1=value1” , “param2” , “!param3” })
public String testParams() {
System. out .println( “test Params…” );
return “testParams” ;
}


用`@RequestMapping` 的params 属性指定了三个参数,这些参数都是针对请求参数而言的,它们分别表示参数param1 的值必须等于value1,参数param2 必须存在,值无所谓,参数param3 必须不存在,只有当请求/testParams.do 并且满足指定的三个参数条件的时候才能访问到该方法。所以当请求/testParams.do?param1=value1&param2=value2 的时候能够正确访问到该testParams 方法,当请求  
 /testParams.do?param1=value1&param2=value2&param3=value3 的时候就不能够正常的访问到该方法,因为在`@RequestMapping` 的params 参数里面指定了参数param3 是不能存在的。  
 (2)method属性



@RequestMapping (value= “testMethod” , method={RequestMethod.GET, RequestMethod. DELETE })
public String testMethod() {
return “method” ;
}


在上面的代码中就使用method 参数限制了以GET 或DELETE 方法请求/testMethod 的时候才能访问到该Controller 的testMethod 方法。  
 (3)headers属性



@RequestMapping (value= “testHeaders” , headers={ “host=localhost” , “Accept” })
public String testHeaders() {
return “headers” ;
}


headers 属性的用法和功能与params 属性相似。在上面的代码中当请求/testHeaders.do 的时候只有当请求头包含Accept 信息,且请求的host 为localhost 的时候才能正确的访问到testHeaders 方法。


3、`@RequestMapping` 标记的处理器方法支持的方法参数和返回类型


1. 支持的方法参数类型  
 (1)HttpServlet对象,主要包括HttpServletRequest、HttpServletResponse 和HttpSession 对象。这些参数Spring 在调用处理器方法的时候会自动给它们赋值,所以当在处理器方法中需要使用到这些对象的时候,可以直接在方法上给定一个方法参数的申明,然后在方法体里面直接用就可以了。但是有一点需要注意的是在使用HttpSession 对象的时候,如果此时HttpSession 对象还没有建立起来的话就会有问题。  
 2 )Spring 自己的WebRequest对象。使用该对象可以访问到存放在HttpServletRequest 和HttpSession 中的属性值。


3 )InputStream 、OutputStream、Reader 和Writer。InputStream 和Reader 是针对HttpServletRequest 而言的,可以从里面取数据;OutputStream 和Writer 是针对HttpServletResponse 而言的,可以往里面写数据。


(4)使用@PathVariable 、@RequestParam 、@CookieValue 和@RequestHeader 标记的参数。


5 )使用@ModelAttribute 标记的参数。


6 )java.util.Map 、Spring 封装的Model 和ModelMap 。 这些都可以用来封装模型数据,用来给视图做展示。  
 (7 )实体类。可以用来接收上传的参数。  
 (8 )Spring 封装的MultipartFile。用来接收上传文件的。  
 (9 )Spring 封装的Errors 和BindingResult 对象。这两个对象参数必须紧接在需要验证的实体对象参数之后,它里面包含了实体对象的验证结果。  
 2. 支持的返回类型  
 (1 )一个包含模型和视图的ModelAndView 对象。  
 (2 )一个模型对象,这主要包括Spring 封装好的Model和ModelMap,以及java.util.Map,当没有视图返回的时候视图名称将由RequestToViewNameTranslator 来决定。  
 (3 )一个View 对象。这个时候如果在渲染视图的过程中模型的话就可以给处理器方法定义一个模型参数,然后在方法体里面往模型中添加值。  
 (4 )一个String 字符串。这往往代表的是一个视图名称。这个时候如果需要在渲染视图的过程中需要模型的话就可以给处理器方法一个模型参数,然后在方法体里面往模型中添加值就可以了。  
 (5 )返回值是void 。这种情况一般是我们直接把返回结果写到HttpServletResponse 中了,如果没有写的话,那么Spring 将会利用RequestToViewNameTranslator 来返回一个对应的视图名称。如果视图中需要模型的话,处理方法与返回字符串的情况相同。  
 (6 )如果处理器方法被注解`@ResponseBody` 标记的话,那么处理器方法的任何返回类型都会通过HttpMessageConverters 转换之后写到HttpServletResponse 中,而不会像上面的那些情况一样当做视图或者模型来处理。  
 (7 )除以上几种情况之外的其他任何返回类型都会被当做模型中的一个属性来处理,而返回的视图还是由RequestToViewNameTranslator 来决定,添加到模型中的属性名称可以在该方法上用@ModelAttribute(“attributeName”) 来定义,否则将使用返回类型的类名称的首字母小写形式来表示。使用@ModelAttribute 标记的方法会在@RequestMapping 标记的方法执行之前执行。


#### 4、使用@ModelAttribute和 @SessionAttributes 传递和保存数据


`SpringMVC` 支持使用 `@ModelAttribute` 和 `@SessionAttributes` 在不同的模型(model)和控制器之间共享数据。 `@ModelAttribute` 主要有两种使用方式,一种是标注在方法上,一种是标注在 Controller 方法参数上。


当 `@ModelAttribute` 标记在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session 或模型属性中,属性名称可以使用 `@ModelAttribute(“attributeName”)` 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。关于 `@ModelAttribute` 标记在方法上时对应的属性是存放在 session 中还是存放在模型中,我们来做一个实验,看下面一段代码。



@Controller
@RequestMapping ( “/myTest” )public class MyController {
@ModelAttribute ( “hello” )
public String getModel() {
System. out .println( “-------------Hello---------” );
return “world” ;
}
@ModelAttribute ( “intValue” )
public int getInteger() {
System. out .println( “-------------intValue---------------” );
return 10;
}
@RequestMapping ( “sayHello” )
public void sayHello( @ModelAttribute ( “hello” ) String hello, @ModelAttribute ( “intValue” ) int num, @ModelAttribute ( “user2” ) User user, Writer writer, HttpSession session) throws IOException {
writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
writer.write( “\r” );
Enumeration enume = session.getAttributeNames();
while (enume.hasMoreElements())
writer.write(enume.nextElement() + “\r” );
}
@ModelAttribute ( “user2” )
public User getUser(){
System. out .println( “---------getUser-------------” );
return new User(3, “user2” );
}
}


当我们请求 /myTest/sayHello.do 的时候使用 `@ModelAttribute` 标记的方法会先执行,然后把它们返回的对象存放到模型中。最终访问到 sayHello 方法的时候,使用 `@ModelAttribute` 标记的方法参数都能被正确的注入值。执行结果如下所示:  
 Hello world,Hello user210


由执行结果我们可以看出来,此时 session 中没有包含任何属性,也就是说上面的那些对象都是存放在模型属性中,而不是存放在 session 属性中。那要如何才能存放在 session 属性中呢?这个时候我们先引入一个新的概念 `@SessionAttributes` ,它的用法会在讲完 `@ModelAttribute` 之后介绍,这里我们就先拿来用一下。我们在 MyController 类上加上 `@SessionAttributes` 属性标记哪些是需要存放到 session 中的。看下面的代码:



@Controller
@RequestMapping ( “/myTest” )
@SessionAttributes (value={ “intValue” , “stringValue” }, types={User. class })public class MyController {
@ModelAttribute ( “hello” )
public String getModel() {
System. out .println( “-------------Hello---------” );
return “world” ;
}
@ModelAttribute ( “intValue” )
public int getInteger() {
System. out .println( “-------------intValue---------------” );
return 10;
}
@RequestMapping ( “sayHello” )
public void sayHello(Map<String, Object> map, @ModelAttribute ( “hello” ) String hello, @ModelAttribute ( “intValue” ) int num, @ModelAttribute ( “user2” ) User user, Writer writer, HttpServletRequest request) throws IOException {
map.put( “stringValue” , “String” );
writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
writer.write( “\r” );
HttpSession session = request.getSession();
Enumeration enume = session.getAttributeNames();
while (enume.hasMoreElements())
writer.write(enume.nextElement() + “\r” );
System. out .println(session);
}
@ModelAttribute ( “user2” )
public User getUser() {
System. out .println( “---------getUser-------------” );
return new User(3, “user2” );
}
}


在上面代码中我们指定了属性为 intValue 或 stringValue 或者类型为 User 的都会放到 Session中,利用上面的代码当我们访问 /myTest/sayHello.do 的时候,结果如下:  
 Hello world,Hello user210


仍然没有打印出任何 session 属性,这是怎么回事呢?怎么定义了把模型中属性名为 intValue 的对象和类型为 User 的对象存到 session 中,而实际上没有加进去呢?难道我们错啦?我们当然没有错,只是在第一次访问 /myTest/sayHello.do 的时候 `@SessionAttributes` 定义了需要存放到 session 中的属性,而且这个模型中也有对应的属性,但是这个时候还没有加到 session 中,所以 session 中不会有任何属性,等处理器方法执行完成后 Spring 才会把模型中对应的属性添加到 session 中。所以当请求第二次的时候就会出现如下结果:



Hello world,Hello user210
user2
intValue
stringValue


当 @ModelAttribute 标记在处理器方法参数上的时候,表示该参数的值将从模型或者 Session 中取对应名称的属性值,该名称可以通过 @ModelAttribute(“attributeName”) 来指定,若未指定,则使用参数类型的类名称(首字母小写)作为属性名称。


#### 5、@PathVariable和@RequestParam的区别


请求路径上有个id的变量值,可以通过@PathVariable来获取 `@RequestMapping(value = "/page/{id}", method = RequestMethod.GET)`  
 `@RequestParam`用来获得静态的URL请求入参spring注解时action里用到。  
 简介:  
 handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)  
 A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;  
 B、处理request header部分的注解:`@RequestHeader, @CookieValue;`  
 C、处理request body部分的注解:`@RequestParam, @RequestBody;`  
 D、处理attribute类型是注解: `@SessionAttributes, @ModelAttribute;`  
 (1)@PathVariable  
 当使用`@RequestMapping URI template` 样式映射时, 即 `someUrl/{paramId}`, 这时的paramId可通过 `@Pathvariable`注解绑定它传过来的值到方法的参数上。  
 示例代码:



@Controller
@RequestMapping(“/owners/{ownerId}”) public class RelativePathUriTemplateController {
@RequestMapping(“/pets/{petId}”)
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}


上面代码把URI template 中变量 ownerId的值和petId的值,绑定到方法的参数上。若方法参数名称和需要绑定的uri template中变量名称不一致,需要在@PathVariable(“name”)指定uri template中的名称。  
 (2) @RequestHeader、@CookieValue  
 `@RequestHeader` 注解,可以把Request请求header部分的值绑定到方法的参数上。  
 示例代码:  
 这是一个Request 的header部分:



Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
@RequestMapping(“/displayHeaderInfo.do”)
public void displayHeaderInfo(@RequestHeader(“Accept-Encoding”) String encoding,
@RequestHeader(“Keep-Alive”) long keepAlive) {
}


上面的代码,把request header部分的 `Accept-Encoding`的值,绑定到参数encoding上了, `Keep-Alive header`的值绑定到参数keepAlive上。  
 `@CookieValue` 可以把Request header中关于cookie的值绑定到方法的参数上。  
 例如有如下Cookie值:



JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
@RequestMapping(“/displayHeaderInfo.do”) public void displayHeaderInfo(@CookieValue(“JSESSIONID”) String cookie) {
}


即把JSESSIONID的值绑定到参数cookie上。  
 (3)@RequestParam, @RequestBody  
 @RequestParam  
 A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String–> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;  
 B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;  
 C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;  
 示例代码:



@Controller
@RequestMapping(“/pets”)
@SessionAttributes(“pet”) public class EditPetForm {
@RequestMapping(method = RequestMethod.GET)
public String setupForm(@RequestParam(“petId”) int petId, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute(“pet”, pet);
return “petForm”;
}
}


@RequestBody  
 该注解常用来处理Content-Type: 不是`application/x-www-form-urlencoded`编码的内容,例如application/json, application/xml等;


它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。  
 因为配置有`FormHttpMessageConverter`,所以也可以用来处理 `application/x-www-form-urlencoded`的内容,处理完的结果放在一个`MultiValueMap<String, String>`里,这种情况在某些特殊需求下使用,详情查看`FormHttpMessageConverter api;`  
 示例代码:



@RequestMapping(value = “/something”, method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}


(4)`@SessionAttributes, @ModelAttribute`  
 **@SessionAttributes**:  
 该注解用来绑定`HttpSession`中的attribute对象的值,便于在方法中的参数里使用。  
 该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象;  
 示例代码:



@Controller
@RequestMapping(“/editPet.do”)
@SessionAttributes(“pet”) public class EditPetForm {
// …
}


**@ModelAttribute**


该注解有两个用法,一个是用于方法上,一个是用于参数上;  
 用于方法上时: 通常用来在处理`@RequestMapping`之前,为请求绑定需要从后台查询的model;  
 用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:


* A) `@SessionAttributes` 启用的attribute 对象上;
* B) `@ModelAttribute` 用于方法上时指定的model对象;
* C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把`request`中按名称对应的方式把值绑定到bean中。


用到方法上`@ModelAttribute`的示例代码:



@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}


这种方式实际的效果就是在调用@RequestMapping的方法之前,为request对象的model里put(“account”, Account)。  
 用在参数上的@ModelAttribute示例代码:



@RequestMapping(value=“/owners/{ownerId}/pets/{petId}/edit”, method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) {
}


首先查询 `@SessionAttributes`有无绑定的Pet对象,若没有则查询`@ModelAttribute`方法层面上是否绑定了Pet对象,若没有则将`URI template`中的值按对应的名称绑定到Pet对象的各属性上。


#### 6、< context:component-scan base-package = “” />浅析



<context:component-scan base-package=“com.bocsoft.ccms.demo” use-default-filters=“false”>
<context:include-filter type=“annotation”
expression=“com.bocsoft.exts.core.annotation.WebConfiguration” />
</context:component-scan>


`component-scan` 默认扫描的注解类型是 `@Component`,不过,在 `@Component` 语义基础上细化后的`@Repository,@Service`和`@Controller` 也同样可以获得 component-scan 的青睐  
 有了`<context:component-scan>`,另一个`<context:annotation-config/>`标签根本可以移除掉,因为已经被包含进去了  
 另外`<context:annotation-config/>`还提供了两个子标签


* `<context:include-filter>` // 指定扫描的路径
* `<context:exclude-filter>` // 排除扫描的路径


## 总结

这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分**面试题及答案**,希望能帮助到大家

![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/9f06c50bc191d480d693abad0355f190.webp?x-oss-process=image/format,png)

![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/f3229e628a2bdae30faa73b5a95b9239.webp?x-oss-process=image/format,png)

的青睐  
 有了`<context:component-scan>`,另一个`<context:annotation-config/>`标签根本可以移除掉,因为已经被包含进去了  
 另外`<context:annotation-config/>`还提供了两个子标签


* `<context:include-filter>` // 指定扫描的路径
* `<context:exclude-filter>` // 排除扫描的路径


## 总结

这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分**面试题及答案**,希望能帮助到大家

[外链图片转存中...(img-QwsPe5ve-1714474869704)]

[外链图片转存中...(img-KaoTUqgA-1714474869705)]

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.youkuaiyun.com/topics/618154847)收录**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值