原文作者:柠檬学园

springmvc的注解及原理(SpringMVC中常用注解含义及用法)(1)

1、@Controller

在SpringMVC中只需要使用这个标记一个类是Controller,然后使用@requestMapping和@RequestParam等一些注解用以定义URL请求和Controller方法之间的映射,这样的Controller就能被外界访问到。此外,Controller不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,他们可以通过Controller的方法参数灵活的获取到。

举个例子:

@Controller public class TestController { @RequestMapping ( "/showView" ) public ModelAndView showView() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } }

在上面的例子中,@Controller是标记在类TestController上面的, 所以类TestController就是一个SpringMVC Controller对象。分发处理器会扫描使用了该注解的类的方法,并检测该方法是否调用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器。然后使用@RequestMapping ( "/showView" )标记在Controller方法上,表示当请求/showView.do 的时候访问的是TestController 的showView 方法,该方法返回了一个包括Model 和View 的ModelAndView 对象。

单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要把这个控制器类交给Spring 来管理。

第一种方式是在SpringMVC 的配置文件中定义MyController 的bean 对象。

<bean class="com.host.app.web.controller.TestController"/>

第二种方式是在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。

< context:component-scan base-package = "com.host.app.web.controller" > < context:exclude-filter type = "annotation" expression = "org.springframework.stereotype.Service" /> </ context:component-scan >

注:上面 context:exclude-filter 标注的是不扫描 @Service 标注的类

2、@RequestMapping

使用 @RequestMapping 来映射 Request 请求与处理器,通过这个注解可以定义不同的处理器映射规则,即为控制器指定可以处理哪些URL请求。

用@RequestMapping 来映射URL 到控制器类,或者是到Controller 控制器的处理方法上。当@RequestMapping 标记在Controller 类上的时候,里面使用@RequestMapping 标记的方法的请求地址都是相对于类上的@RequestMapping 而言的;当Controller 类上没有标记@RequestMapping 注解时,方法上的@RequestMapping 都是绝对路径。这种绝对路径和相对路径所组合成的最终路径都是相对于根路径“/ ”而言的。

在上面那个例子中:

这个控制器里因为TestController 没有被@RequestMapping 标记,所以当需要访问到里面使用了@RequestMapping 标记的showView 方法时,就是使用的绝对路径/showView.do 请求就可以了。

如果改成这样:

@Controller @RequestMapping ( "/test" ) public class TestController { @RequestMapping ( "/showView" ) public ModelAndView showView() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } }

这种情况下是在控制器上加了@RequestMapping 注解,所以当需要访问到里面使用了@RequestMapping 标记的方法showView() 的时候就需要使用showView 方法上@RequestMapping 相对于控制器TestController上@RequestMapping 的地址,即/test/showView.do 。


URL路径映射:@RequestMapping("/hello"),可以将多个url映射到同一个方法上。

窄化请求映射:

(1)在class上面添加@RequestMapping(url)指定通用请求前缀,限制此类下的所有方法请求url必须以请求前缀开头,通过此方法来分类管理url;

(2)在方法名上面再设置请求映射url,即添加@RequestMapping注解在方法名上。return “/WEB-INF/jsp/login.jsp” 调用这个方法,重定向的到指定的jsp页面或制定的@RequestMapping的请求路径;

(3)在浏览器上输入相应地址,完成访问。

3、@RequestBody

用于读取http请求的内容(字符串),通过springMVC提供的HttpMessageConverter接口将读取到的内容转换为json、xml等格式的数据,再转换为Java对象绑定到Controller类方法的参数上。

简单点来说,就是把json格式的数据转换为java对象,就举个例子来说明:

编写一个jsp页面来向后台传递json格式的数据(切记是json格式的):

<script> jsonData(); function jsonData() { $.ajax({ url:"<%=path%>/user/jsonTest.do", contentType:'application/json;charset=utf-8',//设置json格式 data:'{"username":"张三":"address":"福州"}', type:'post', success:function(data){ alert(data); },error:function(error){ alert(error); } }) } </script>

然后在后台接收一下:

@RequestMapping("/jsonTest.do") public void jsonTest(@RequestBody User user) throws Exception { System.out.println(user.toString()); }

这样的话,前台的两个json数据就会自动匹配到User这个对象的属性中了,当然属性名称要一样的。

查看一下结果:

springmvc的注解及原理(SpringMVC中常用注解含义及用法)(2)

可以看到User这个对象中的username和address都已经自动赋值好了,这个就是json格式的数据转java对象了,可以省去我们在后台将json转成java对象。不过在使用的时候,要注意两边的名称要相同,前台的username要对应java对象中的username这样才能成功。否则得到如下:

springmvc的注解及原理(SpringMVC中常用注解含义及用法)(3)

4、@ResponseBody

含义:

@Responsebody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。

作用:

用于将Controller中方法返回的对象通过适当的HttpMessageConverter转换为指定格式的数据,如:json、xml等,然后写入到response对象的body区,通过Response响应给客户端。需要注意的是,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。

使用时机:

返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;

举个例子:

  @RequestMapping("/login")   @ResponseBody   public User login(User user){     return user;   }

User字段是:userName pwd

那么在前台接收到的数据为:'{"userName":"xxx","pwd":"xxx"}'

效果等同于如下代码:

  @RequestMapping("/login")   public void login(User user, HttpServletResponse response){     response.getWriter.write(JSONObject.fromObject(user).toString());   }

5、@ModelAttribute

在方法定义上使用该注解: SpringMVC在调用目标处理方法前, 会先逐个调用在方法级上标注了@ModelAttribute的方法;

在方法的入参前使用该注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数 –绑定到对象中,再传入入参将方法入参对象添加到模型中。

6、@RequestParam

处理简单类型的绑定,用 @RequestParam 绑定 HttpServletRequest 请求参数到控制器方法参数,即在处理方法入参处使用该注解,可以把请求参数传递给请求方法。

@RequestMapping ( "requestParam" ) public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) { return "requestParam" ; }

在上面代码中利用@RequestParam 从HttpServletRequest 中绑定了参数name 到控制器方法参数name ,绑定了参数age 到控制器方法参数age 。当没有明确指定从request 中取哪个参数时,Spring 在代码是debug 编译的情况下会默认取跟方法参数同名的参数,如果不是debug 编译的就会报错。此外,当需要从request 中绑定的参数和方法的参数名不相同的时候,也需要在@RequestParam 中明确指出是要绑定哪个参数。在上面的代码中如果访问 /requestParam.do?name=hello&age=1 则Spring 将会把request请求参数name的值hello赋给对应的处理方法参数name ,把参数age 的值1 赋给对应的处理方法参数age 。

在@RequestParam 中除了指定绑定哪个参数的属性value之外,还有一个属性required,它表示所指定的参数是否必须在request 属性中存在,默认是true,表示必须存在,当不存在时就会报错。在上面代码中我们指定了参数name的required的属性为false ,而没有指定age 的required 属性,这时候如果我们访问/requestParam.do而没有传递参数的时候,系统就会抛出异常,因为age 参数是必须存在的,而我们没有指定。而如果我们访问 /requestParam.do?age=1 的时候就可以正常访问,因为我们传递了必须的参数age ,而参数name是非必须的,不传递也可以。

value:参数名,即入参的请求参数名字

如:value="id",表示将请求的参数区的名字为id的参数的值等待传入;

require:是否必需,默认是true,表示请求中一定要有相应的参数,否则会报400错误。且在每个参数定义前设置。

defaultValue:默认值,表示如果请求中没有同名参数时的默认值。


通过 require=true 限定参数id必须传递,如果不传递会报400错误;

可以使用defaultValue设置默认值,即使 require=true 也可以不传递id参数。

7、@PathVariable 绑定URL占位符到入参。

8、@ExceptionHandler 注解到方法上, 出现异常时会执行该方法。

9、@ControllerAdvice 使一个Controller成为全局的异常处理类, 类中用ExceptinHandler方法注解的方法可以处理所有Controller发生的异常。

10、@Autowired

它可以对类成员变量、方法以及构造函数进行标注,完成自动装配的工作。通过@Autowired 的使用来消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。

@Autowired 和 @Service("")的配合使用:

实例:

@Controller @RequestMapping("/test") public class StudentController { @Autowired private StudentService studentService; @RequestMapping("getInfo") @ResponseBody public int getInfo(Student student){ return studentService.insertStu(student); } }

在Controller中对私有变量用@Autowired标注,因为studentService这个变量是service层接口,所以要找到他的实现类StudentServiceImpl,并在实现类上添加@Service("")的注释。

@Service("StudentService") public class StudentServiceImpl implements StudentService { @Autowired private StudentDao studentDao; public int insertStu(Student student){ return studentDao.insertInfo(student); } }

如果不添加@Service("")注释,会报如下错误。因为@Autowired 将寻找与之匹配的bean来创建(类名)bena,但因为删除接口实现类上@Service("")注解,找不到服务对象,@Autowired自然也就找不到实例bean了。

springmvc的注解及原理(SpringMVC中常用注解含义及用法)(4)

11、@Override

@Override是伪代码,表示重写(当然不写也可以),不过也有好处:

(1)可以当注释用,方便阅读;

(2)编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。

例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。

举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性。

@Override

public void onCreate(Bundle savedInstanceState)

{…….}

这种写法是正确的,如果你写成:

@Override

public void oncreate(Bundle savedInstanceState)

{…….}

编译器会报如下错误:

The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写onCreate方法(因为oncreate应该为onCreate)。

而如果你不加@Override,则编译器将不会检测出错误,而是会认为你为子类定义了一个新方法:oncreate

12、@Transactional

使用时机:

对数据库的数据进行批量或连表操作时,为了保证数据的一致性和正确性,则需要添加事务管理机制进行管理;

当对数据库的数据操作失败时,事务管理可以很好保证所有的数据 回滚 到原来的数据,如果操作成功,则保证所有的需要更新的数据持久化。

回滚(Rollback)指的是程序或数据处理错误,将程序或数据恢复到上一次正确状态的行为。

回滚包括程序回滚和数据回滚等类型。

删除由一个或多个部分完成的事务执行的更新。为保证应用程序、数据库或系统错误后还原数据库的完整性,需要使用回滚。

回滚泛指程序更新失败, 返回上一次正确状态的行为。

回滚与恢复有本质的区别。

升级回滚:是指因升级中所发生的意外而自动回滚。

使用优点:

(1)开发团队达成一致约定,明确标注事务方法的编程风格;

(2)保证事务方法的执行时间尽可能短,不要穿插其他网络操作,RPC/HTTP请求或者剥离到事务方法外部;

(3)不是所有的方法都需要事务,如果只有一条修改操作、只读操作不需要事务控制。

13、@Param

mybatis提供了一个使用注解来参入多个参数的方法,这种方法需要在接口的参数上添加@Param注解。

举个例子:

/** * 更新学生信息 * @param student * @return */ int updateInfo(@Param("student") Student student);

在这个updateInfo的方法中需要传入多个参数,那么在进行mybatis配置的时候,没有办法同事配置多个参数,所以需要@Param这个注解来绑定参数对象。student这个参数中包含了三个对象,用@Param来绑定参数并命名为"student"。并且在mapper.xml文件中调用时,对逐个参数在调用时,要加上 student. 的前缀。如下所示:

<update id="updateInfo"> UPDATE test_student SET name=#{student.name},age=#{student.age} WHERE id=#{student.id} </update>

注意事项:在使用@Param来注解时,如果使用#{ } 或者 ${ } 的方式都可以,但如果不是用@Param注解时,则必须使用#{ }方式。


@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用来指示参数是否必须绑定。

在方法参数里面如是:

public WebResponse findReleventPolicyPage(@RequestParam("pageSize") Integer pageSize, @RequestParam("pageNum") Integer pageNum, @RequestParam("type") Integer type){}

@RequestBody

处理HttpEntity传递过来的数据,一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。

GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。

POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用HandlerAdapter 配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上。

用于将Controller中方法返回的对象,通过适当的HttpMessageConverter转换为指定格式的数据,如:json、xml等,然后通过Response响应给客户端。

在方法参数里面如是:

@RequestMapping("/json_test") // 响应json数据,把pojo对象转换成json数据并响应 @ResponseBody public Items jsonTest (@RequestBody Items items){ // 接受json数据并转换成pojo对象 return items; }

总结

在GET请求中,不能使用@RequestBody。

在POST请求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,对于参数转化的配置必须统一。

举个例子,在SpringMVC配置了HttpMessageConverters处理栈中,指定json转化的格式,如Date转成‘yyyy-MM-dd’,则参数接收对象包含的字段如果是Date类型,就只能让客户端传递年月日的格式,不能传时分秒。因为不同的接口,它的参数可能对时间参数有不同的格式要求,所以这样做会让客户端调用同事对参数的格式有点困惑,所以说扩展性不高。

如果使用@RequestParam来接受参数,可以在接受参数的model中设置@DateFormat指定所需要接受时间参数的格式。

另外,使用@RequestBody接受的参数是不会被Servlet转化统一放在request对象的Param参数集中,@RequestParam是可以的。

综上所述,一般情况下,推荐使用@RequestParam注解来接受Http请求参数。


最后,我自己是一名从事了多年开发的Java老程序员,辞职目前在做自己的Java私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的Java学习干货,可以送给每一位喜欢Java的小伙伴,想要获取的可以关注我的头条号并在后台私信我:01,即可免费获取。

,