详解Struts2中json 相互引用死循环解决办法

下面是详解Struts2中json 相互引用死循环解决办法的完整攻略。

简介

在 Struts2 中,使用 JSON 返回数据时,如果包含相互引用的对象,就会出现死循环的情况。这是因为在序列化时,对象互相引用,导致 Gson 序列化器无法判断对象的终止条件从而产生栈溢出。解决这个问题的方法是给予 JSON 序列化器一些帮助,在序列化时忽略相互引用的部分。

解决方案

1. 使用 Jackson 序列化器

Jackson 是一个高性能的 JSON 序列化库,它支持完全的 JSON 规范并且可以与大量的 Java 框架集成。在 Struts2 的配置文件中,将默认的 JSON 序列化器 Gson 改为 Jackson 即可解决相互引用的问题。

<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.JacksonJaxbJsonMapper"/>

2. 添加 Jackson 库对相互引用的支持

在上一步中,将默认的 JSON 序列化器改为了 Jackson,但是默认情况下 Jackson 也无法处理相互引用的问题。需要添加 Jackson 库对相互引用的支持。

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {

    private Long id;
    private String name;
    private Group group;

    // getters and setters
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Group {

    private Long id;
    private String name;
    private List<User> users;

    // getters and setters
}

在类上添加 @JsonIdentityInfo 注解,其中 generator 属性指定了序列化时采用的引用生成器,property 属性指定了生成的引用标识属性。这样,在序列化时,只要检测到两个对象 id 相同,就会进行引用替换,从而避免了相互引用的死循环问题。

示例

例1:Gson 序列化器

public class User {

    private Long id;
    private String name;
    private Group group;

    // getters and setters
}

public class Group {

    private Long id;
    private String name;
    private List<User> users;

    // getters and setters
}

public class JsonAction extends ActionSupport {

    private List<Group> groups;

    // getters and setters

    public String execute() throws Exception {
        groups = new ArrayList<Group>();

        Group group1 = new Group();
        group1.setId(1L);
        group1.setName("Group 1");

        Group group2 = new Group();
        group2.setId(2L);
        group2.setName("Group 2");

        groups.add(group1);
        groups.add(group2);

        User user1 = new User();
        user1.setId(1L);
        user1.setName("User 1");
        user1.setGroup(group1);

        User user2 = new User();
        user2.setId(2L);
        user2.setName("User 2");
        user2.setGroup(group2);

        User user3 = new User();
        user3.setId(3L);
        user3.setName("User 3");
        user3.setGroup(group1);

        group1.setUsers(Arrays.asList(user1, user3));
        group2.setUsers(Arrays.asList(user2));

        return SUCCESS;
    }

    public String toJson() {
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("application/json;charset=utf-8");

        Gson gson = new Gson();
        String json = gson.toJson(groups);

        try {
            response.getWriter().write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}

上述示例中使用了 Gson 序列化器,在执行 toJson 方法时返回字串完全错误。出现死循环的原因是 Group 中包含了多个 User 对象,User 中包含了一个 Group,导致序列化时出现了循环引用。

例2:Jackson 序列化器

<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.JacksonJaxbJsonMapper"/>
public class User {

    private Long id;
    private String name;

    @JsonIgnoreProperties("users")
    private Group group;

    // getters and setters
}

public class Group {

    private Long id;
    private String name;

    @JsonManagedReference
    private List<User> users;

    // getters and setters
}

public class JsonAction extends ActionSupport {

    private List<Group> groups;

    // getters and setters

    public String execute() throws Exception {
        groups = new ArrayList<Group>();

        Group group1 = new Group();
        group1.setId(1L);
        group1.setName("Group 1");

        Group group2 = new Group();
        group2.setId(2L);
        group2.setName("Group 2");

        groups.add(group1);
        groups.add(group2);

        User user1 = new User();
        user1.setId(1L);
        user1.setName("User 1");
        user1.setGroup(group1);

        User user2 = new User();
        user2.setId(2L);
        user2.setName("User 2");
        user2.setGroup(group2);

        User user3 = new User();
        user3.setId(3L);
        user3.setName("User 3");
        user3.setGroup(group1);

        group1.setUsers(Arrays.asList(user1, user3));
        group2.setUsers(Arrays.asList(user2));

        return SUCCESS;
    }

    public String toJson() {
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("application/json;charset=utf-8");

        ObjectMapper mapper = new ObjectMapper();
        String json = null;

        try {
            json = mapper.writeValueAsString(groups);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            response.getWriter().write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}

上述示例中使用了 Jackson 序列化器,在执行 toJson 方法时正确地序列化了数据,避免了死循环的问题。在 User 类中,使用了 @JsonIgnoreProperties 注解,排除了序列化 users 属性,从而避免了嵌套序列化的问题。在 Group 类中,使用了 @JsonManagedReference 注解,指定了 users 属性为父对象,在反序列化时会自动添加到父对象中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Struts2中json 相互引用死循环解决办法 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Servlet服务端实现原理详解

    一、Servlet服务端实现原理 在Web应用中,服务端可以通过Java的Servlet技术实现对客户端(浏览器)的响应。Servlet是运行在服务端的Java程序,实现了应用服务器与客户端(浏览器)之间的通讯和数据交换。Servlet是一种通用的、基于Java的服务器端组件技术,它是在服务器端动态生成Web页面或进行数据处理的主要手段之一。 Servlet…

    Java 2023年6月15日
    00
  • SpringMVC的五大核心组件用法及说明

    以下是关于“SpringMVC的五大核心组件用法及说明”的完整攻略,其中包含两个示例。 SpringMVC的五大核心组件用法及说明 SpringMVC是Spring框架的一个模块,它是一个基于MVC(Model-View-Controller)架构的Web框架,用于构建Web应用程序。SpringMVC的五大核心组件包括DispatcherServlet、H…

    Java 2023年5月16日
    00
  • 在spring boot中使用java线程池ExecutorService的讲解

    下面就详细讲解一下“在springboot中使用java线程池ExecutorService”的完整攻略。 1. 概述 在应用程序中,我们通常需要进行一些异步的操作,例如发送邮件、短信通知等,这些操作不应该阻塞主线程的执行。Java中提供了线程池ExecutorService来帮助我们完成这些异步操作,它能够维护一定数量的线程来处理任务,避免了每次需要处理任…

    Java 2023年5月15日
    00
  • Java 通过mave命令下载jar包的示例代码

    当需要使用 Maven 管理 Java 项目的依赖时,通常需要通过 Maven 命令下载 jar 包文件。下面是操作步骤: 安装 Maven 首先需要安装 Maven 工具。这里假设您已经安装了 Maven。 步骤一:创建项目 首先创建一个基于 Maven 的 Java 项目。可以使用 Eclipse 或 Intellij IDEA 等集成开发环境创建。 步…

    Java 2023年5月20日
    00
  • Java如何实现自定义异常类

    Java允许用户通过继承Exception或RuntimeException类来创建自定义异常类。下面是实现自定义异常类的步骤: 步骤1:创建自定义异常类 用户可以创建自己的异常类,继承Exception或RuntimeException。 public class MyException extends Exception { public MyExcep…

    Java 2023年5月27日
    00
  • Java复合语句的使用方法详解

    Java复合语句的使用方法详解 介绍 Java中,复合语句是指一个包含多条语句的语句块,被括号{ }包围,它可以被作为一个单独的语句来使用,是控制语句、方法、类等程序块体的基础。本文将详细讲解Java复合语句的使用方法,包括复合语句的定义、使用场景、语法格式以及示例。 定义 在Java中,复合语句的定义即定义一组语句,这些语句被包含在一对花括号{ }中。在复…

    Java 2023年5月20日
    00
  • SpringSecurity添加图形验证码认证实现

    下面我来为你讲解SpringSecurity添加图形验证码认证实现的完整攻略。 1. 引入依赖 在pom.xml文件中添加以下依赖: <!–验证码依赖–> <dependency> <groupId>com.github.axolo</groupId> <artifactId>image-ver…

    Java 2023年5月20日
    00
  • Spring Boot定时器创建及使用解析

    Spring Boot定时器创建及使用解析 1. 概述 Spring Boot提供了丰富的定时任务的支持,其中最常用的是基于注解的定时任务。通过在方法上添加@Scheduled注解,即可实现对应的定时任务调度。 2. 添加依赖 在使用Spring Boot的定时任务功能前,我们需要先在pom.xml文件中添加对应的依赖: <dependency>…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部