You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA Projections与DTO接口获取JSON数组时转义字符问题

问题描述

我有一个用于关联查询多表数据的DTO接口HRJobsDTO,定义如下:

public interface HRJobsDTO {

    String getEditorName();

    String getEditorId();

    String getBillingMonth();

    Integer getEditorWordCount();

    Integer getJobCount();

    Integer getEmployeeGrade();

    Float getGrossPayableAmount();

    Float getJobBillingRate();

    Float getTaxDeduction();

    Float getTaxDeductionAmount();

    Float getNetPayableAmount();

    String getInvoiceStatus();

    String getFreelanceInvoiceId();
}

其中getFreelanceInvoiceId()方法借助MySQL的json_arrayagg函数返回JSON数组,但我尝试将该字段类型改为String、String[]和ArrayList后,返回的响应中该字段始终是带转义字符的字符串形式数组:

"freelanceInvoiceId": "[\"4af9e342-065b-4594-9f4f-a408d5db9819/2022121-95540\", \"4af9e342-065b-4594-9f4f-a408d5db9819/2022121-95540\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\"]"

请问如何让该字段返回不含转义字符的纯数组格式?

解决方案

方法1:用Jackson手动解析字符串为数组

在返回数据前,将freelanceInvoiceId的字符串内容解析为List<String>或String[],替换原字段返回:

ObjectMapper objectMapper = new ObjectMapper();
// 假设dto是HRJobsDTO的实例
List<String> invoiceIds = objectMapper.readValue(
    dto.getFreelanceInvoiceId(),
    new TypeReference<List<String>>() {}
);

如果是Spring环境,也可以在DTO中通过默认方法自动处理:

public interface HRJobsDTO {
    // 其他方法保持不变
    String getFreelanceInvoiceId();

    @JsonGetter("freelanceInvoiceId")
    default List<String> getParsedFreelanceInvoiceId() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(getFreelanceInvoiceId(), new TypeReference<List<String>>() {});
    }
}

注意要处理JsonProcessingException,可统一捕获或向上抛出。

方法2:修改JPA查询,直接映射为集合

借助Hibernate的JSON类型支持,将查询结果直接映射为List<String>:

  1. 先添加Hibernate类型依赖(Maven):
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.19.2</version>
</dependency>
  1. 修改DTO的字段类型并标注类型:
public interface HRJobsDTO {
    // 其他方法保持不变
    @Type(type = "json")
    List<String> getFreelanceInvoiceId();
}
  1. 调整JPA查询,将聚合结果转为JSON类型:
SELECT 
    -- 其他字段
    CAST(json_arrayagg(f.invoice_id) AS JSON) AS freelanceInvoiceId
FROM your_table
-- 关联查询逻辑
GROUP BY ...

这样Hibernate会自动将JSON数组映射为List<String>,返回时直接是纯数组格式。

方法3:自定义JSON反序列化器

在DTO字段上添加@JsonDeserialize注解,指定自定义解析器自动处理:

public interface HRJobsDTO {
    // 其他方法保持不变
    @JsonDeserialize(using = JsonArrayToListDeserializer.class)
    List<String> getFreelanceInvoiceId();
}

自定义反序列化器实现:

public class JsonArrayToListDeserializer extends JsonDeserializer<List<String>> {
    @Override
    public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String jsonStr = p.getText();
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(jsonStr, new TypeReference<List<String>>() {});
    }
}

这种方式会在序列化响应时自动完成解析,无需手动处理。

方法4:改用JPA关联查询替代聚合函数

如果业务允许,可放弃json_arrayagg,通过JPA的@OneToMany关联关系获取发票ID列表,这样返回的直接是集合类型,不会出现转义问题。但需要调整实体类的关联逻辑,适合数据量较小的场景。


内容的提问来源于stack exchange,提问作者Siddhant Bhandari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 16:32:22