1、@PathVariable

  • @PathVariable:映射URL绑定的占位符。

  • 适用REST。

  package com.xianhuii;

  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.PathVariable;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;

  @Controller
  @RequestMapping("/springmvc")
  public class RequestMappingTest01 {
      private static final String SUCCESS = "success";

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

  }

2、REST

  • REST(Representational State Transfer):(资源)表现层状态转化。

  • 资源(Resources):网络上的一个实体,每种资源对应一个特定的URI。

  • 表现层(Representation):把资源具体呈现出来的形式。

  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议是一种无状态的协议,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,就必须通过某种手段,让服务器端发生“转台转化”(State Transfer)。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别敌营四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。

    /order/1 GET:获取id=1的order
    /order/1 DELETE:删除id=1的order
    /order/1 PUT:更新id=1的order
    /order POST:新增order

3、HiddenHttpMethodFilter过滤器

  • HiddenHttpMethodFilter:将POST请求转为DELETE、PUT请求。

  • 源码:

    package org.springframework.web.filter;
    
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.Locale;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.http.HttpMethod;
    import org.springframework.util.Assert;
    import org.springframework.util.StringUtils;
    
    public class HiddenHttpMethodFilter extends OncePerRequestFilter {
        private static final List<String> ALLOWED_METHODS;
        public static final String DEFAULT_METHOD_PARAM = "_method";
        private String methodParam = "_method";
    
        public HiddenHttpMethodFilter() {
        }
    
        public void setMethodParam(String methodParam) {
            Assert.hasText(methodParam, "'methodParam' must not be empty");
            this.methodParam = methodParam;
        }
    
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            HttpServletRequest requestToUse = request;
            if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
                String paramValue = request.getParameter(this.methodParam);
                if (StringUtils.hasLength(paramValue)) {
                    String method = paramValue.toUpperCase(Locale.ENGLISH);
                    if (ALLOWED_METHODS.contains(method)) {
                        requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                    }
                }
            }
    
            filterChain.doFilter((ServletRequest)requestToUse, response);
        }
    
        static {
            ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
        }
    
        private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
            private final String method;
    
            public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
                super(request);
                this.method = method;
            }
    
            public String getMethod() {
                return this.method;
            }
        }
    
    }
  • 配置(web.xml):

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <!--配置HidenHttpMethodFilter:将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>
    
    </web-app>
  • 前端:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    
      <head>
        <title>$Title$</title>
      </head>
    
      <body>
      <%--GET--%>
      <a href="/springmvc/testRest/1">testRest1</a><br>
      <%--POST--%>
    
      <form action="/springmvc/testRest" method="post">
        <input type="submit" value="testRest POST">
      </form>
    
      <%--DELETE--%>
    
      <form action="/springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="testRest DELETE">
      </form>
    
      <%--PUT--%>
    
      <form action="/springmvc/testRest/1" method="post">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="testRest PUT">
      </form>
    
      </body>
    </html>
  • Controller:

    package com.xianhuii;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @Controller
    @RequestMapping("/springmvc")
    public class RequestMappingTest01 {
        private static final String SUCCESS = "success";
    
        @RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
        public String testRestGet(@PathVariable("id") Integer id) {
            System.out.println("get" + id);
            return SUCCESS;
        }
    
        @RequestMapping(value = "/testRest/", method = RequestMethod.POST)
        public String testRestPost() {
            System.out.println("POST");
            return SUCCESS;
        }
    
        @RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
            //@ResponseBody
        public String testRestDelete(@PathVariable("id") Integer id) {
            System.out.println("DELETE" + id);
            return SUCCESS;
        }
    
        @RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
            //@ResponseBody
        public String testRestPut(@PathVariable("id") Integer id) {
            System.out.println("PUT" + id);
            return SUCCESS;
        }
    
    }

    4、@RequestParam

  • SpringMVC通过分析处理方法的签名,将HTTP请求信息绑定到处理方法相应的形参中。

  • SpringMVC对控制器处理方法签名的限制是很宽松的,几乎可以按照喜欢的任何方法对方法进行签名。

  • 必要是可以对方法、方法形参标注相应的注解:@PathVariable、@RequestParam、@RequestHeader等。SpringMVC会将HTTP请求的信息绑定到相应的方法形参中,并根据方法的返回值类型作出相应的后续处理。

  package com.xianhuii;

  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.*;

  @Controller
  @RequestMapping("/springmvc")
  public class RequestMappingTest01 {
      private static final String SUCCESS = "success";

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

  }

5、@RequestHeader

  • 映射请求头信息。

    package com.xianhuii;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    @Controller
    @RequestMapping("/springmvc")
    public class RequestMappingTest01 {
        private static final String SUCCESS = "success";
    
        @RequestMapping("/testRequestHeader")
        public String testRequestHeader(@RequestHeader("Accept-Language") String val) {
            System.out.println("testRequestHeader: " + val);
            return SUCCESS;
        }
    
    }

    6、@CookieValue

  • 绑定请求中的Cookie值。

    package com.xianhuii;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    @Controller
    @RequestMapping("/springmvc")
    public class RequestMappingTest01 {
        private static final String SUCCESS = "success";
    
        /**
         * @CookieValue:映射一个Cookie值。
         * @param sessionId
         * @return
         */
        @RequestMapping("testCookieValue")
        public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
            System.out.println("testCookieValue: " + sessionId);
            return SUCCESS;
        }
    
    }

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

  • SpringMVC会按照请求参数名和POJO属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。

  • POJO(User):

    package com.xianhuii.entities;
    
    public class User {
        private String username;
        private String password;
        private String email;
        private int age;
        private 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;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", email='" + email + '\'' +
                    ", age=" + age +
                    ", address=" + address +
                    '}';
        }
    
    }
  • POJO(Address):

    package com.xianhuii.entities;
    
    public class Address {
        private String province;
        private String city;
    
        public String getProvince() {
            return province;
        }
    
        public void setProv***ring 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 + '\'' +
                    '}';
        }
    
    }
  • 前端:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    
      <head>
        <title>$Title$</title>
      </head>
    
      <body>
    
      <form action="/springmvc/testPOJO" method="post">
        <p>username: <input type="text" name="username"></p>
        <p>password: <input type="password" name="password"></p>
        <p>email: <input type="text" name="email"></p>
        <p>age: <input type="text" name="age"></p>
        <p>city: <input type="text" name="address.city"></p>
        <p>province: <input type="text" name="address.province"></p>
        <p><input type="submit" value="Submit"></p>
      </form>
    
      </body>
    </html>
  • Controller:

    package com.xianhuii;
    
    import com.xianhuii.entities.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    @Controller
    @RequestMapping("/springmvc")
    public class RequestMappingTest01 {
        private static final String SUCCESS = "success";
    
        @RequestMapping("/testPOJO")
        public String testPojo(User user) {
            System.out.println(user);
            return SUCCESS;
        }
    
    }

    8、使用Servlet API作为形参

      package com.xianhuii;
    
      import com.xianhuii.entities.User;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.*;
    
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
    
      @Controller
      @RequestMapping("/springmvc")
      public class RequestMappingTest01 {
          private static final String SUCCESS = "success";
    
          /**
           * 可以使用Servlet原生API作为目标方法的参数:
           *      HttpServletRequest
           *      HttpServletResponse
           *      HttpSession
           *      java.security.Principal
           *      Locale
           *      InputStream
           *      OutputStream
           *      Reader
           *      Writer
           * @param request
           * @param response
           * @return
           */
          @RequestMapping("/testServletAPI")
          public String testServletAPI(HttpServletRequest request,
                                       HttpServletResponse response) {
              return SUCCESS;
          }
      }