Spring、SpringMVC中常用注解含义及用法

落花浮王杯 提交于 2019-12-09 00:53:36

1、@Controller    (注入服务)

@Component扩展,被@Controller注解的类表示Web层实现,从而见到该注解就想到Web层实现,使用方式和@Component相同;

在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这个对象的属性中了,当然属性名称要一样的。

查看一下结果:

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

 

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 

它可以对类成员变量、方法以及构造函数进行标注,完成自动装配的工作。自动装配的意思就是让Spring从应用上下文中找到对应的bean的引用,并将它们注入到指定的bean。通过@Autowired注解可以完成自动装配。使用@Autowired 来消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。

只要对应类型的bean有且只有一个,则会自动装配到该属性上。如果没有找到对应的bean,应用会抛出对应的异常,如果想避免抛出这个异常,则需要设置@Autowired(required=false)。不过,在应用程序设计中,应该谨慎设置这个属性,因为这会使得你必须面对NullPointerException的问题。

如果存在多个同一类型的bean,则Spring会抛出异常,表示装配有歧义,解决办法有两个: 
(1)通过@Qualifier注解指定需要的bean的ID; 
(2)通过@Resource注解指定注入特定ID的bean;

@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了。

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注解时,则必须使用#{ }方式。

14、@Component (把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>

定义Spring管理Bean

在Java配置文件中有两个注解值得注意:

@Configuration     表示这个.java文件是一个配置文件;

@ComponentScan   表示开启Component扫描,Spring将会设置该目录以及子目录下所有被@Component注解修饰的类。

15、@Configuration

 表示这个类是一个spring 配置类,一般这里面会定义Bean,会把这个类中bean加载到spring容器中。

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
public class SoundSystemConfig {
}

16、@Bean

在JavaConfig中的属性注入:

@Bean
public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
}

看起来是函数调用,实际上不是:由于sgtPeppers()方法被@Bean注解修饰,所以Spring会拦截这个函数调用,并返回之前已经创建好的bean——确保该SgtPeppers bean为单例。

17、@ComponentScan

@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中。且这个注解默认会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中。

如果不设置basePackage的话,默认会扫描包的所有类,所以最好还是写上basePackage,减少加载时间。默认扫描**/*.class路径,比如这个注解在com.wuhulala下面,那么会扫描这个包下的所有类还有子包的所有类。比如com.wuhulala.service包的应用。

总结@ComponentScan的常用方式:

  • 自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器

  • 通过includeFilters加入扫描路径下没有以上注解的类加入spring容器

  • 通过excludeFilters过滤出不用加入spring容器的类

  • 自定义增加了@Component注解的注解方式

 18、@Service (注入dao)

用于标注服务层,主要用来进行业务的逻辑处理。@Component扩展,被@Service注解的POJO类表示Service层实现,从而见到该注解就想到Service层实现,使用方式和@Component相同;

19、@Repository (实现dao访问)

用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件。@Component扩展,被@Repository注解的POJO类表示DAO层实现,从而见到该注解就想到DAO层实现,使用方式和@Component相同;


@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请求参数。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!