Spring boot 3 API 响应升级问题

问题描述 投票:0回答:1

我正在将当前的 Spring Boot 2.6.7 升级到 Spring Boot 3.1.4。我已经更新了所有依赖项并重新导入了所有必需的包。这是一个多租户应用程序。

我正在使用 Postgres 数据库。为了获取 JSON 格式的查询结果,我正在按以下格式编写本机查询

select Row_to_json(list) as response, row_number() over() as id from (
select * from sch.employees )list

下面是将实体管理器中的结果提取为所需格式的代码。

public <T> Optional<List<T>> getResultList(String[] parametersName, Object[] parametersValues, Class<T> klazz,
          String queryString) {
      try {
          Query nativeQuery = em.createNativeQuery(queryString, NativeQueryResponse.class);
          for (int i = 0; i < parametersName.length; i++) {
              nativeQuery.setParameter(parametersName[i], parametersValues[i]);
          }
          List<NativeQueryResponse<T>> details = nativeQuery.getResultList();
          Type typeOfT = TypeToken.getParameterized(List.class, klazz).getType();

          List<T> response;
          if (!details.isEmpty() && details.get(0).getResponse() instanceof List) {
              response = (List<T>) details.get(0).getResponse();
          } else {
              response = details.stream().map(NativeQueryResponse::getResponse)
                      .collect(Collectors.toCollection(ArrayList::new));
          }

          em.clear();
          return Optional.of(gson.fromJson(gson.toJson(response), typeOfT));
      } catch (Exception e) {
          log.error("error while executing query {} with parameters as {} and parameters values as {} ", queryString,
                  parametersName, parametersValues);
          CommonUtils.printStackTrack(e);
          return Optional.empty();
      }
  }

它也返回数据并最终将其映射到所需的对象。下边是 它映射到的类。

public class NativeQueryResponse<T> {
    @Id
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @Type(JsonType.class)
    @Column(columnDefinition = "jsonb")
    T response;

}

它也在创建员工对象列表。在我的班级下面要反序列化。

@Setter
@Getter
public class Employee {
    
    @SerializedName(value = "id")
    private Long id;

    @SerializedName(value = "first_name")
    private String firstName;

    @SerializedName(value = "middle_name")
    private String middleName;

    @SerializedName(value = "dob")
    private String dob;
}

即使在控制器层,我也可以看到员工列表,其每个属性都填充了数据,但是在返回响应时,它不会在定义的java属性中发送响应,而是以我定义的serializedName发送响应

{
    "id": 1,
    "first_name": "User 1",
    "middle_name": "M name",
    "dob": ""
}

预计是

{
    "id": 1,
    "firstName": "User 1",
    "middleName": "M name",
    "dob": ""
}

我什至浏览了github链接,上面说的是定义

spring.http.converters.preferred-json-mapper:gson

但即使在那之后,它仍然在我为 SerializedName 定义的属性中返回 API 响应,或者就像我们从数据库查询返回的那样。

以下是应用程序中当前的春季安全更新

@Bean
  SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
      http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(
              request -> request.requestMatchers(HttpMethod.OPTIONS).permitAll().requestMatchers("/**").permitAll())
              .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
              .addFilterBefore(new AuthenticationFilter(environment), UsernamePasswordAuthenticationFilter.class);
      return http.build();
  }

更多配置细节以供更多分析。

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <project.reports.dir>${basedir}/target/reports</project.reports.dir>
        <java.version>20</java.version>
        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
        <json-path.version>2.4.0</json-path.version>
        <org.projectlombok.version>1.18.24</org.projectlombok.version>
        <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
        <log4j2.version>2.17.0</log4j2.version>

我不确定具体问题出在哪里。每个API都是这样的,但是如果我使用JPA存储库来获取API中的数据,它们会正确返回结果。只有当我使用GSON反序列化时才会出现这个问题。

如果上述实施似乎不正确或未作为最佳实践的一部分正确实施,请提出建议。

spring spring-boot spring-security gson spring-boot-3
1个回答
0
投票

您的序列化器正在完全按照您的要求进行操作。您甚至不需要考虑导致创建员工列表的所有逻辑;您需要知道的是,您有一份员工列表,但这些员工没有按照您认为应该的方式进行序列化。

考虑这个测试

@Test
public void testIt() {
    List<Employee> employees = new ArrayList<>();
    employees.add(Employee.builder().firstName("bob").middleName("middle bob").build());
    employees.add(Employee.builder().firstName("bill").middleName("middle bill").build());

    Assertions.assertEquals("[{\"firstName\":\"bob\",\"middleName\":\"middle bob\"},{\"firstName\":\"bill\",\"middleName\":\"middle bill\"}]", new Gson().toJson(employees));
}

如果你现在运行它,它将失败并显示

org.opentest4j.AssertionFailedError: 
Expected :[{"firstName":"bob","middleName":"middle bob"},{"firstName":"bill","middleName":"middle bill"}]
Actual   :[{"first_name":"bob","middle_name":"middle bob"},{"first_name":"bill","middle_name":"middle bill"}]

现在,删除 Employee 类上的那些注释,这些注释专门告诉序列化器将

firstName
序列化为
first_name
middleName
middle_name
,然后再次运行测试。这次你的测试将通过。

您的序列化正在完全按照您的指示进行。如果在您之前的实现中,即使您将

SerializedName
设置为
first_name
,它仍将firstName 序列化为firstName,那么这是因为您在之前的版本中出现了错误。

© www.soinside.com 2019 - 2024. All rights reserved.