欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring入门(十三):Spring MVC常用注解讲解

程序员文章站 2022-09-27 17:02:32
在使用Spring MVC开发Web应用程序时,控制器Controller的开发非常重要,虽然说视图(JSP或者是Thymeleaf)也很重要,因为它才是直接呈现给用户的,不过由于现在前端越来越重要,很多公司都开始采用前后端分离的开发模式,所以我们暂时可以将精力放在开发控制器上。 使用Spring ......

在使用spring mvc开发web应用程序时,控制器controller的开发非常重要,虽然说视图(jsp或者是thymeleaf)也很重要,因为它才是直接呈现给用户的,不过由于现在前端越来越重要,很多公司都开始采用前后端分离的开发模式,所以我们暂时可以将精力放在开发控制器上。

使用spring mvc开发控制器主要使用以下7个注解:

  1. @controller
  2. @requestmapping
  3. @responsebody
  4. @requestparam
  5. @pathvariable
  6. @requestbody
  7. @restcontroller

接下来,我们依次讲解每个注解的使用方法。

1. @controller

先回顾下上篇博客中新建的简单控制器hellocontroller:

package chapter05.controller;

import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.requestmethod;

@controller
public class hellocontroller {
    @requestmapping(value = "index", method = requestmethod.get)
    public string hello() {
        // 这里返回的逻辑视图名
        return "index";
    }
}

这里@controller注解的作用是用来声明控制器,它的源码如下所示:

package org.springframework.stereotype;

import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@target({elementtype.type})
@retention(retentionpolicy.runtime)
@documented
@component
public @interface controller {
    string value() default "";
}

这里值得注意的是,@controller注解使用了@component注解,而@component注解我们并不陌生,它用来声明一个bean。

虽然有些书中说可以把@controller注解替换为@component注解,运行没有差别,只是表意性差一点,但是如果你将上面代码中的@controller注解修改为@component注解,然后重新打包发布到tomcat,会发现访问地址http://localhost:8080/spring-action-1.0-snapshot/index时,报如下所示的404错误:

Spring入门(十三):Spring MVC常用注解讲解

@component注解还原为@controller注解,然后重新打包发布到tomcat,再次访问地址http://localhost:8080/spring-action-1.0-snapshot/index时,访问正常:

Spring入门(十三):Spring MVC常用注解讲解

所以,在spring mvc中声明控制器时,推荐使用@controller注解。

注意事项:程序员在阅读技术书籍时,要多思考,多尝试,因为书籍中讲解的,很可能是错的。

2. @requestmapping

@requestmapping注解用来映射web请求,它有2种使用形式:

  1. 应用在方法级别,如上面的代码中展示的那样。
  2. 应用在类级别,当控制器在类级别上添加@requestmapping注解时,这个注解会应用到控制器的所有处理器方法上,处理器方法上的@requestmapping注解会对类级别上的@requestmapping注解的声明进行补充。

@requestmapping注解常用的3个参数如下所示:

  1. value:指定映射的url地址,如index
  2. method:指定映射的请求类型,如get请求、post请求等
  3. produces:指定返回的response的媒体类型和字符集,如application/json;charset=utf-8。

指定method值时使用org.springframework.web.bind.annotation.requestmethod枚举:

package org.springframework.web.bind.annotation;

public enum requestmethod {
    get,
    head,
    post,
    put,
    patch,
    delete,
    options,
    trace;

    private requestmethod() {
    }
}

指定produces值时一般使用org.springframework.http.mediatype类下的常量:

public static final string application_json_value = "application/json";
public static final mediatype application_json_utf8 = valueof("application/json;charset=utf-8");
public static final string application_json_utf8_value = "application/json;charset=utf-8";

为了更好的理解,我们在hellocontroller类上添加如下代码:

package chapter05.controller;

import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.requestmethod;

@controller
@requestmapping("/hello")
public class hellocontroller {
    @requestmapping(value = "index", method = requestmethod.get)
    public string hello() {
        // 这里返回的逻辑视图名
        return "index";
    }
}

重新打包并部署到tomcat中,此时的访问地址从之前的http://localhost:8080/spring-action-1.0-snapshot/index变成了http://localhost:8080/spring-action-1.0-snapshot/hello/index,如下所示:

Spring入门(十三):Spring MVC常用注解讲解

@requestmapping注解的value属性还支持接受一个string类型的数组,如下所示:

@requestmapping({"/hello", "/index"})
public class hellocontroller {
    // 省略其它代码
}

此时也可以通过地址http://localhost:8080/spring-action-1.0-snapshot/index/index进行访问:

Spring入门(十三):Spring MVC常用注解讲解

3. @responsebody

在上面的代码中,我们的方法是返回逻辑视图名index,然后由视图解析器最终找到运行时的/web-inf/classes/views/index.jsp视图,但有时我们不需要返回一个页面,而是直接返回数据给到前端。

此时我们可以使用@responsebody注解,该注解可以放在返回值前或者方法上,用于将返回值放在response体内,而不是返回一个页面。

为了更好的理解,我们新建个demoannocontroller控制器如下所示:

package chapter05.controller;

import org.springframework.http.mediatype;
import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.requestmethod;
import org.springframework.web.bind.annotation.responsebody;

import javax.servlet.http.httpservletrequest;

@controller
@requestmapping("/anno")
public class demoannocontroller {
    @requestmapping(value = "/index", method = requestmethod.get, produces = mediatype.text_plain_value)
    public @responsebody
    string index(httpservletrequest request) {
        return "url:" + request.getrequesturi() + " can access";
    }
}

重新打包并部署到tomcat中,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/index,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

也可以将@responsebody注解放在方法上,如下所示:

@requestmapping(value = "/index", method = requestmethod.get, produces = mediatype.text_plain_value)
@responsebody
public string index(httpservletrequest request) {
    return "url:" + request.getrequesturi() + " can access";
}

4. @requestparam

@requestparam注解用于接收url中的参数信息。

为了更好的理解 ,我们在demoannocontroller控制器中添加如下方法:

@requestmapping(value = "/requestparam", method = requestmethod.get, produces = "text/plain;charset=utf-8")
@responsebody
public string passrequestparam(@requestparam("id") long id, @requestparam("name") string name, httpservletrequest request) {
    return "url:" + request.getrequesturi() + " can access,id: " + id + ",name=" + name;
}

重新打包并部署到tomcat中,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam?id=1&name=zwwhnly ,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

注意事项:上面示例中,url中的参数名称和方法中的变量名称完全一致,所以可以省略掉@requestparam注解,不过为了代码的易读性,建议保留@requestparam注解。

如果不传递参数,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam,则会提示如下信息:

Spring入门(十三):Spring MVC常用注解讲解

或者只传递其中1个参数,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam?id=1,则会提示如下信息:

Spring入门(十三):Spring MVC常用注解讲解

由此也说明,使用了@requestparam注解的参数,在url中必须传递。

不过,@requestparam注解提供了defaultvalue属性,可以给参数指定默认值,比如我们给参数id设置默认值1,给参数name设置默认值zwwhnly,然后访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

或者访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam?id=2,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

不过,还是有一个异常场景需要注意,就是url中传递的参数和方法中定义的参数类型不匹配,比如我们将id的值传错,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/requestparam?id=zwwhnly&name=zwwhnly,会看到如下报错信息:

Spring入门(十三):Spring MVC常用注解讲解

5. @pathvariable

@pathvariable注解也是用于接收url中的参数信息,不过和@requestparam注解稍有不同。

@pathvariable注解用于解析url中的路径参数,如https://www.cnblogs.com/zwwhnly/中的zwwhnly部分,而@requestparam注解用于解析url中的查询参数,如https://i.cnblogs.com/posts?page=2中的page部分。

为了更好的理解 ,我们在demoannocontroller控制器中添加如下方法:

@requestmapping(value = "/pathvar/{str}", produces = "text/plain;charset=utf-8")
public @responsebody
string demopathvar(@pathvariable("str") string str, httpservletrequest request) {
    return "url:" + request.getrequesturi() + " can access,str: " + str;
}

重新打包并部署到tomcat中,访问地址http://localhost:8080/spring-action-1.0-snapshot/anno/pathvar/zwwhnly ,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

注意事项:如果@pathvariable注解中指定value属性的话,它会假设占位符的名称与方法的参数名相同。

因为这里方法的参数名正好与占位符的名称相同,所以我们可以去掉@pathvariable注解的value属性:

@requestmapping(value = "/pathvar/{str}", produces = "text/plain;charset=utf-8")
public @responsebody
string demopathvar(@pathvariable string str, httpservletrequest request) {
    return "url:" + request.getrequesturi() + " can access,str: " + str;
}

6. @requestbody

@requestbody注解允许request的参数在request体中,而不是直接链接在地址后面,该注解放在参数前。

为了更好的理解 ,我们在demoannocontroller控制器中添加如下方法:

@requestmapping(value = "/obj", produces = mediatype.application_json_utf8_value)
@responsebody
public string passobj(@requestbody demoobj demoobj, httpservletrequest request) {
    return "url:" + request.getrequesturi() + " can access,demoobj id:" + demoobj.getid() +
            " demoobj name:" + demoobj.getname();
}

重新打包并部署到tomcat中,然后使用postman工具调用接口http://localhost:8080/spring-action-1.0-snapshot/anno/passobj,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

7. @restcontroller

@restcontroller是一个组合注解,它组合了@controller注解和@responsebody注解,源码如下所示:

package org.springframework.web.bind.annotation;

import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
import org.springframework.stereotype.controller;

@target({elementtype.type})
@retention(retentionpolicy.runtime)
@documented
@controller
@responsebody
public @interface restcontroller {
    string value() default "";
}

因此,如果某个控制器中所有的方法都只是返回数据而不是页面的话,就可以使用@restcontroller注解。

为了更好的理解 ,我们举个具体的示例。

首先,在pom.xml中添加如下依赖,用于对象和json之间的转换:

<dependency>
    <groupid>com.fasterxml.jackson.core</groupid>
    <artifactid>jackson-databind</artifactid>
    <version>2.9.9</version>
</dependency>

然后新建控制器demorestcontroller如下所示:

package chapter05.controller;

import chapter05.model.demoobj;
import org.springframework.http.mediatype;
import org.springframework.web.bind.annotation.requestbody;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.requestmethod;
import org.springframework.web.bind.annotation.restcontroller;

@restcontroller
@requestmapping("/rest")
public class demorestcontroller {
    @requestmapping(value = "/getjson", method = requestmethod.get, produces = mediatype.application_json_utf8_value)
    public demoobj getjson(@requestbody demoobj demoobj) {
        return new demoobj(demoobj.getid(), demoobj.getname());
    }
}

因为使用@restcontroller注解,相当于同时使用了@controller注解和@responsebody注解,所以上面的代码等价于下面的代码:

package chapter05.controller;

import chapter05.model.demoobj;
import org.springframework.http.mediatype;
import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.*;

@controller
@responsebody
@requestmapping("/rest")
public class demorestcontroller {
    @requestmapping(value = "/getjson", method = requestmethod.get, produces = mediatype.application_json_utf8_value)
    public demoobj getjson(@requestbody demoobj demoobj) {
        return new demoobj(demoobj.getid(), demoobj.getname());
    }
}

重新打包并部署到tomcat中,然后使用postman工具调用接口http://localhost:8080/spring-action-1.0-snapshot/rest/getjson,效果如下所示:

Spring入门(十三):Spring MVC常用注解讲解

8. 源码及参考

源码地址:,欢迎下载。

craig walls 《spring实战(第4版)》

汪云飞《java ee开发的颠覆者:spring boot实战》

9. 最后

欢迎扫码关注微信公众号:「申城异乡人」,定期分享java技术干货,让我们一起进步。

Spring入门(十三):Spring MVC常用注解讲解