SpringBoot学习之路(二):对XML文件的解析和JSON数据的返还
【对xml文件的解析】
一、为什么要对xml文件进行解析
-
配置文件:在传统的 Java 开发中,很多项目使用 XML 文件作为配置文件来定义应用程序的行为。Spring Boot 支持通过解析 XML 文件来读取和加载配置信息,以便在应用程序中进行相应的配置。
Spring 框架集成:Spring 框架本身支持通过 XML 文件来定义和配置应用程序的组件和依赖关系。Spring Boot 可以解析和加载这些 XML 配置文件,使得开发者可以方便地集成和使用 Spring 框架的各种功能。
-
兼容性:许多遗留的项目和第三方库可能仍然使用 XML 文件作为配置文件。Spring Boot 的目标是提供一种简化和快速开发的方式,同时也要保持与现有项目和库的兼容性,所以它需要支持解析和处理 XML 文件。
总之,Spring Boot 对 XML 文件进行解析是为了 常见的解析工具有 DOM4j、JDOM 等,为了标准化 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 字段转成了空字符串了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)