SpringBoot学习之路(二):对XML文件的解析和JSON数据的返还

【对xml文件的解析】

一、为什么要对xml文件进行解析

  1. 配置文件:在传统的 Java 开发中,很多项目使用 XML 文件作为配置文件来定义应用程序的行为。Spring Boot 支持通过解析 XML 文件来读取和加载配置信息,以便在应用程序中进行相应的配置。

 

Spring 框架集成:Spring 框架本身支持通过 XML 文件来定义和配置应用程序的组件和依赖关系。Spring Boot 可以解析和加载这些 XML 配置文件,使得开发者可以方便地集成和使用 Spring 框架的各种功能。

 

  1. 兼容性:许多遗留的项目和第三方库可能仍然使用 XML 文件作为配置文件。Spring Boot 的目标是提供一种简化和快速开发的方式,同时也要保持与现有项目和库的兼容性,所以它需要支持解析和处理 XML 文件。

总之,Spring Boot 对 XML 文件进行解析是为了 常见的解析工具有 DOM4jJDOM 等,为了标准化 XML 文件解析,Java 中提出了 JAXP  DOM:将标记语言文档一次性加载进入内存中,在内存中形成一颗 DOM 优点:操作方便,可以对文档进行 CRUD *缺点:一次性加载进入内存形成 DOM  SAX:逐行读取,基于事件驱动(安卓终端常用)

  • 优点:不消耗资源
  • 缺点:只能读取,不能增删改

 下面是我用SAX工具来对一个示例xml文件进行解析:

public class Test {
    public static void main(String[] args) throws Exception {
        // 创建 SAXParserFactory 实例
        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
        // 创建 SAXParser 实例
        SAXParser saxParser = parserFactory.newSAXParser();
        // 创建用于存储解析结果的学生列表
        final List<Student> studentList = new ArrayList<Student>();

        // 调用 saxParser.parse() 方法进行解析,传入 XML 文件路径和 DefaultHandler 对象
        saxParser.parse("xml02/students.xml", new DefaultHandler() {
            // 存储当前解析到的学生对象
            private Student student = null;
            // 标记当前解析的标签类型
            private int flag = 0;

            // 解析开始标签时调用
            public void startElement(String uri, String localName, String qName, Attributes attributes)
                    throws SAXException {
                if ("student".equals(qName)) {
                    // 创建新的学生对象
                    student = new Student();
                    // 获取并设置学生对象的 id 属性
                    String id = attributes.getValue("id");
                    if (id != null && id.trim().length() > 0)
                        student.setId(id);
                } else if ("name".equals(qName))
                    flag = 1;
                else if ("age".equals(qName))
                    flag = 2;
                else if ("sex".equals(qName))
                    flag = 3;
            }

            // 解析字符数据时调用
            @Override
            public void characters(char[] ch, int start, int length) throws SAXException {
                // 获取字符数据并去除首尾空格
                String tmp = new String(ch, start, length);
                if (tmp != null && tmp.trim().length() > 0) {
                    // 根据 flag 的值设置学生对象的相应属性
                    if (flag == 1)
                        student.setName(tmp.trim());
                    else if (flag == 2) {
                        Integer kk = Integer.parseInt(tmp.trim());
                        student.setAge(kk);
                    } else if (flag == 3)
                        student.setSex(tmp.trim());
                }
            }

            // 解析结束标签时调用
            @Override
            public void endElement(String uri, String localName, String qName) throws SAXException {
                flag = 0;
                if ("student".equals(qName))
                    // 将解析完成的学生对象添加到列表中
                    studentList.add(student);
            }
        });

        // 打印学生列表中的每个学生对象
        studentList.forEach(System.out::println);
    }
}

 

    以上的代码是逐行扫描 XML 文件并根据标签的不同进行处理。通过实现 DefaultHandler 类,可以在解析的各个阶段进行相应的操作。

    在这个例子中,解析过程中遇到 “student” 标签时会创建一个新的 Student 对象,然后解析该标签下的子标签并设置学生对象的属性。最后,遇到 “student” 结束标签时,将解析完成的学生对象添加到学生列表中。

PS:以上代码中用到了一个 Student 类,你可以定义一个 Student 类来表示学生的属性和行为。

【SpringBoot对JSON数据的返回】

一、返回JSON格式数据的方法

    早期数据传输使用 xml 作为交互格式,例如 webservice 技术,但是由于 xml 解析比较麻烦,所以现在在项目开发中,在接口与接口之间以及前后端之间数据的传输都使用 Json 格式,在 Spring Boot 中接口返回 Json 格式的数据很简单,在 Controller 中使用@RestController 注解即可返回 Json 格式的数据,@RestController 也是Spring Boot 新增的一个复合注解。

    我们可以看一下它的源代码:

/*用于声明另一个注解可以使用在什么地方。在这个例子中,@Target({ElementType.TYPE}) 意味着 @RestController 注解可以被应用于类上。*/
@Target({ElementType.TYPE})
/* 用于声明另一个注解需要保持到什么阶段。RetentionPolicy.RUNTIME 表示这个注解在编译生成的字节码中会一直保持到运行时。也就是说,这个注解可以通过 Java 反射机制在运行时获取到。*/
@Retention(RetentionPolicy.RUNTIME)
/*这个注解用于指示被注解的元素可以被包含在文档中。常用于生成 API 文档或其他类似的文档。*/
@Documented
/*这个注解用于标识一个类是 MVC 架构中的控制器。在 Spring 框架中,@Controller 注解常用于处理 HTTP 请求和返回视图。*/
@Controller
/*这个注解用于标识一个方法或类的返回值需要被转换为 HTTP 响应体。通常与 @Controller 注解一起使用,用于返回 JSON、XML 或其他格式的数据给客户端。*/
@ResponseBody
public @interface RestController {
//@RestController,这个注解是由上述的注解组合而成的一个自定义注解。它结合了 @Controller 和 @ResponseBody 的功能,并可以通过 value 属性指定自定义的值。
    String value() default "";
}

    可 以 看 出 @RestController 注 解 包 含 了 原 来 的 @Controller @ResponseBody 注 解 , 使 用 过 Spring @Controller 注解用于声明当前类是控制器类,@ResponseBody 注解是将返回的数据结构转换为 Json 格式。

    所以在默认情况下,使用了@RestController 注解即可将返回的数据结构转换成 Json 格式,Spring Boot 中默认使用的 Json 解析技术框架是 jackson

点开 pom.xml 中的 spring-boot-starter-web 依赖,可以看到一个spring-boot-starter-json 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <scope>compile</scope>
</dependency>

    Spring Boot 中对依赖都做了很好的封装,可以看到很多 spring-boot-starter-xxx 系列的依赖,这是 Spring Boot的特点之一,不需要人为去引入很多相关的依赖了,starter-xxx 系列直接都包含了所必要的依赖,所以再次点进去上面这个 spring-boot-starter-json 依赖,可以看到:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
    <scope>compile</scope>
</dependency>

    到此为止,我就知道了 Spring Boot 中默认使用的 json 解析框架是 jackson。默认的 jackson 框架对常用数据类型的转 Json 处理。

二、SpringBoot对JSON的默认处理

    在我做一些小的实际项目中,常用的数据结构无非有三种:类对象、List 对象、Map 对象,默认的 jackson 框架对这三个常用的数据结构都可以转成 json 的格式。非常的方便。下面我将给出我的处理顺序:

1.创建名为USer的实体类

public class User {
   private Long id;
   private String username;
   private String password;
  /* 省略 get、set 和带参构造方法,或者可以使用@Data注释对此类进行声明,这样可以省下构造getter、setter方法 */
}

2.创建 Controller

 

//分别返回 User 对象、List<User>和 Map<String, Object> 
@RestController
@RequestMapping("/json")
public class JsonController {
    @RequestMapping("/user")
    public User getUser() {
        return new User(1, "躺平小伙", "123456");
    }

    @RequestMapping("/list")
    public List<User> getUserList() {
        List<User> userList = new ArrayList<>();
        User user1 = new User(1, "躺平小伙", "123456");
        User user2 = new User(2, "卷王", "123456");
        userList.add(user1);
        userList.add(user2);
        return userList;
    }

    @RequestMapping("/map")
    public Map<String, Object> getMap() {
        Map<String, Object> map = new HashMap<>(3);
        User user = new User(1, "躺平小伙", "123456");
        map.put("作者信息", user);
        map.put("博客地址", "http://www.cnblog.com/TPwang");
        map.put("粉丝数量", 0);
        return map;
    }
}

3.在浏览器中测试结果

    写好了接口,分别返回了一个 User 对象、一个 List 集合和一个 Map 集合,其中 Map 集合中的 value 存的是不同的数据类型在浏览器中输入:

localhost:8080/json/user

localhost:8080/json/list

localhost:8080/json/map

    以上三个网址来测试是否返回前端的数据为JSON格式。

4.jackson 中对 null 的处理

    在项目中,难免会遇到一些 null 值出现,转 json 时是不希望有这些 null 出现的,比如期望所有的 null 在转 json 时都变成""这种空字符串,那怎么做呢?在 Spring Boot 中做一下配置即可,新建一个 jackson 的配置类:

    @Configuration //用于声明当前类是一个配置类,最新的注解为@SpringBootConfiguration
    public class JacksonConfig {
        @Bean //用于在配置类中,表示方法的返回值是一个受管 bean
        @Primary //如果多个配置,则以当前的为主
        @ConditionalOnMissingBean(ObjectMapper.class) //条件注解,表示如果受管 bean 中没有 ObjectMapper类型的对象,则需要构建
        public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
            ObjectMapper objectMapper = builder.createXmlMapper(false).build();
            objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
                @Override
                public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                        throws IOException {
                    jsonGenerator.writeString(""); 针对 null 内容输出空字符串
                }
            });
            return objectMapper;
        }
    }
    //然后修改一下上面返回 map 的接口,将几个值改成 null 测试一下:
    @RequestMapping("/map")
    public Map<String, Object> getMap() {
        Map<String, Object> map = new HashMap<>(3);
        User user = new User(1, "躺平小伙", null);
        map.put("作者信息", user);
        map.put("博客地址", "http://www.cnblog.com/TPwang");
        map.put("CSDN 地址", null);
        map.put("粉丝数量", 0);
        return map;
    }

    重启项目再次输入 localhost:8080/json/map,可以看到 jackson 已经将所有 null 字段转成了空字符串了。

 

 

 
posted @ 2023-07-23 23:12  躺平小伙  阅读(2622)  评论(0编辑  收藏  举报