JavaWeb学习笔记(Day05)之请求响应

一、Postman

1. 使用教程

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

(2) 创建请求:

点击"Save",保存当前请求

2. 简单参数
(1) 原始方式

① 在原始的Web程序当中,需要通过Servlet中提供的API:HttpServletRequest(请求对象),获取请求的相关信息。比如获取请求参数:

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

java 复制代码
//根据指定的参数名获取请求参数的数据值
String request.getParameter("参数名")
java 复制代码
@RestController
public class RequestController {
    //原始方式
    @RequestMapping("/simpleParam")
    public String simpleParam(HttpServletRequest request){
        // http://localhost:8080/simpleParam?name=Tom&age=10
        // 请求参数: name=Tom&age=10   (有2个请求参数)
        // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
        // 第2个请求参数: age=10     参数名:age , 参数值:10

        String name = request.getParameter("name");//name就是请求参数名
        String ageStr = request.getParameter("age");//age就是请求参数名

        int age = Integer.parseInt(ageStr);//需要手动进行类型转换
        System.out.println(name+"  :  "+age);
        return "OK";
    }
}

以上这种方式,我们仅做了解。(在以后的开发中不会使用到)

(2)SpringBoot方式(推荐)

在Springboot的环境中,对原始的API进行了封装,接收参数的形式更加简单。 如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。

java 复制代码
@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=10
    // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
    // 第2个请求参数: age=10     参数名:age , 参数值:10
    
    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致
        System.out.println(name+"  :  "+age);
        return "OK";
    }
}

postman测试( GET 请求)

postman测试( POST请求 ):

结论:不论是GET请求还是POST请求,对于简单参数来讲,只要保证请求参数名和Controller方法中的形参名保持一致,就可以获取到请求参数中的数据值。

(3) 参数名不一致

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

java 复制代码
@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方法中的形参名不相同,怎么办?

解决方案:可以使用Spring提供的@RequestParam注解完成映射

java 复制代码
@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";
    }
}

Q: @RequestParam 到底在干嘛?

A:简单来说,@RequestParam 就是 Spring Boot 用来把「URL 请求参数」和「方法形参」绑定起来的工具

  • 你的 URL 里的参数名是 name,但方法里的变量名是 username,名字不一样。
  • 这时候必须用 @RequestParam("name") 告诉 Spring:"把 URL 里 name 参数的值,赋值给方法里的 username 变量。"
3. 实体参数
(1) 简单实体对象

① 定义 Pojo 实体类:

java 复制代码
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方法:

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

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

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

② 代码演示:

  • Address实体类
java 复制代码
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实体类
java 复制代码
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 +
                '}';
    }
}
(3) 数组集合参数
① 使用场景

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

② 数组参数

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

2). 代码演示

Controller方法:

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

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

默认情况下,请求中参数名相同的多个值,是封装到数组。如果要封装到集合,要使用@RequestParam绑定参数关系

2). 代码演示

java 复制代码
@RestController
public class RequestController {
    //数组集合参数
    @RequestMapping("/listParam")
    public String listParam(@RequestParam List<String> hobby){
        System.out.println(hobby);
        return "OK";
    }
}
(4) 日期参数
① 使用场景

因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。

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

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

② 代码演示
java 复制代码
@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";
    }
}
(5) JSON参数

① Postman发送JSON格式数据:

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

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

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

Q:什么是POJO类型形参?

A: POJO 全称是 Plain Old Java Object ,翻译过来就是「普通的 Java 对象」。它没有继承任何特殊类、也没有实现任何特殊接口,唯一的作用就是封装数据。简单来说,你可以把它理解成一个 "数据容器",专门用来存放前端传递过来的 JSON 数据。

③ 代码演示

Controller方法:

java 复制代码
@RestController
public class RequestController {
    //JSON参数
    @RequestMapping("/jsonParam")
    public String jsonParam(@RequestBody User user){
        System.out.println(user);
        return "OK";
    }
}
(6) 路径参数

① 路径参数

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

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

② 代码演示

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

二、响应

1. @ResponseBody

(1) @ResponseBody注解:

① 类型:方法注解、类注解

② 位置:书写在Controller方法上或类上

③ 作用:将方法返回值直接响应给浏览器

  • 如果返回值类型是实体对象/集合,将会转换为JSON格式后在响应给浏览器

(2) 但是在我们所书写的Controller中,只在类上添加了@RestController注解、方法添加了@RequestMapping注解,并没有使用@ResponseBody注解,怎么给浏览器响应呢?

java 复制代码
@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("Hello World ~");
        return "Hello World ~";
    }
}

原因:在类上添加的@RestController注解,是一个组合注解。

  • @RestController = @Controller + @ResponseBody
2. 统一响应结果

(1) 统一的返回结果使用类来描述,在这个结果中包含:

  • 响应状态码:当前请求是成功,还是失败

  • 状态码信息:给页面的提示信息

  • 返回的数据:给前端响应的数据(字符串、对象、集合)

(2) 代码演示

① 定义在一个实体类Result来包含以上信息。代码如下:

java 复制代码
public class Result {
    private Integer code;//响应码,1 代表成功; 0 代表失败
    private String msg;  //响应码 描述字符串
    private Object data; //返回的数据

    public Result() { }
    public Result(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    //增删改 成功响应(不需要给前端返回数据)
    public static Result success(){
        return new Result(1,"success",null);
    }
    //查询 成功响应(把查询结果做为返回数据响应给前端)
    public static Result success(Object data){
        return new Result(1,"success",data);
    }
    //失败响应
    public static Result error(String msg){
        return new Result(0,msg,null);
    }
}

② 改造Controller:

java 复制代码
@RestController
public class ResponseController { 
    //响应统一格式的结果
    @RequestMapping("/hello")
    public Result hello(){
        System.out.println("Hello World ~");
        //return new Result(1,"success","Hello World ~");
        return Result.success("Hello World ~");
    }

    //响应统一格式的结果
    @RequestMapping("/getAddr")
    public Result getAddr(){
        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");
        return Result.success(addr);
    }

    //响应统一格式的结果
    @RequestMapping("/listAddr")
    public Result listAddr(){
        List<Address> list = new ArrayList<>();

        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");

        Address addr2 = new Address();
        addr2.setProvince("陕西");
        addr2.setCity("西安");

        list.add(addr);
        list.add(addr2);
        return Result.success(list);
    }
}

三、案例

1. 需求说明

需求:加载并解析xml文件中的数据,完成数据处理,并在页面展示

2. 准备工作

(1) 前端页面资源

  • 已经准备好,直接拷贝进来,放在src/main/resources下的static目录下

(2) Springboot项目的静态资源(html,css,js等前端资源)默认存放目录为:classpath:/static 、 classpath:/public、 classpath:/resources

  • classpath:代表的是类路径,在maven的项目中,其实指的就是 src/main/resources 或者 src/main/java,但是java目录是存放java代码的,所以相关的配置文件及静态资源文档,就放在 src/main/resources下。
3. 代码实现
java 复制代码
@RestController
public class EmpController {
    @RequestMapping("/listEmp")
    public Result list(){
        //1. 加载并解析emp.xml
        String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
        //System.out.println(file);
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);

        //2. 对数据进行转换处理 - gender, job
        empList.stream().forEach(emp -> {
            //处理 gender 1: 男, 2: 女
            String gender = emp.getGender();
            if("1".equals(gender)){
                emp.setGender("男");
            }else if("2".equals(gender)){
                emp.setGender("女");
            }

            //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
            String job = emp.getJob();
            if("1".equals(job)){
                emp.setJob("讲师");
            }else if("2".equals(job)){
                emp.setJob("班主任");
            }else if("3".equals(job)){
                emp.setJob("就业指导");
            }
        });
        //3. 响应数据
        return Result.success(empList);
    }
}

核心逻辑:

① String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();

|---------------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| 代码片段 | 核心作用 | 大白话解释 |
| this.getClass() | 获取当前类的Class对象 | 拿到 EmpController 这个类的"身份证",通过它能找到加载这个类的"工具"。 |
| .getClassLoader() | 获取类加载器(ClassLoader) | 类加载器是JVM的"资源查找工具",它默认会去 target/classes 目录(Maven编译后,resources 里的文件会复制到这里)找资源文件。 |
| .getResource("emp.xml") | 从类路径根目录找文件 | 告诉类加载器:"去你的默认查找目录(classpath根)里找名为 emp.xml 的文件",返回一个 URL 对象(包含文件的位置信息)。<br>⚠️ 这里不用加 /,因为 resources 编译后就是类路径(classpath)的根目录。 |
| .getFile() | 把URL转成绝对路径字符串 | 把 URL 对象(比如 file:/D:/JavaWeb/demo/target/classes/emp.xml)转换成普通的文件路径字符串,方便后续XML解析工具读取文件。 |

② Stream流

java 复制代码
// 流式遍历
empList.stream().forEach(emp -> {
    // 处理 gender 和 job 的逻辑(和上面完全一样)
    String gender = emp.getGender();
    if("1".equals(gender)){
        emp.setGender("男");
    }else if("2".equals(gender)){
        emp.setGender("女");
    }

    String job = emp.getJob();
    if("1".equals(job)){
        emp.setJob("讲师");
    }else if("2".equals(job)){
        emp.setJob("班主任");
    }else if("3".equals(job)){
        emp.setJob("就业指导");
    }
});

**Q1:**为什么是 emp ->

A1:

emp -> 是 Java 8 推出的 Lambda 表达式 语法,在你的代码里,它的作用是:

"把遍历到的每一个 Emp 类型的对象,用 emp 这个变量名来代表,然后把这个 emp 传递给后面 {} 里的代码块去处理。"

② 简单说:emp 就是遍历过程中 "当前那一个员工对象" 的名字,-> 是 "把这个对象交给后面处理" 的分隔符。
**Q2:**为什么要使用 stream()

A2:

不用 stream ()(传统 for 循环写法)

java 复制代码
// 传统 for 循环遍历
for (int i = 0; i < empList.size(); i++) {
    Emp emp = empList.get(i);
    // 处理 gender
    String gender = emp.getGender();
    if("1".equals(gender)){
        emp.setGender("男");
    }else if("2".equals(gender)){
        emp.setGender("女");
    }
    // 处理 job
    String job = emp.getJob();
    if("1".equals(job)){
        emp.setJob("讲师");
    }else if("2".equals(job)){
        emp.setJob("班主任");
    }else if("3".equals(job)){
        emp.setJob("就业指导");
    }
}

① 代码更简洁,少写 "模板代码"

传统 for 循环需要写 int i=0; i<empList.size(); i++empList.get(i) 这些 "遍历的模板代码",而 stream().forEach() 直接聚焦 "对每个 emp 对象做什么",不用关心 "怎么遍历"------ 把注意力放在数据处理逻辑 (改 gender、job),而非遍历的过程

② 可读性更高(语义化)

empList.stream().forEach(emp -> { ... }) 读起来就像 "把 empList 转成流,对每个 emp 执行下面的操作",语义更直观,新手也能一眼看懂 "这是遍历每个员工并处理数据"。

四、如何搜索CSDN编写文章内容的关键字

  • 从当前页面点击右上角的头像 → 选择「我的主页」
  • 进入个人博客主页后,在顶部的搜索框(一般在头像下方 / 页面顶部)输入关键字
  • 按回车,结果会显示你的文章列表,每条结果会高亮关键字在正文中的位置,并展示正文片段,不用点开就知道内容是否匹配。
相关推荐
承渊政道1 小时前
C++学习之旅【C++Vector类介绍—入门指南与核心概念解析】
c语言·开发语言·c++·学习·visual studio
hetao17338371 小时前
2026-01-21~22 hetao1733837 的刷题笔记
c++·笔记·算法
2501_901147832 小时前
零钱兑换——动态规划与高性能优化学习笔记
学习·算法·面试·职场和发展·性能优化·动态规划·求职招聘
狐573 小时前
2026-01-22-LeetCode刷题笔记-3507-移除最小数对使数组有序I
笔记·leetcode
wrj的博客10 小时前
python环境安装
python·学习·环境配置
优雅的潮叭10 小时前
c++ 学习笔记之 chrono库
c++·笔记·学习
星火开发设计10 小时前
C++ 数组:一维数组的定义、遍历与常见操作
java·开发语言·数据结构·c++·学习·数组·知识
星幻元宇VR11 小时前
走进公共安全教育展厅|了解安全防范知识
学习·安全·虚拟现实
知识分享小能手11 小时前
Oracle 19c入门学习教程,从入门到精通, Oracle 表空间与数据文件管理详解(9)
数据库·学习·oracle