请求响应:统一的响应结果

67 阅读4分钟

@ResponsetBody

先看一个在SpringBoot框架中的接收请求的方法(这种方法在Spring框架中叫控制器方法):

@RequestMapping("/listParameter")
public String getListParameter(@RequestParam(name = "hobby") List<String> hobbyss) {
    for (String s : hobbyss) {
        System.out.println(s);
    }
    System.out.println("用集合成功接收数组参数");
    return "successful";
}

这个方法有个字符串类型的返回值“successful”,当这个方法执行结束之后,会将这个返回值当作响应数据响应给前端,然而这个数据是如何响应给前端的呢?其主要是依靠了注解 @ResponseBody,这是一个方法注解,也是一个类注解,一般是用于Controller方法上(控制器方法)或Controller类上,其主要作用是:将方法的返回值直接响应给前端(若用在类上,则该类中所有方法的返回值都会作为响应数据响应给前端。),如果方法的返回值是实体对象(集合),则会先转换为Json格式再响应给前端。 有了这个注解,才可以让方法的返回值直接响应给前端。

但是在这个方法所属的类上的注解,并没有使用@ResponseBody注解,那为什么还能直接将返回值响应给前端?

image.png 其原因是因为虽然该类没有直接使用@ResponseBody注解,但是其使用了@RestController注解,@RestController注解上使用了@ResponseBody注解:

image.png 剖析@RestController注解的源代码可以发现,除了元注解之外,其使用了@Controller注解和@ResponseBody注解,当我们使用这个注解也就相当于同时使用了@Controller注解和@ResponseBody注解,所以说该类下的所有方法的返回值都可以直接响应给前端。

并且通过观察HTTP请求响应的原始数据,方法的返回值是在响应体中的,

image.png

这也就是@ResponseBody注解的名字由来(其实不是,只是为了便于理解):将方法的返回值作为响应数据在响应体中响应给前端。

统一响应结果

让我们先看一下某个Controller请求处理类中的方法:

@RequestMapping("/listParameter")
public String getListParameter(@RequestParam(name = "hobby") List<String> hobbyss) {
    for (String s : hobbyss) {
        System.out.println(s);
    }
    System.out.println("用集合成功接收数组参数");
    return "successful";
}


@RequestMapping("/date")
public String getDateParameter(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime times) {
    System.out.println(times);
    return "现在时间是" + times;
}

@RequestMapping("/Json")
public String getJsonParameter(@RequestBody TestUser user) {
    System.out.println(user);
    return "Json数据接收成功" + user;
}

@RequestMapping("/path/{id}")
public String getPathParameter(@PathVariable int id) {
    System.out.println("成功获取路径参数:" + id);
    return "successful";
}

@RequestMapping("/path/{id}/{name}")
public String getManyPathParameter(@PathVariable int id, @PathVariable String name) {
    System.out.println("成功获取多个路径参数:" + id + "   " + name);
    return "successful";
}

这个请求处理类中有很多控制器方法,用于处理不同的请求(这样处理不同的请求的方法也可以叫做功能接口),但是每个接口的返回值——也就是响应给前端的数据格式都是不同的:有字符串、有时间、有实体对象(Json),因为有大量不同的响应数据类型,所以说前端对其进行解析十分困难,大大加大了工作难度,也不适合前后端协作,所以说为了解决这个问题,一般会定义一个统一的响应结果。这个统一的响应结果应该至少包含以下三个属性:1.请求的状态码,和HTTP请求状态码一样,这个类也应该有请求状态码,能够让前端清楚的知道请求是否成功;2.包含响应的数据,如果请求成功了而且需要给前端响应数据,那么就将数据封装进响应类中;3.其他信息,响应类需要其他信息:如果请求失败了,需要将失败的原因封装进去,有时成功了也需要封装信息进去(这个得看前后端的约定)。 所以说按照这个原则设计统一的响应类:

public class Result<T> {
    private Integer code; //状态码:1成功,0和其它数字为失败
    private T data; // 可能会返回的数据
    private String message; // 错误信息
    
    public static <T> Result<T> success() {
        Result<T> result = new Result<>();
        result.code = 1;
        return result;
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.code = 1;
        result.data = data;
        return result;
    }

    public static <T> Result<T> error(String msg) {
        Result<T> result = new Result<>();
        result.code = 0;
        result.message = msg;
        return result;
    }

}

该统一的响应类就可以按照请求成功或失败返回对应的实体对象,这样之后,每一次请求都会返回一样的响应结果(数据不同),不但更加规范,并且前端解析也更加轻松。