SpringMVC注解完全解析(上)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringMVC注解完全解析(上)

学习是一个循序渐进的过程,了解SpringMVC的背景和概念之后,我们就要去深入学习一下SpringMVC。我们知道,SpringMVC基于一套MVC注解,将普通的POJO类变为控制器,而无需实现任何接口,所以注解在SpringMVC中的地位是无法撼动的,下面就对SpringMVC中的注解做一个解析。

@RequestMapping

首先来看一下RequestMapping,这是一个很重要的API,我们在编写入门案例的时候就用过,它可以注解在其它方法上,并指定请求路径。
当然,RequestMapping可不是只能修饰方法,它还能够修饰类,例如下面的这个例子:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping("/test")
    public String hello() {
   
   
        System.out.println("hello world");
        return "success";
    }
}

此时若要想通过url地址访问该类下的hello()方法,应该怎么写呢(只需加上类注解即可)?url地址即为 /springmvc/test,我们测试一下:
在这里插入图片描述
由此我们得知:

  • 类定义处:提供初步的请求映射信息,相对于Web应用的根目录
  • 方法定义处:提供进一步的映射信息,相对于类定义处的URL,若类定义处未标记@RequestMapping,则方法处标记的URL相对于Web应用的根目录

很显然,@RequestMapping的作用远不止如此,否则,我也不必大费周章地来写它, 所以,我们来看它的下一个功能:映射请求参数、请求方法或请求头

1.映射请求参数、请求方法或请求头

@RequestMapping除了可以使用请求URL映射请求外,还可以使用请求方法、请求参数以及请求头映射请求。
@RequestMapping的valie、method、params以及heads分别表示请求URL、请求方法、请求参数和请求头,它们之间是与的关系,联合使用多个条件可让请求映射更加精确化。
看一个例子:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping(value = "/testMethod", method = RequestMethod.POST)
    public String testMethod() {
   
   
        System.out.println();
        return "success";
    }
}

在这里我们将映射路径设置为了/springmvc/testMethod,这是由类和方法注解共同组成的,然后将请求方式设置为Post请求。
测试页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <form action="springmvc/testMethod" method="post">
        <input type="submit" value="submit">
    </form>

</body>
</html>

运行结果:
在这里插入图片描述
但需要注意的是,由于你设置的请求方式为Post,所以如果不是Post请求程序就会报错,无法正常运行。
该方式在实际开发中是十分常用的配置。

@RequestMapping同样还支持请求参数和请求头的设置,请求参数和请求头支持简单的表达式,例如:

  • param1:表示请求必须包含名为param1的请求参数
  • !param1:表示请求不能包含名为param1的请求参数
  • param!=value1:表示请求包含名为param1的请求参数,但其值不能为value1
  • {"param1=value1","param2"}:表示请求必须包含名为param1和param2的请求参数,且param1参数的值必须为value1

请求头与其类似。

使用@RequestMapping设置的映射地址还支持通配符,不过通配符必须使用Ant风格,Ant风格资源地址支持三种匹配符:

  1. ?:匹配文件名中的一个字符
  2. *:匹配文件名中的任意字符
  3. **:匹配多层路径

我们举个例子:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping("testAntPath/*/abc")
    public String testAntPath() {
   
   
        System.out.println("testAntPath");
        return "success";
    }

}

这样配置的意思是:我们在testAntPath和abc之间添加任意字符都可以访问到该方法,如:/testAntPath/test/abc、/testAntPath/test2/abc等。另外两种通配符与其类似,就不做重复讲解了。

2.@PathVariable

@PathVariable能够映射URL绑定的占位符,带占位符的URL是Spring3.0新增的功能,该功能在SpringMVC向REST目标挺进发展过程中具有里程碑意义。
通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的参数中:URL中的{xxx}占位符可以通过@PathVariable{"xxx"}绑定到操作方法的参数中。
看一个例子:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping("testPathVariable/{id}")
    public String testPathVariable(@PathVariable("id") Integer id) {
   
   
        System.out.println("testPathVariable" + id);
        return "success";
    }

}

通过这样的配置我们就能够获取到URL地址中占位符的参数并绑定到处理方法的参数中,我们测试一下:
在这里插入图片描述
既然说到了REST,那就简单地聊一聊吧。
REST:即Representational State Transfer。(资源)表现层状态转化,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息,它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI,要获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符。
  • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层。
  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态的协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务端发生"状态转化",而这种转化是建立在表现层之上的,所以就是"表现层转化"。具体说,就是HTTP协议里面,四个表示操作方式的动作词:GET、POST、PUT、DELETE,它们分别对应四种基本操作:GET用来获取资源;POST用来新建资源;PUT用来更新资源;DELETE用来删除资源。

示例:

  • /order/1 HTTP GET :得到id = 1的order
  • /order/1 HTTP DELETE :删除id = 1的order
  • /order/1 HTTP PUT :更新id = 1的order
  • /order HTTP POST :新增order

以上是一个REST风格的增删改查示例。
但事实上浏览器form表单只支持GET与POST请求,而DELETE、PUT等请求并不支持,为此,Spring3.0添加了一个过滤器(HiddenHttpMethodFilter),该过滤器可以将这些请求转换为标准的http方法,使得浏览器间接支持GET、POST、PUT和DELETE请求。

说了一大堆,不如一个实际案例看得明白,我们就通过一个例子来使用一下该过滤器。
首先在web.xml文件中配置过滤器:

<!-- 配置org.springframework.web.filter.HiddenHttpMethodFilter:可以将post请求转为delete或put请求 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

接着我们在jsp页面创建四个表单,分别对应四种请求方式:


    <form action="springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="PUT"> 
        <input type="submit" value="TestRest PUT">
    </form>
    <br>

    <form action="springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="DELETE"> 
        <input type="submit" value="TestRest DELETE">
    </form>
    <br>

    <form action="springmvc/testRest" method="post">
        <input type="submit" value="TestRest POST">
    </form>
    <br>

    <form action="springmvc/testRest/1" method="get">
        <input type="submit" value="TestRest GET">
    </form>
    <br>

</body>
</html>

然后在控制器中编写对应的四个测试方法:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
    public String testRestPut(@PathVariable Integer id) {
   
   
        System.out.println("testRest PUT: " + id);
        return "success";
    }

    @RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
    public String testRestDelete(@PathVariable Integer id) {
   
   
        System.out.println("testRest DELETE: " + id);
        return "success";
    }

    @RequestMapping(value = "/testRest", method = RequestMethod.POST)
    public String testRestPost() {
   
   
        System.out.println("testRest POST");
        return "success";
    }

    @RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
    public String testRestGet(@PathVariable Integer id) {
   
   
        System.out.println("testRest GET: " + id);
        return "success";
    }
}

在前面已经提到过,如果客户端实际请求的方式和@RequestMapping设置的请求方式不匹配,程序就会报错,所以如果四种请求方式都能成功访问,说明请求方式确实被HiddenHttpMethodFilter成功转换了。
接下来运行看结果:
在这里插入图片描述
运行结果是没有问题的,但是这里要注意一些地方,我在这里也遇到了很多坑,和大家分享一下:

  1. PUT和DELETE请求是无法识别到的,所以要通过一个隐藏域来辅助完成,隐藏域的name必须为 "_method",valueI必须为请求方式名称,这是由过滤器的底层决定的。
  2. 如果你碰到了下面的问题,那么你有三种解决方案
    在这里插入图片描述
    a.tomcat换到7.0以及以下版本
    b.请求先转给一个Controller,再返回jsp页面
    c.<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isErrorPage="true"%>,设置isErrorPage为true

暂时我也只遇到了这两个问题。

@RequestParam

前面我们使用@PathVariable可以获取请求参数,这是一个Rest风格的URL,使用炸占位符的方式携带一个参数,但是它并不是真正意义的请求参数,我们应该用@RequestParam来处理请求参数。

使用@RequestParam绑定请求参数

在处理方法的参数中使用@RequestParam可以把请求参数传递给请求方法

  • value:参数名
  • required:是否必须,默认为true,表示请求参数中必须包含对应的参数,若不存在,将抛出异常

看一个案例:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    /**
     * @RequestParam     用来映射请求参数
     * value            值即请求的参数名
     * required         该请求参数是否必须,默认为true,必须
     * defaultValue        请求参数的默认值
     * @param username
     * @param age
     * @return
     */
    @RequestMapping(value = "/testRequestParam")
    public String testRequestParam(@RequestParam(value = "username") String username,
            @RequestParam(value = "age") int age) {
   
   
        System.out.println("testRequestParam,username = " + username + "--- age = " + age);
        return "success";
    }
}

此时我们访问这样的一个URL:

http://localhost:8080/SpringMVC/springmvc/testRequestParam?username=abc&age=20

运行结果为:

testRequestParam,username = abc--- age = 20

前面已经说过,required默认为true,所以通过@RequestParam配置的参数在发送请求时必须携带,否则将抛出异常,那么如果要设置某个参数为非必须,即不携带该参数也能成功访问,只需将该参数的required属性设置为false即可。

    @RequestMapping(value = "/testRequestParam")
    public String testRequestParam(@RequestParam(value = "username") String username,
            @RequestParam(value = "age", required = false) int age) {
   
   
        System.out.println("testRequestParam,username = " + username + "--- age = " + age);
        return "success";
    }

@RequestHeader

@RequestHeader和@RequestParam的用法相同,它能够获取请求头的信息并注入目标方法的参数中,我们来看案例:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping(value = "/testRequestHeader")
    public String testRequestHeader(@RequestHeader(value="Accept-Language") String al) {
   
   
        System.out.println("testRequestHeader,Accept-Language: " + al);
        return "success";
    }
}

访问http://localhost:8080/SpringMVC/springmvc/testRequestHeader进行测试,结果为:

testRequestHeader,Accept-Language: zh-CN

@CookieValue

@CookieValue注解,从名字就可以知道,它是用来获取cookie值的,它能够将获取cookie值并注入目标方法的参数中,看一个例子:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping(value = "/testCookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
   
   
        System.out.println("testCookieValue,sessionId: " + sessionId);
        return "success";
    }
}

访问http://localhost:8080/SpringMVC/springmvc/testCookieValue进行测试,结果为:

testCookieValue,sessionId: B7EB860C3764C4BAB0C1F526B830C1FF

使用POJO对象绑定请求参数值

我们知道,一个表单所包含的信息非常多,通常会将这些数据封装成一个对象,这个时候如果每个参数都用@RequestParam去映射,成本未免过高了,这个时候我们就可以直接使用一个对象作为请求参数。SpringMVC会按照请求参数名和POJO属性名进行自动匹配,自动为该对象填充属性值,它还支持级联属性,如:dept.deptId、dept.adress.tel等,我们来看一个例子。
首先编写表单:

<form action="springmvc/testPojo" method="post">
        username:<input type="text" name="username">
        <br>
        password:<input type="password" name="password">
        <br>
        email:<input type="text" name="email">
        <br>
        age:<input type="text" name="age">
        <br>
        city:<input type="text" name="address.city">
        <br>
        province:<input type="text" name="address.province">
        <br>
        <input type="submit" value="submit">
    </form>

然后创建两个Bean类:

public class User {
   
   

    private String username;
    private String password;
    private String email;
    private int age;

    private Address address;

    public Address getAddress() {
   
   
        return address;
    }

    public void setAddress(Address address) {
   
   
        this.address = address;
    }

    public String getUsername() {
   
   
        return username;
    }

    public void setUsername(String username) {
   
   
        this.username = username;
    }

    public String getPassword() {
   
   
        return password;
    }

    public void setPassword(String password) {
   
   
        this.password = password;
    }

    public String getEmail() {
   
   
        return email;
    }

    public void setEmail(String email) {
   
   
        this.email = email;
    }

    public int getAge() {
   
   
        return age;
    }

    public void setAge(int age) {
   
   
        this.age = age;
    }

    @Override
    public String toString() {
   
   
        return "User [username=" + username + ", password=" + password + ", email=" + email + ", age=" + age
                + ", address=" + address + "]";
    }
}
public class Address {
   
   

    private String province;
    private String city;
    public String getProvince() {
   
   
        return province;
    }
    public void setProvince(String province) {
   
   
        this.province = province;
    }
    public String getCity() {
   
   
        return city;
    }
    public void setCity(String city) {
   
   
        this.city = city;
    }

    @Override
    public String toString() {
   
   
        return "Address [province=" + province + ", city=" + city + "]";
    }
}

因为它是支持级联属性的,所以在表单中的address.city和address.province是没有问题的。
测试方法:

@RequestMapping("/springmvc")
@Controller
public class HelloWorld {
   
   

    @RequestMapping("/testPojo")
    public String testPojo(User user) {
   
   
        System.out.println("testPojo: " + user);
        return "success";
    }
}

访问http://localhost:8080/SpringMVC/springmvc/testPojo进行测试,结果为:

testPojo: User [username=admin, password=123456, email=admin@163.com, age=20, address=Address [province=ZheJiang, city=HangZhou]]

这种注入表单参数的方式还是用得比较多的,所以一定要掌握。

相关文章
|
26天前
|
负载均衡 算法 Java
Spring Cloud全解析:负载均衡算法
本文介绍了负载均衡的两种方式:集中式负载均衡和进程内负载均衡,以及常见的负载均衡算法,包括轮询、随机、源地址哈希、加权轮询、加权随机和最小连接数等方法,帮助读者更好地理解和应用负载均衡技术。
|
10天前
|
Java 对象存储 开发者
解析Spring Cloud与Netflix OSS:微服务架构中的左右手如何协同作战
Spring Cloud与Netflix OSS不仅是现代微服务架构中不可或缺的一部分,它们还通过不断的技术创新和社区贡献推动了整个行业的发展。无论是对于初创企业还是大型组织来说,掌握并合理运用这两套工具,都能极大地提升软件系统的灵活性、可扩展性以及整体性能。随着云计算和容器化技术的进一步普及,Spring Cloud与Netflix OSS将继续引领微服务技术的发展潮流。
24 0
|
3月前
|
设计模式 监控 Java
解析Spring Cloud中的断路器模式原理
解析Spring Cloud中的断路器模式原理
|
3月前
|
安全 Java 数据安全/隐私保护
解析Spring Security中的权限控制策略
解析Spring Security中的权限控制策略
|
24天前
|
XML 监控 Java
Spring Cloud全解析:熔断之Hystrix简介
Hystrix 是由 Netflix 开源的延迟和容错库,用于提高分布式系统的弹性。它通过断路器模式、资源隔离、服务降级及限流等机制防止服务雪崩。Hystrix 基于命令模式,通过 `HystrixCommand` 封装对外部依赖的调用逻辑。断路器能在依赖服务故障时快速返回备选响应,避免长时间等待。此外,Hystrix 还提供了监控功能,能够实时监控运行指标和配置变化。依赖管理方面,可通过 `@EnableHystrix` 启用 Hystrix 支持,并配置全局或局部的降级策略。结合 Feign 可实现客户端的服务降级。
101 23
|
7天前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
14 1
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
23 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
Java 微服务 Spring
Spring Cloud全解析:配置中心之解决configserver单点问题
但是如果该configserver挂掉了,那就无法获取最新的配置了,微服务就出现了configserver的单点问题,那么如何避免configserver单点呢?
|
2月前
|
XML Java 数据格式
Spring Cloud全解析:注册中心之zookeeper注册中心
使用ZooKeeper作为Spring Cloud的注册中心无需单独部署服务器,直接利用ZooKeeper服务端功能。项目通过`spring-cloud-starter-zookeeper-discovery`依赖实现服务注册与发现。配置文件指定连接地址,如`localhost:2181`。启动应用后,服务自动注册到ZooKeeper的`/services`路径下,形成临时节点,包含服务实例信息。
170 3
|
3月前
|
负载均衡 Java Spring
@EnableFeignClients注解源码解析
@EnableFeignClients注解源码解析
68 14

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面