Servlet & Spring Boot Web请求

  • 在上一讲,学习了Spring Boot Web的快速入门以及Web开发的基础知识,包括HTTP协议以及Web服务器Tomcat等内容。
  • 基于SpringBoot的方式开发一个web应用,浏览器发起请求 /hello 后 ,服务器给浏览器返回字符串 “Hello World ~”。
  • 运行启动类启动内嵌的Tomcat服务器之后就可以打开浏览器,然后在浏览器的地址栏当中输入访问路径,回车之后就可以访问到我们部署在Tomcat服务器当中的应用程序了。

  • 其实呢,是我们在浏览器发起请求,请求了我们的后端web服务器(也就是内置的Tomcat)。而我们在开发web程序时呢,定义了一个控制器类Controller,请求会被部署在Tomcat中的Controller接收,Controller接收到请求之后,对请求进行处理,处理完毕之后然后Controller再给浏览器响应一个对应的结果,响应一个字符串 “Hello World”。
  • 客户端浏览器和服务器在进行数据传输的时候,是基于HTTP协议的因为HTTP协议就规定了浏览器与服务器进行数据传输的规则,请求响应的过程中是遵循HTTP协议的
  • 我们之前所编写的这个Controller程序,它仅仅是一个简单的Java类,它并没有实现任何的接口,也没有继承任何的类,那其实在Tomcat这类Web服务器中,是不识别我们自己定义的Controller程序的。
  • Tomcat虽然不识别我们所编写的Controller程序,但是Tomcat它是一个Servlet容器,它是支持Servlet规范的,所以在Tomcat中是可以识别Servlet程序的。

那我们所编写的XxxController 是如何处理请求的,又与Servlet之间有什么联系呢?

  • 在SpringBoot进行web程序开发时,它内置了一个核心的Servlet程序DispatcherServlet
  • 其实,在我们基于Spring Boot进行Web程序开发时,Spring Boot底层给我们提供了一个非常核心的Servlet程序DispatcherServlet(核心控制器 / 前端控制器)。

  • 而这个Dispatcher Servlet它就实现了Servlet规范当中的 Servlet接口,所以它是一个可以被Tomcat识别的Servlet程序。

  • 有了DispatcherServlet之后,前端浏览器发起的请求,都会先经过DispatcherServlet,由DispatcherServlet再将这个请求转发给后面的各个请求处理器Controller程序,由Controller程序再对请求进行处理,请求处理器Controller程序处理完请求之后再将处理完的结果返回给DispatcherServlet,最终再由DispatcherServlet给浏览器响应数据。
  • 通过该流程我们可以看出DispatcherServlet在Web请求当中是一个非常核心的一个类,所以这个类在Spring Boot当中我们称为核心控制器或者叫前端控制器。  

我们如何在Servlet程序当中来获取请求的参数呢?

  • 将来前端浏览器发起请求,会携带HTTP的请求数据,包括:请求行、请求头;
  • 请求到达Web服务器Tomcat之后,Tomcat服务器会负责解析这些请求数据,然后将解析后的请求数据会传递给 / 封装到Servlet程序的HttpServletRequest对象(请求对象)
  • 那也就意味着HttpServletRequest对象就可以获取到请求数据
  • 接下来我们的应用程序可以从HttpServletRequest对象当中来获取请求数据,然后再对这个请求进行处理,处理完毕之后Tomcat服务器需要根据HTTP响应数据的格式给浏览器响应数据。

那Tomcat怎么就知道要给浏览器响应哪些数据呢?

  • Tomcat还给Servlet程序传递了一个参数HttpServletResponse。
  • 其实在Servlet程序当中,我们可以借助于另外一个对象HttpServletResponse(响应对象)通过这个对象,我们就可以给浏览器设置响应的数据。
  • 然后Tomcat就会根据我们在这个请求对象当中所设置的响应信息来响应数据给浏览器。

这就是Web应用程序整体的请求访问流程,对于我们来说,我们需要重点关注的就是我们所编写的Controller控制器程序

在Controller程序当中,最重要的就是获取请求参数以及设置响应参数。

请求对象  HttpServeltRequest,它就是用来获取请求数据的。

响应对象  HttpServletResponse,它就是用来设置响应数据的。

 那上述所描述的这种浏览器/服务器的架构模式呢,我们称之为:BS架构。

BS架构:Browser/Server,浏览器/服务器架构模式。

  • 在这种架构模式当中,客户端只需要一个浏览器就行,应用程序所有的逻辑和数据都是存储在服务端的。
  • 浏览器很简单,我们系统已经安装好了,我们要访问这一类的应用,直接打开浏览器地址栏,输入地址就可以直接访问,非常方便。
  • 只要能通过浏览器所访问到的网站,都是BS架构。
  • 由于BS架构不需要单独的安装客户端,因此BS架构维护起来会更加方便一些,只需要维护服务端就可以。
  • 但由于所有的逻辑和数据都是存储在服务器端的,因此我们在通过浏览器端去访问服务器端的时候,它的加载速度就会收到网络带宽以及服务器的性能影响。
  • 我们在以后基于Java语言去开发Web应用程序的时候基本上都是BS架构。

CS架构:Client/Server,客户端/浏览器架构模式。

  • 在这种架构模式当中,我们是需要单独去下载对应的客户端的,而且不同的操作系统对应的客户端也不一样,Windows有Windows版的客户端,Mac有Mac版的客户端。
  • 所以在这种软件架构模式下,软件的开发以及维护会比较麻烦,但是体验不错,因为它有独立的客户端,有很多的逻辑以及数据它是可以在客户端进行处理的,速度会更快一点。
  • 请求:就是在Controller程序当中,我们要来获取各种各样的参数

  • 响应:就是在Controller程序当中,我们要来设置响应的数据

  • 分层解耦:就是将我们所编写的应用程序进行改造,完成代码的分层解耦

0. Servlet 

0.1 Servlet入门 

  • Servlet是Java提供的一门动态Web资源开发技术。
  • Servlet是JavaEE13项规范之一,其实就是一个接口,将来我们需要定义Servlet类实现Servlet接口,并由Web服务器运行Servlet。
  • 如果是原始的Servlet程序,是需要将Servlet程序部署在Tomcat服务器上才能运行的,Servlet程序没办法通过main方法来启动,Servlet程序必须要依赖于Servlet容器才能运行。 

Internet上供外界访问的资源分为两大类:
  1. 静态资源
  2. 动态资源 

在Java中,动态Web资源开发技术我们统称为Java Web!

什么是动态Web资源,什么是静态Web资源呢?

其实浏览器访问我们的Web服务器,最终返回的资源就包含两类:一类是动态Web资源,一类是静态Web资源。 

静态Web资源:
  • 静态Web资源是指在服务器上事先存在的,内容不会随着用户请求或其它外部因素而改变的资源。这些资源的内容在服务器部署时已经确定,常见的静态Web资源包括HTML文件、CSS样式表、JavaScript脚本文件、图像文件、字体文件等。静态Web资源可以直接通过URL访问,并且其内容在客户端显示时不会发生改变。

所谓静态Web资源指的就是你所有人访问我这个页面,你看到的内容一样的,比如像HTML、CSS、JS...

动态Web资源: 
  • 动态Web资源是指在每次用户请求时,根据用户请求的不同或其它外部因素,服务器端可以根据特定的逻辑动态生成内容的资源动态Web资源的内容是根据服务器端程序的逻辑和用户请求的参数动态生成的,常见的动态Web资源包括动态网页、动态图表、动态地图、动态生成的文件等。像Servlet、JSP这些技术开发的资源就是动态资源。
  • 动态Web资源的生成过程可能涉及到数据库查询、数据处理、业务逻辑计算等操作。
  • 动态资源被访问后,需要先转换为静态资源,再返回给浏览器

在Servlet规范当中如何去去开发一个原始的Servlet程序? 

0.2 Servlet快速入门 

需求:使用Servlet开发一个Web应用,浏览器发起请求/hello后,给浏览器返回字符串"Hello World~"。

步骤:
  • 创建Maven项目,导入Servlet依赖坐标
  • 定义一个类,实现Servlet接口(继承HttpServlet),并实现所有方法,并在Service中输出一句话
  • 在Servlet类上使用@WebServlet注解,配置该Servlet的访问路径
  • 部署应用程序到Tomcat,启动访问 
Servlet依赖坐标: 
<!-- Servlet依赖坐标-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

将scope的取值设置为provided,代表主程序内有效,测试程序内有效,但是不打包。

为什么不将Servlet的依赖打包呢? 
  • 因为Tomcat叫Servlet容器,最终Servlet程序是要部署在Servlet容器上才能运行的,而Servlet容器当中已经提供了Servlet的jar包了,如果打包的时候再把Servlet的jar包打进来,就会导致jar包冲突了。 

Servlet程序: 

package com.gch.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/** 配置Servlet的访问路径,指定当前Servlet的请求路径 */
@WebServlet("/hello")
public class HelloServlet implements Servlet {
    /**
     * 初始化方法,Servlet实例化后执行,只执行一次
     * Servlet实例化是在第一次访问的时候才实例化,而不是服务器启动的时候
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init...");
    }

    /**
     * 每次请求Servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("接收到请求,service方法运行...");
        // ServletRequest和ServletResponse是顶层接口,由于我们使用的是Http协议,所以我们要强转为HttpServletRequest、HttpServletResponse
        HttpServletResponse httpServletResponse = (HttpServletResponse)res;
        // 给浏览器响应数据:由于Http协议底层是基于TCP协议的,因此我们要拿到输出流,用流来响应数据
        httpServletResponse.getWriter().write("Hello World~");
    }

    /**
     * 销毁方法,Web服务器关闭时,会调用此方法,只执行一次
     */
    @Override
    public void destroy() {
        System.out.println("destroy...");

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public String getServletInfo() {
        return null;
    }
}

怎样将Servlet程序部署在Tomcat服务器上呢?
 

 

Servlet生命周期的几个阶段? 
  • 生命周期指的是一个对象从创建到销毁的整个过程。
  • 默认是在第一次访问的时候,由Web服务器 / Tomcat服务器创建的Servlet对象。
  • 初始化的方法为init,只会调用一次,完成一些初始化的环境准备工作,比如:加载配置文件
  • 请求处理的方法为service,每次请求Servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理。
  • 销毁的方法为destroy,Web服务器关闭时,会调用此方法,并且只会调用一次,主要完成一些资源的释放。

0.3 Servlet详解 

Servlet体系结构 

  • 最顶级的Servlet接口,就是Servlet规范当中提供的Servlet接口,叫Servlet。
  • 在Servlet体系当中,有这么两个常见的实现:GenericServlet和HttpServlet,也就意味着如果现在我们想去定义一个Servlet程序,我可以实现Servlet这个接口,我也可以继承GenericServlet抽象类或者HttpServlet类。
  • 我们将来开发的Web项目,都是针对HTTP协议,所以我们自定义Servlet,会选择继承HttpServlet,实现其中的两个方法,一个是doGet(),一个是doPost()。

 

浏览器地址栏所发起的请求全部都是Get请求!

Servlet-请求响应 

HttpServletRequest请求对象方法含义
req.getRequestURL()获取请求的URL(统一资源定位符)
req.getParameter("name")获取请求参数
req.getHeader("name")获取请求头
req.getMethod()获取请求方式,比如:GET,POST
HttpServletResponse响应对象方法含义
resp.setHeader("..","..")设置响应头
resp.setStatus(...)设置状态码
resp.getWriter().write(...)获取输出流,输出响应内容
HttpServlet代码: 
package com.gch.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/** 配置Servlet的访问路径,指定当前Servlet的请求路径 */
@WebServlet("/servlet")
public class HttpServletDemo extends HttpServlet {
    /**
     * 处理Get请求
     * @param req  an {@link HttpServletRequest} 请求对象:封装了Http协议当中各种各样的请求数据
     * @param resp an {@link HttpServletResponse} 响应对象:用来封装要给前端浏览器响应的数据的
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet...");
        /**
           获取请求数据
         */
        // 获取请求的URL
        String url = req.getRequestURL().toString();
        System.out.println("请求的URL:" + url);

        // 获取请求的方式
        String method = req.getMethod();
        System.out.println("请求方式为:" + method);

        /**
           设置响应数据
         */
        // 设置响应头
        resp.setHeader("jwt","snbhadjdhka");
        // 设置响应状态码
        resp.setStatus(200);
        // 获取输出流,设置输出响应数据
        resp.getWriter().write("OK");
    }

    /**
     * 处理Post请求
     * @param req  an {@link HttpServletRequest}
     * @param resp an {@link HttpServletResponse}
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost...");
    }
}

一. 请求

第一章请求,主要讲解如何接收页面传递过来的请求数据以及各类请求参数的接收及封装(包括简单参数、实体参数、数组集合参数、日期参数、Json参数、路径参数等)

  • 先需要介绍一款功能强大的接口测试工具-Postman

介绍并安装

  • 当前最主流的开发模式就是前后端分离开发,在这种开发模式下,前端人员基于"接口文档",开发前端的工程 / 前端程序,后端人员基于"接口文档",开发后端的工程 / 程序。
  • 在后端工程的开发过程当中,我们开发完一个功能,就需要对这个功能接口来进行测试,而由于是前后端分离开发的,对我们后端技术人员来讲,在开发过程中,我们是没有前端页面的,那这个时候我们该怎么测试?

方式1:像之前SpringBoot入门案例中一样,直接使用浏览器。在浏览器中输入地址,测试后端程序。

  • 弊端:在浏览器地址栏中输入地址这种方式都是GET请求如果我们要用到测试POST方式的请求怎么办呢?
    要解决POST请求,要测试POST方式的请求,需要程序员自己编写前端代码(比较麻烦)

  • 如果我们要测试POST方式的请求,这个时候就比较麻烦了,我们可能需要自己去编写前端的代码,然后再来进行后端的功能接口测试,这是比较繁琐的,此时我们就可以借助一款功能强大的接口测试工具-Postman,通过Postman就可以轻松的解决各种接口测试的需求了。

注意:浏览器地址栏输入地址所发起的请求,全部都是GET请求。

方式2:使用专业的接口测试工具(Postman工具)

1.1.1 介绍

  • Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。
  • Postman原本是Chrome浏览器的一款插件,可以用来模拟浏览器来发起任何形式(如:get、post) 的HTTP请求,并且在请求的过程当中还可以很方便的去携带很多的请求参数,请求头等信息
  • 常用于做接口的测试,也是后端开发工程师进行接口测试的首选工具。
  • 作用:常用于进行接口测试
  • 特征

    • 简单

    • 实用

    • 美观

    • 大方

  • 基于Postman也衍生出来了很多其他的工具,比如:Apipost,Apifox等,这些工具都是基于Postman衍生出来的。所以它们的使用方式也很简单,和Postaman基本一致。

 1.1.2 安装

  • 登录完成之后,可以创建工作空间:

  • 创建请求:

 界面介绍:

  • 第一栏要选择的是请求方式   后面要填写的就是URL请求路径(统一资源定位器)
  • 请求的参数  请求头的信息  请求体的信息
  • 点击send之后在下面的区域展示的就是响应回来的数据

  • 如果我们需要将测试的请求信息保存下来,就需要创建一个postman的账号,然后登录之后才  可以。
  • 如果想把本次请求测试完毕之后的请求的数据保存下来,可以点击右上角的Save或者直接按Ctrl+S就可以进入到保存的界面上

  • Request Name:请求的名字
  • 设置完请求的名字之后,在下面的这个位置需要来选择一个集合或者一个文件夹,来对这个请求进行归类处理。可以直接点击按钮来创建一个集合。 

 

 

常见参数的接收及封装

1.2 简单参数

简单参数:在向服务器发起请求时,向服务器传递的是一些普通的请求数据。

那么在后端程序中,如何接收传递过来的普通参数数据呢?

我们在这里讲解两种方式:

  1. 原始方式

  2. SpringBoot方式

1.2.1 原始方式

  • 在原始的Web程序当中,需要通过Servlet中提供的API:HttpServletRequest(请求对象),获取请求的相关信息。比如获取请求参数:
  • Tomcat接收到http请求时:把请求的相关信息封装到HttpServletRequest对象中
  • 这个请求对象当中封装了所有的请求数据

    我们所获取过来的所有请求参数都是一个字符串

  • 在Controller中,我们要想获取Request对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:
package com.gch.controller;

import com.gch.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;

/**
   测试请求参数接收
 */
@RestController // 该注解用来标识当前类就是Spring当中的一个请求处理类而不是普通类
public class RequestController {

    // 原始方式
     // http://localhost:8080/simpleParam?name=Tom&age=10
        // 请求参数: name=Tom&age=10   (有2个请求参数)
        // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
        // 第2个请求参数: age=10     参数名:age , 参数值:10
    /**
     * 原始方式接收传递过来的普通参数数据
     * 注解@RequestMapping:用来指定请求路径
     * @param request:请求对象
     * @return "OK"
     */
    @RequestMapping("/simpleParam")
    public String simpleParam(HttpServletRequest request){
        // 获取请求参数
        String name = request.getParameter("name");
        String ageStr = request.getParameter("age");
        // 手动类型转换
        int age = Integer.valueOf(ageStr);
        System.out.println(name + ":" + age);
        return "OK";
    }
}
  •  以上这种方式,我们仅做了解。(在以后的开发中不会使用到)

1.2.2 SpringBoot方式

在Spring Boot当中怎么简化这一块的参数接收?

  • 在Springboot的环境中,对原始的API进行了封装,接收参数的形式更加简单。 如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。
  • 在Spring Boot当中,前端在请求的时候传递的这些简单参数,我们只需要在Controller方法当中声明对应的形参就可以接收到了只需要保证前端的请求参数名与Controller方法的形参变量名保持一致,即可接收成功。并且在接收的过程中当中还会进行自动的类型转化。
@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=10
    // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
    // 第2个请求参数: age=10     参数名:age , 参数值:10
    
   /**
     * springboot方式 
     * 请求处理方法
     * 基于SpringBoot的方式来接收传递过来的普通参数数据
     * SpringBoot会进行自动类型转换
     * @RequestMapping注解是建立url路径跟我们这个方法之间的对应关系的
     * @ReuqestMapping里面指定的value值就是它要处理的请求路径是什么
     * 协议://主机[:端口][/路径][?查询参数]
     * http://localhost:8080/hello?参数名=参数值&参数名=参数值
     * @RestController和RequestMapping这两个注解就是SpringBoot提供给我们的规则、条条框框
     * @return:该方法的返回值就是我们要返回给浏览器的数据
     */
    @RequestMapping("/simpleParam")
    public String simpleParam(String name, Integer age){
        System.out.println(name + ":" + age);
        return "OK";
    }
}

postman测试( GET 请求):  

  • 在GET请求的请求路径后面携带了两个请求参数

postman测试( POST请求 ):POST请求请求参数是在请求体当中携带

 结论:不管是GET请求还是POST请求,对于简单参数只需要保证请求的参数名与Controller方法              的形参名保持一致,就可以自动接收成功,从而获取到请求参数中的数据值。

1.2.3 参数名不一致

如果方法形参名称与请求参数名称不一致,controller方法中的形参还能接收到请求参数值吗?

@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=20
    // 请求参数名:name

    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(String username , Integer age ){//请求参数名和形参名不相同
        System.out.println(username+"  :  "+age);
        return "OK";
    }
}

答案:运行没有报错。 controller方法中的username值为:null,age值为20

  • 结论:对于简单参数来讲,请求参数名和controller方法中的形参名不一致时,无法接收到请             求数据
  • 只要参数能对应上,就可以接收成功。如果参数对应不上,接收不成功,但是它不会报错。

那么如果我们开发中,遇到了这种请求参数名和controller方法中的形参名不相同,怎么办?

  • 如果参数对应不上,也可以接收成功,这个时候需要借助于Spring当中提供的一个注解@RequestParam手动的来完成映射。
  • 我们需要在Controller方法的形参前面加上一个@RequestParam并且通过name / value属性来指定请求参数名是什么。通过name / value属性指定的请求参数名会映射到Controller方法的形参上面来。
@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=20
    // 请求参数名:name

    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam("name") String username , Integer age ){
        System.out.println(username+"  :  "+age);
        return "OK";
    }
}

注意事项:

  • @RequestParam中的required属性默认为true(默认值也是true),代表该请求参数必须传递,如果不传递将报错

 如果该参数可传递可不传递,可以将required属性设置为false

@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
System.out.println(username+ ":" + age);
return "OK";
}

1.3 实体参数

  • 在简单参数接收的时候,前端传递了多少个请求参数,我们就需要在后端Controller方法当中声明多少个形参来接收。
  • 如果请求参数比较多,通过上述的方式一个参数一个参数的接收,会比较繁琐。 
  • 此时,我们可以考虑将请求参数封装到一个实体类对象中。 要想完成数据封装,需要遵守如下规则:请求参数名与实体类的属性名相同
  • 将所有的请求参数都封装到一个实体类 / 对象当中。要想成功的封装,就必须保证一个原则:需要让请求的参数名与是实体类的属性名保持一致。

1.3.1 简单实体对象

 定义POJO实体类:

public class User {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Controller方法:

@RestController
public class RequestController {
    //实体参数:简单实体对象
    @RequestMapping("/simplePojo")
    public String simplePojo(User user){
        System.out.println(user);
        return "OK";
    }
}

Postman测试:

  • 参数名和实体类属性名一致时

  •  参数名和实体类属性名不一致时:不会接收成功,但也不会报错

 简单实体参数的请求用例

  • 简单实体参数的封装只需要保证请求的参数名与形参对象的属性名保持一致。

1.3.2 复杂实体对象

上面我们讲的呢是简单的实体对象,下面我们在来学习下复杂的实体对象。

复杂实体对象指的是,在实体类中有一个或多个属性,也是实体对象类型的。如下:

  • User类中有一个Address类型的属性(Address是一个实体类)

 复杂实体对象的封装,需要遵守如下规则:

  • 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套实体类属性参数。

定义POJO实体类:

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 + '\'' +
                '}';
    }
}

 User实体类:

public class User {
    private String name;
    private Integer age;
    private Address address; //地址对象

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    public Address getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address=" + address +
                '}';
    }
}

Controller方法:

@RestController
public class RequestController {
    //实体参数:复杂实体对象
    @RequestMapping("/complexPojo")
    public String complexPojo(User user){
        System.out.println(user);
        return "OK";
    }
}

Postman测试:

简单实体参数的接收

1.4 数组集合参数

数组集合参数的使用场景:在HTML的表单中,有一个表单项是支持多选的(复选框),可以提交选                                             择的多个值。

 多个值是怎么提交的呢?其实多个值也是一个一个的提交。

后端程序接收上述多个值的方式有两种:

  1. 数组

  2. 集合

服务端请求参数的接收方式: 使用数组来接收    使用集合来接收

 1.4.1 数组

数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数

Controller方法:

@RestController
public class RequestController {
    //数组集合参数
    @RequestMapping("/arrayParam")
    public String arrayParam(String[] hobby){
        System.out.println(Arrays.toString(hobby));
        return "OK";
    }
}

 Postman测试:

在前端请求时,有两种传递形式: 前端参数传递的形式:

  • 方式一: xxxxxxxxxx?hobby=game&hobby=java

  •  方式二:xxxxxxxxxxxxx?hobby=game,java

1.4.2 集合  使用集合来完成参数的接收以及封装

集合参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系

  • 默认情况下,请求中参数名相同的多个值,是封装到数组。
  • 如果要封装到集合,要使用@RequestParam绑定参数关系
  • 使用集合封装,要在形参的这个List集合前面加上一个注解@RequestParam来绑定参数关系,因为默认情况下这多个值它是会封装到数组当中的,如果要封装到List集合,就需要在前面加上这个@RequestParam注解。

 Controller方法:

@RestController
public class RequestController {
    //数组集合参数
    @RequestMapping("/listParam")
    public String listParam(@RequestParam List<String> hobby){
        System.out.println(hobby);
        return "OK";
    }
}

Postman测试:

方式一: xxxxxxxxxx?hobby=game&hobby=java

 方式二:xxxxxxxxxxxxx?hobby=game,java

  •  这就是使用数组以及集合的形式来接收前端传递过来的多个请求参数值,

1.5 日期参数(Date Param)

日期时间类型的参数

  • 在项目的前端表单页面当中,经常会遇到一些日期时间类型的参数,比如像用户的生日入职日期,操作时间这样的请求参数,这一类型的请求参数可以根据项目的需要,将其封装到日期类Date或者是JDK1.8以后提供的LocalDateTime当中来。

  • 由于前端在传递日期类时间参数的时候,格式多种多样,有可能是横杠分隔,有可能是斜杠分隔,有可能是年月日这种格式所以在服务端我们接收的时候,需要指定前端传递过来的格式是什么样子的,通过一个注解@DateTimeFormat,然后里面声明一个属性pattern来指定前端传递的日期参数的格式。这就代表前端将来在请求的时候,就必须按照这个格式来传递对应的请求参数。方法形参的名称也需要与请求参数的名称保持一致。
  • 因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。

  • @DateTimeFormat注解的pattern属性中指定了哪种日期格式,前端的日期参数就必须按照指定的格式传递。

  • 后端controller方法中,需要使用Date类型或LocalDateTime类型,来封装传递的参数。

Controller方法:

@RestController
public class RequestController {
    //日期时间参数
   @RequestMapping("/dateParam")
    public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
        System.out.println(updateTime);
        return "OK";
    }
}

 Postman测试:

1.6 JSON参数

第五种接收Json格式的参数     

  • JSON格式的参数在前后端异步交互的时候,使用的是非常多的。
  • JSON是开发中最常用的前后端数据交互方式

我们学习JSON格式参数,主要从以下两个方面着手:

  1. Postman在发送请求时,如何传递json格式的请求参数

  2. 在服务端的controller方法中,如何接收json格式的请求参数

Postman发送JSON格式数据:

  • 需要将请求方式设置为POST因为这个JSON格式的请求数据是需要放在请求体当中携带到服务端的。
  • 选择JSON然后填写JSON格式的请求参数
  • JSON当中所有的key必须得使用双引号将其引起来,如果没有加双引号,将会报错。

 服务端Controller方法接收JSON格式数据:

  • 接收JSON格式的数据,一般会通过实体类对象来接收。
  • 需要让JSON格式的键名与实体对象的属性名保持一致。

    通过实体对象来接收并封装JSON格式的请求数据。

    加上注解@RequestBody之后就可以将JSON格式的请求数据直接封装到这个实体对象当中。

  • 传递json格式的参数,在Controller中会使用实体类进行封装。

  • 封装规则:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数。需要使用 @RequestBody标识

  • @RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)

 实体类:Address

public class Address {
    private String province;
    private String city;
    
	//省略GET , SET 方法
}

实体类:User

public class User {
    private String name;
    private Integer age;
    private Address address;
    
    //省略GET , SET 方法
}    

Controller方法:

@RestController
public class RequestController {
    //JSON参数
    @RequestMapping("/jsonParam")
    public String jsonParam(@RequestBody User user){
        System.out.println(user);
        return "OK";
    }
}

Postman测试:

1.7 路径参数(Path Param)

传统的开发中请求参数是放在请求体(POST请求)传递跟在URL后面通过?key=value的形式传递(GET请求)。

  • 在现在的开发中,经常还会直接在请求的URL中传递参数。例如:
http://localhost:8080/user/1        
http://localhost:880/user/1/0
  • 上述的这种传递请求参数的形式呢,我们称之为:路径参数。  
  • 路径参数是一种比较特殊的请求参数,路径参数指的是参数已经成为了URL请求路径的一部分。

在后端服务端Controller的方法当中怎么样来获取 / 接收这个路径参数?

路径参数:

  • 前端:通过请求URL直接传递参数

  • 后端:使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数

路径参数:在后端Controller方法注解@RequestMapping中请求路径中的路径参数应该是动态                      的,而不应该写死

例如:@RequestMapping("/path/{id}")

  • 请求路径里面 {id}代表路径参数,代表路径参数的参数名就叫id

  •  在Controller方法当中,声明这么一个形参就叫id,并且在形参前面加上一个注解@PathVariable,用来指定我们要获取到这个路径参数,并且把路径参数的值绑定给我们的方法形参,这样方法形参它就会自动的获取到路径参数这个id上,路径参数的参数名id需要与方法形参名称id保持一致。

Controller方法:

@RestController
public class RequestController {
    //路径参数
    @RequestMapping("/path/{id}")
    public String pathParam(@PathVariable Integer id){
        System.out.println(id);
        return "OK";
    }
}

Postman测试:

传递多个路径参数:

  • 如果我们需要传递多个路径参数我们直接在请求路径当中使用斜杠来分隔,然后再写第二个参数就可以了。
  • 然后我们再定义一个Controller方法来指定访问的路径,请求路径当中有几个路径参数就在Controller方法当中定义几个形参,并且在每个形参前面加上一个注解@PathVeriable通过@PathVeriable就可以获取到这个路径参数,并且把路径参数的值绑定给这个形参。

注意:路径参数名必须与方法形参名称保持一致才可以绑定成功。

Controller方法:

@RestController
public class RequestController {
    //路径参数
    @RequestMapping("/path/{id}/{name}")
    public String pathParam2(@PathVariable Integer id, @PathVariable String name){
        System.out.println(id+ " : " +name);
        return "OK";
    }
}

Postman:

Web开发一些常见的请求参数的接收就已经介绍完了,还有一些比较特殊的请求参数的接收在后续会学习。

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Surpass余sheng军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值