一、请求数据传入(从页面获取数据)

1、JavaWeb 获取请求数据

请求数据:请求参数、cookie 信息、请求头信息......

JavaWEB:

  • HttpRequest;
  • Request.getParameter(参数名);
  • Request.getParameterMap();
  • Request.getCookie();
  • Request.getHeader();

2、请求处理方法签名

(1)Spring MVC 通过分析处理方法的签名(方法名+参数列表),将 HTTP 请求信息绑定到处理方法的相应入参中

(2)Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名;

(3)必要时可以对方法及方法形参标注相应的注解(@PathVariable、@RequestParam、@RequestHeader 等)

(4)Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理;

二、@RequestParam 注解

1、用法

使用 SpringMVC 时,可以自动把根据请求中的参数映射到入参上面,即在处理请求的方法中,加入相对应的形参,保证入参参数名和传递的数据的参数名保持一致,就可以自动赋值。

当请求中的参数名与入参参数名不一致时,就可以在处理方法形参处使用 @RequestParam 可以把请求参数传递给请求方法;

2、属性

value 参数名
    当不满足赋值条件时,可以使用 value 属性,指定映射关系;

required 是否必须。
    默认为 true,必须赋值,表示请求参数中必须包含对应的参数,若不存在,将抛出异常。
    若设置为 false,则不必须赋值,因此形参的值可能为 null

defaultValue 默认值,当没有传递参数时使用该值;
    若形参所获得的值为 null,则设置一个默认值,(用在分页和模糊查询中)

3、示例

/**
      * @RequestMapping 注解用于映射请求参数
      *   value        用于映射请求参数名称
      *   required     用于设置请求参数是否必须赋值
      *   defaultValue 设置默认值,当没有传递参数时使用该值
      *
      */

    @RequestMapping(value = "/handle01")
    public String handle01(@RequestParam(value = "user", required = false, defaultValue = "Tom")String userName, String age) {
        System.out.println("handle01...");
        System.out.println("userName = " + userName);
        System.out.println("age = " + age);
        return "success";
    }

请求链接:

<a href="/handle01?user=abc&age=10">testRequestParam</a>

4、细节

(1)默认方式获取请求参数

直接给方法入参上写一个和请求参数名相同的变量,这个变量就用来接收请求参数的值;

如果请求中带值:就是获取的参数值;

如果请求中没带值:获取为 null

对于上面案例中的 age 就是这样获取方式;

(2)@RequestParam 注解

使用 @RequestParam 注解获取请求参数,参数默认是必须带的,如果没有会报错,可以使用 required 指定该参数是否为必须;还可以使用 defaultValue 指定参数的默认值。

@RequestParam("user")String userName

相当于

userName = request.getParameter("user");

(3)@RequestParam 与 @PathVariable 区别?

@RequestParam 是获取请求参数?后面的值

@PathVariable 是获取路径中的参数值

/book/[{user}pathVariable]?[user=admin(requestParam)]

三、@RequestHeader 注解

1、用法

(1)使用 @RequestHeader 绑定请求报头的属性值;

(2)请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中。

2、属性

value 获取的请求头,指定映射关系;

required 是否必须。
    默认为 true,必须赋值,表示请求头中必须包含对应的参数,若不存在,将抛出异常。
    若设置为 false,则不必须赋值,因此值为 null

defaultValue 设置请求头默认值,当没有传递请求头时使用该值;

3、示例

    @RequestMapping(value = "/handle02")
    public String handle02(@RequestHeader(value = "User-Agent", required = false, defaultValue = "Chrome")String userAgent) {
        System.out.println("handle02...");
        System.out.println("userAgent = " + userAgent);
        return "success";
    }

注意:如果请求头中没有对应的值就会报错,可以使用 required 和 defaultValue 属性;

四、@CookieValue 注解

1、用法

(1)使用 @CookieValue 绑定请求中的 cookie 值;

(2)@CookieValue 可让处理方法形参绑定某个 cookie 值

2、属性

value 绑定请求中的 cookie 值,指定映射关系;

required 是否必须。
    默认为 true,必须赋值,表示 cookie 中必须包含对应的参数,若不存在,将抛出异常。
    若设置为 false,则不必须赋值,因此值为 null

defaultValue 设置 cookie 默认值,当没有传递指定 cookie 时就使用该值;

3、示例

    @RequestMapping(value = "/handle03")
    public String handle03(@CookieValue(value = "JSESSIONID", required = false, defaultValue = "sessionID")String jid) {
        System.out.println("handle03...");
        System.out.println("cookie = " + jid);
        return "success";
    }

五、使用 POJO 作为参数

1、用法

(1)使用 POJO 对象绑定请求参数值;

(2)Spring MVC 会按请求参数名和 POJO 属性名自动匹配,自动为该对象填充属性值,支持级联属性。如 dept.deptId、dept.deptaddress.tel 等

2、示例

① 增加实体类

public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Address address;
}

public class Address {
    private String province;
    private String city;
    private String country;
}

② 控制器方法

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

③ 表单页面

<!-- 测试 POJO 对象传参,支持级联属性-->
<form action="/handle04" method="post">
    username:<input type="text" name="username"  /><br />
    password:<input type="text" name="password"  /><br />
    age:<input type="text" name="age" /><br />
    province:<input type="text"  name="address.province" /><br />
    city:<input type="text" name="address.city"  /><br />
    country:<input type="text"  name="address.country" /><br />
    <input type="submit" value="添加" />
</form>

④ 测试

可以看到数据可以封装进来,但是存在请求的乱码问题。

3、提交的中文乱码

对于提交的数据出现了乱码情况:

请求乱码:

方式一:修改 Tomcat 的 server.xml,在 8080 端口处添加 URIEncoding="UTF-8";

方式二:将请求参数转码(SpringMVC 中不可用)

String user = new String(request.getParameter("user").getBytes("ISO-8859-1"), "UTF-8");

响应乱码:

response.setContentType("text/html;charset=utf-8"); //解决响应乱码

六、使用 Servlet 原生 API 作为参数

1、SpringMVC 的 Handler 方法可以接受 Servlet 原生 Servlet API 类型的参数:

1)HttpServletRequest 请求对象
2)HttpServletResponse 响应对象
3)HttpSession 会话对象
4)java.security.Pincipal HTTPS 安全相关
5)Locale 国际化有关的区域信息对象
6)InputStream         获取字节输入流 request.getInputStream()
8)OutputStream         获取字节输出流 request.getOutputStream()
9)Reader            获取字符输入流 request.getReader()
10)Writer 获取字符输出流 request.getWriter()

2、示例

控制器:

    /*
        SpringMVC 可以直接在参数上写原生API
     */

    @RequestMapping(value = "/handle05")
    public String handle05(HttpServletRequest request, HttpSession session) {
        System.out.println("handle05...");
        request.setAttribute("request""这个是 request 域");
        session.setAttribute("session""这个是 session 域");
        return "success";
    }

请求链接:

<!-- 测试 Servlet API 作为处理请求参数 -->

<a href="handle05">testServletAPI</a>

3、源码参考:

源码:AnnotationMethodHandlerAdapter(L866)

         @Override
         protected Object  resolveStandardArgument(Class<?> parameterType,  NativeWebRequest webRequest) throws Exception {
              HttpServletRequest request =  webRequest.getNativeRequest(HttpServletRequest.class);
              HttpServletResponse response =  webRequest.getNativeResponse(HttpServletResponse.class);
              if  (ServletRequest.class.isAssignableFrom(parameterType)  ||
                       MultipartRequest.class.isAssignableFrom(parameterType))  
{
                  Object nativeRequest =  webRequest.getNativeRequest(parameterType);
                  if (nativeRequest == null) {
                       throw new IllegalStateException(
                                "Current request is not  of type [" + parameterType.getName() + "]: " +  request);
                  }
                  return nativeRequest;
              }
              else if  (ServletResponse.class.isAssignableFrom(parameterType))  {
                  this.responseArgumentUsed = true;
                  Object nativeResponse =  webRequest.getNativeResponse(parameterType);
                  if (nativeResponse == null) {
                       throw new IllegalStateException(
                                "Current response is  not of type [" + parameterType.getName() + "]: " +  response);
                  }
                  return nativeResponse;
              }
              else if  (HttpSession.class.isAssignableFrom(parameterType)) {
                  return request.getSession();
              }
              else if  (Principal.class.isAssignableFrom(parameterType)) {
                  return request.getUserPrincipal();
              }
              else if  (Locale.class.equals(parameterType)) {
                  return  RequestContextUtils.getLocale(request);
              }
              else if  (InputStream.class.isAssignableFrom(parameterType)) {
                  return request.getInputStream();
              }
              else if  (Reader.class.isAssignableFrom(parameterType)) {
                  return request.getReader();
              }
              else if  (OutputStream.class.isAssignableFrom(parameterType)) {
                  this.responseArgumentUsed = true;
                  return response.getOutputStream();
              }
              else if  (Writer.class.isAssignableFrom(parameterType)) {
                  this.responseArgumentUsed = true;
                  return response.getWriter();
              }
              return  super.resolveStandardArgument(parameterType,  webRequest);
         }

八、字符编码过滤器(解决请求中文乱码)

1、字符编码过滤器

SpringMVC 给我们提供了一个字符编码过滤器 CharacterEncodingFilter

如果有中文乱码问题,需要配置字符编码过滤器,而且一定要配置其他过滤器之前,如(HiddenHttpMethodFilter),否则不起作用。

2、在 web.xml 中配置字符编码过滤器:

    <!--  字符编码过滤器  -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置字符编码 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 强制设置响应进行编码 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>  <!-- 对所有的请求都拦截,处理所有响应-->
    </filter-mapping>

注意:字符编码过滤器一定要在配置文件其他过滤器之前,否则不起作用。

获取在获取流或者其他处理的时候就不起作用。

3、字符编码过滤器 CharacterEncodingFilter 源码

public class CharacterEncodingFilter extends OncePerRequestFilter {

    private String encoding;

    private boolean forceEncoding = false;

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public void setForceEncoding(boolean forceEncoding) {
        this.forceEncoding = forceEncoding;
    }

    @Override
    protected void doFilterInternal(
            HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)

            throws ServletException, IOException 
{

        if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
            request.setCharacterEncoding(this.encoding);
            if (this.forceEncoding) {
                response.setCharacterEncoding(this.encoding);
            }
        }
        filterChain.doFilter(request, response);
    }

}
posted on 2021-11-09 09:58  格物致知_Tony  阅读(143)  评论(0编辑  收藏  举报