SpringBoot (二) --- 返回Json数据
作者:mmseoamin日期:2024-01-18

SpringBoot(二) — 返回Json数据

SpringBoot (二) --- 返回Json数据,第1张

文章目录

  • SpringBoot(二) --- 返回Json数据
    • 什么是JSON
      • json的基本语法格式如下:
      • @RestController
      • 不同数据类型返回的JSON
        • 创建People实体类
        • 创建JsonController类
        • 返回结果展示
        • 补充一点
        • Jackson 中对 null 的处理
        • 封装一个通用类
          • 修改JsonController的返回值类型
          • 补充
            • 1.@PathVariable注解的用法和作用
            • 2.自定义输出格式---Json的几个注解

              什么是JSON

              ​ JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互。

              相当于全球通用语—英语,中国56个民族不同地区的通用语言-普通话

              json的基本语法格式如下:

              • json是一种纯字符数据,不属于编程语言
              • json的语法与js中object的语法几乎一致
              • json数据中的键值对可以使用编程语言中所谓的关键字
              • json的数据可以用花括号{}或中括号[]包裹,对应js中的object和array,示例{"name":"admin","age":18}或者["SpringBoot",3.1415,"json"]
              • json数据以键值对形式存在,多个键值对之间用逗号,隔开,但数据结束后,不允许出现没有意义的逗号,键值对的键和值之间用冒号:连接,键值对的键部分,必须用双引号"包裹,单引号都不行;键值对的值部分,不允许出现函数function,undefined,NaN,但是可以有null

                ​ 在我们的项目开发中,接口与接口之间,前后端之间的数据传输都是使用的JSON格式

                @RestController

                ​ 上文我们有提到 @RestController = @controller + @ResponseBody,而@ResponseBody注解的作用就是将返回的数据转换为JSON格式。因此在SpringBoot中 使用@RestController 注解即可将返回的数据结构转换成 JSON 格式。我们还是点进(Ctrl+左键)@RestController看看:

                @Target({ElementType.TYPE, ElementType.METHOD})
                @Retention(RetentionPolicy.RUNTIME)
                @Documented
                @Mapping
                public @interface RequestMapping {
                    String name() default "";
                    //指定请求的实际地址
                    @AliasFor("path")
                    String[] value() default {};
                    @AliasFor("value")
                    String[] path() default {};
                    //指定请求的method类型, GET、POST、PUT、DELETE等
                    RequestMethod[] method() default {};
                    //指定request中必须包含某些参数值是,才让该方法处理。
                    String[] params() default {};
                    //指定request中必须包含某些指定的header值,才能让该方法处理请求。
                    String[] headers() default {};
                    //指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
                    String[] consumes() default {};
                    //指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
                    String[] produces() default {};
                }
                

                如此,我们学到了更多@RestController的参数。

                我们点开 pom.xml 中的 spring-boot-starter-web 依赖,可以找到spring-boot-starter-json依赖:

                
                      org.springframework.boot
                      spring-boot-starter-json
                      2.7.9
                      compile
                
                

                继续点开 spring-boot-starter-json 依赖:

                
                      com.fasterxml.jackson.core
                      jackson-databind
                      2.13.5
                      compile
                
                
                      com.fasterxml.jackson.datatype
                      jackson-datatype-jdk8
                      2.13.5
                      compile
                
                
                      com.fasterxml.jackson.datatype
                      jackson-datatype-jsr310
                      2.13.5
                      compile
                
                
                      com.fasterxml.jackson.module
                      jackson-module-parameter-names
                      2.13.5
                      compile
                
                

                我们发现出现了许多jackson,至此我们知道了Spring Boot 中默认使用的 JSON 解析框架是 Jackson。

                不同数据类型返回的JSON

                在我们平时的项目开发中,常用的数据结构有 类对象、List对象、Map对象。

                创建People实体类

                新建entity包与Controller同级,entity我们用来存放实体类。

                SpringBoot (二) --- 返回Json数据,image-20230324110258370,第2张

                导入lombok依赖:

                
                     org.projectlombok
                     lombok
                     1.18.20
                
                

                然后在File --> Settings --> Plugins,搜索 lombok 下载相关插件。

                在entity中编写我们的实体类:

                import lombok.AllArgsConstructor;
                import lombok.Data;
                @Data   // 为属性添加get,set方法
                @AllArgsConstructor // 提供一个全参构造器,此时不在默认含有无参构造器
                public class People {
                    private String Name;
                    private Integer age;
                    private String gender;
                    
                }
                

                点击左下角structure,可以看到,使用了@Data 和@AllArgsConstructor,lombok依赖已经自动帮我们建立好了get,set等方法。

                SpringBoot (二) --- 返回Json数据,image-20230324112144690,第3张

                创建JsonController类

                分别返回People对象,List,Map

                import com.pan.entity.People;
                import org.springframework.web.bind.annotation.RequestMapping;
                import org.springframework.web.bind.annotation.RestController;
                import java.util.ArrayList;
                import java.util.HashMap;
                import java.util.List;
                import java.util.Map;
                @RestController
                public class JsonController {
                    @RequestMapping("/People")
                    public People getPeople() {
                        return new People("tom", 18, "男");
                    }
                    @RequestMapping("/list")
                    public List getPeopleList() {
                        List PeopleList = new ArrayList<>();
                        People People1 = new People("jack", 20, "男");
                        People People2 = new People("lucy", 23, "女");
                        PeopleList.add(People1);
                        PeopleList.add(People2);
                        return PeopleList;
                    }
                    @RequestMapping("/map")
                    public Map getMap() {
                        Map map = new HashMap<>(3);
                        People People = new People("jan", 25, "女");
                        map.put("人物信息", People);
                        map.put("家庭住址", "北京二环路");
                        map.put("代表作品", "《北京的天》");
                        map.put("书籍订阅", 4153);
                        return map;
                    }
                }
                

                返回结果展示

                在浏览器中输入:localhost:8080/people,返回 JSON 如下:

                {"age":18,"gender":"男","name":"tom"}
                

                在浏览器中输入:localhost:8080/list,返回 JSON 如下:

                [{"age":20,"gender":"男","name":"jack"},{"age":23,"gender":"女","name":"lucy"}]
                

                在浏览器中输入:localhost:8080/map,返回 JSON 如下:

                {"人物信息":{"age":25,"gender":"女","name":"jan"},
                "代表作品":"《北京的天》",
                "家庭住址":"北京二环路",
                "书籍订阅":4153}
                

                我们可以看到默认的 Jackson 框架将这三个常用的数据结构成功转成 JSON 格式。

                补充一点

                如何将String类型转换成json格式呢

                我们知道@Controller如果遇到字符串会去寻找view的路径映射,而@RestController如果遇到字符串就会直接返回字符串。上面我们知道@RestController可以把数据结构转换成JSON类型。如果我们想把String返回成JSON,就需要小小的变形一下

                引入依赖:

                
                     com.alibaba
                     fastjson
                     1.2.9
                
                

                重新编写我们的HelloController:

                import com.alibaba.fastjson.JSON;
                import com.alibaba.fastjson.JSONObject;
                import org.springframework.web.bind.annotation.RequestMapping;
                import org.springframework.web.bind.annotation.RestController;
                @RestController
                public class HelloController {
                    @RequestMapping("/hello")
                    public JSONObject Hello(){
                        String str = "{'result': 'success','msg': '登陆成功'}";
                        JSONObject jsonObject =  JSON.parseObject(str);
                        return jsonObject.getClass().getName();
                    }
                }
                

                返回结果:

                {"result":"success","msg":"登陆成功"}
                

                Jackson 中对 null 的处理

                在处理数据的过程中,我们难免会遇到一些 null 值。当我们转 JSON 时,不希望这些 null 出现,比如我们期望所有的 null 在转 JSON 时都变成““””这种空字符串

                与controller包同级目录下我们创建一个config包用来存放我们的配置文件,并创建一个类JacksonConfig

                SpringBoot (二) --- 返回Json数据,image-20230324143032984,第4张

                JacksonConfig内容:

                import com.fasterxml.jackson.core.JsonGenerator;
                import com.fasterxml.jackson.databind.JsonSerializer;
                import com.fasterxml.jackson.databind.ObjectMapper;
                import com.fasterxml.jackson.databind.SerializerProvider;
                import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
                import org.springframework.context.annotation.Bean;
                import org.springframework.context.annotation.Configuration;
                import org.springframework.context.annotation.Primary;
                import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
                import java.io.IOException;
                @Configuration
                public class JacksonConfig {
                    @Bean
                    @Primary
                    @ConditionalOnMissingBean(ObjectMapper.class)
                    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
                        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
                        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer() {
                            @Override
                            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                                jsonGenerator.writeString("");	// 主要修改的地方,你哪怕填写 哦豁 null也会替换成 哦豁
                            }
                        });
                        return objectMapper;
                    }
                }
                 
                

                这里面builder可能会爆红,但是并不影响编译与运行,这是IDEA工具本身造成的。

                添加完配置文件后,我们修改一下map的内容:

                @RequestMapping("/map")
                    public Map getMap() {
                        Map map = new HashMap<>(3);
                        People People = new People("jan", 25, null);
                        map.put("人物信息", People);
                        map.put("家庭住址", null);
                        map.put("代表作品", "《北京的天》");
                        map.put("书籍订阅", null);
                        return map;
                    }
                

                比较输出结果:

                添加配置类之前:

                {"人物信息":{"age":25,"gender":null,"name":"jan"},
                "代表作品":"《北京的天》",
                "家庭住址":null,
                "书籍订阅":null}
                

                添加配置类之后:

                {"人物信息":{"age":25,"gender":"","name":"jan"},
                "代表作品":"《北京的天》",
                "家庭住址":"",
                "书籍订阅":""}
                

                效果达成!

                封装一个通用类

                在项目开发中,我们不仅需要封装数据,还需要在返回的JSON数据中添加一些其他信息,比如返回状态码code,返回信息msg等,这些信息有助于调用者进行一些简单的逻辑判断。因此,我们需要封装一个统一的JSON返回数据结构。

                因为封装的JSON数据类型的不确定,所以我们在定义统一的JSON结构时,需要利用泛型。统一的 JSON 结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加。一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。

                可以新建包common用来存放一些公共类:

                SpringBoot (二) --- 返回Json数据,第5张

                R类中代码如下:

                import lombok.Data;
                @Data
                public class R {
                    /** 编码:1成功,0和其它数字为失败*/
                    private Integer code;
                    /** 信息返回*/
                    private String msg;
                    /** 信息返回数据*/
                    private T data;
                    public static  R success(T object) {
                        R r = new R();
                        r.data = object;
                        r.code = 1;
                        r.msg = CommonConst.SUCCESS_RESULT;
                        return r;
                    }
                    public static  R error(String msg) {
                        R r = new R();
                        r.msg = msg;
                        r.code = 0;
                        return r;
                    }
                }
                

                此外,还可以在common包中提前定义好返回常量:

                SpringBoot (二) --- 返回Json数据,image-20230324150905905,第6张

                CommonConst类中代码如下:

                public class CommonConst {
                    public static final String SUCCESS_RESULT = "获取信息成功";
                    public static final String ERROR_RESULT = "获取信息成功";
                    // 需要什么信息添加什么
                }
                

                这样我们也可以给R类中的msg返回 r.msg = CommonConst.SUCCESS_RESULT;了

                修改JsonController的返回值类型

                因为 我们的通用类R 使用了泛型,所以所有的返回值类型都可以使用该统一结构。在具体的场景将泛型替换成具体的数据类型,非常方便,也便于维护。修改后的JsonController代码如下:

                import com.pan.common.R;
                import com.pan.entity.People;
                import org.springframework.web.bind.annotation.RequestMapping;
                import org.springframework.web.bind.annotation.RestController;
                import java.util.ArrayList;
                import java.util.HashMap;
                import java.util.List;
                import java.util.Map;
                @RestController
                public class JsonController {
                    @RequestMapping("/people")
                    public R getPeople() {
                        People people = new People("tom", 18, "男");
                        return R.success(people);
                    }
                    @RequestMapping("/list")
                    public R> getPeopleList() {
                        List PeopleList = new ArrayList<>();
                        People People1 = new People("jack", 20, "男");
                        People People2 = new People("lucy", 23, "女");
                        PeopleList.add(People1);
                        PeopleList.add(People2);
                        return R.success(PeopleList);
                    }
                    @RequestMapping("/map")
                    public R> getMap() {
                        Map map = new HashMap<>();
                        People People = new People("jan", 25, "女");
                        map.put("人物信息", People);
                        map.put("家庭住址", "北京二环路");
                        map.put("代表作品", "《北京的天》");
                        map.put("书籍订阅", 4153);
                        return R.success(map);
                    }
                }
                

                我们重新在浏览器中输入:localhost:8080/people,返回 JSON 如下:

                {"code":1,"msg":"操作成功","data":{"age":18,"gender":"男","name":"tom"}}
                

                我们重新在浏览器中输入:localhost:8080/list,返回 JSON 如下:

                {"code":1,"msg":"操作成功","data":[{"age":20,"gender":"男","name":"jack"},{"age":23,"gender":"女","name":"lucy"}]}
                

                我们重新在浏览器中输入:localhost:8080/map,返回 JSON 如下:

                {"code":1,"msg":"操作成功","data":{"人物信息":{"age":25,"gender":"女","name":"jan"},"代表作品":"《北京的天》","家庭住址":"北京二环路","书籍订阅":4153}}
                

                补充

                1.@PathVariable注解的用法和作用

                @PathVariable注解的作用是 映射 URL 绑定的占位符,通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx”) 绑定到操作方法的入参中。一般与@RequestMapping(method = RequestMethod.GET)一起使用,例如我们给我们的JsonController增加一个方法:

                 @RequestMapping(value = "/people/{name}",method = RequestMethod.GET) //或者直接用GetMapping注解,甚至method=RequestMethod.GET可以删掉
                    public R getMapOne(@PathVariable("name") String name) {
                        Map map = new HashMap<>(3);
                        People People = new People("jan", 25, "女");
                        map.put("name", People);
                        map.put("家庭住址", "北京二环路");
                        map.put("代表作品", "《北京的天》");
                        map.put("书籍订阅", 4153);
                        return R.success((People) map.get(name));
                    }
                

                我们重新在浏览器中输入:localhost:8080/people/name,返回 JSON 如下:

                {"code":1,"msg":"操作成功","data":{"age":25,"gender":"女","name":"jan"}}
                

                通过在浏览器输入name,直接得到map中键名为name的值

                2.自定义输出格式—Json的几个注解

                @JsonIgnore: 可用来忽略不想输出某个属性的标签;

                import lombok.AllArgsConstructor;
                import lombok.Data;
                @Data   // 为属性添加get,set方法
                @AllArgsConstructor // 提供一个全参构造器,此时不在默认含有无参构造器
                public class People {
                    private String Name;
                    private Integer age;
                    @JsonIgnore
                    private String gender;
                }
                

                我们重新在浏览器中输入:localhost:8080/people,返回 JSON 如下:

                {"code":1,"msg":"操作成功","data":{"age":18,"name":"tom"}}	// gender属性不在输出
                

                **@JsonFormat:**此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,比如:

                public class time{
                    @JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)
                    private Date date;
                }
                

                **@JsonProperty:**可以指定某个属性和json映射的名称。例如我们有个json字符串为{“user_name”:”aaa”},而java中命名要遵循驼峰规则,则为userName,这时通过@JsonProperty 注解来指定两者的映射规则即可

                public class SomeEntity {
                    @JsonProperty("user_name")
                    private String userName;
                }
                

                更多的注解可以查看这个包:

                SpringBoot (二) --- 返回Json数据,image-20230324163904571,第7张

                g":“操作成功”,“data”:{“age”:18,“name”:“tom”}} // gender属性不在输出

                **@JsonFormat:**此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,比如:
                ```java
                public class time{
                    @JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)
                    private Date date;
                }
                

                **@JsonProperty:**可以指定某个属性和json映射的名称。例如我们有个json字符串为{“user_name”:”aaa”},而java中命名要遵循驼峰规则,则为userName,这时通过@JsonProperty 注解来指定两者的映射规则即可

                public class SomeEntity {
                    @JsonProperty("user_name")
                    private String userName;
                }
                

                更多的注解可以查看这个包:

                [外链图片转存中…(img-h0N86b8W-1679647709346)]