Spring Boot如何实现返回columns泛型列表的GET查询接口
核心问题
你当前代码无法实现泛型返回的原因有三个:
- 泛型仅在Controller层做了声明,Java泛型存在运行时类型擦除机制,Jackson无法获取实际反序列化目标类型,无法输出对应结构的对象
- Service层逻辑写死了反序列化目标为
AnalyticIcon类,无法适配不同table_name对应不同columns结构的需求 - Controller层直接返回整个Config对象,没有单独解析
columns字段,和接口需求不匹配
实现步骤
1. 维护表名与列结构的映射关系
服务端可以明确知道每个table_name对应的columns JSON结构,先统一维护映射关系,后续新增配置只需要加映射即可:
import java.util.Map; // 配置表名和对应columns实体类的映射 public class ConfigTypeMapping { public static final Map<String, Class<?>> TABLE_TYPE_RELATION = Map.of( "table1", Table1ColumnConfig.class, "analyticIcon", AnalyticIcon.class // 后续新增配置表在此追加映射 ); }
提前按照JSON结构编写对应的POJO类,比如Table1ColumnConfig对应第一条配置里的id、analyticId、propertytype、minVal、maxVal、StringVal、caseElse、result字段,AnalyticIcon对应第二条配置的字段,普通实体类加@Data注解即可。
2. 改造Service层
把写死类型的方法改成通用泛型方法,通过Jackson的JavaType解决泛型擦除问题:
Service接口
import java.util.List; public interface ConfigService { // 原有已实现方法保留 List<Config> getAllConfig(); Config getConfigValueByTableName(String tableName); // 新增泛型方法 <T> List<T> getColumnsByTableName(String tableName); <T> void updateColumnsByTableName(String tableName, List<T> columns); }
ServiceImpl实现
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service @RequiredArgsConstructor public class ConfigServiceImpl implements ConfigService { private final ConfigDAO configDAO; private final ConfigMapper configMapper; // 直接注入Spring全局ObjectMapper,不要自己new,避免序列化配置不一致 private final ObjectMapper objectMapper; @Override public List<Config> getAllConfig() { // 原有逻辑保留 return null; } @Override public Config getConfigValueByTableName(String tableName) { // 原有逻辑保留 return null; } @Override public <T> List<T> getColumnsByTableName(String tableName) { Optional<ConfigEntity> entityOpt = configDAO.findByTableName(tableName); if (entityOpt.isEmpty()) { // 查不到可以返回空列表,也可以抛自定义业务异常 return List.of(); } ConfigEntity entity = entityOpt.get(); String columnsJson = entity.getColumns(); // 获取当前表对应的目标实体类型 Class<?> targetType = ConfigTypeMapping.TABLE_TYPE_RELATION.get(tableName); if (targetType == null) { throw new IllegalArgumentException("未配置表["+ tableName +"]对应的列结构类型"); } try { // 构造泛型集合类型,解决类型擦除问题,避免返回List<LinkedHashMap> JavaType listType = objectMapper.getTypeFactory() .constructCollectionType(List.class, targetType); return objectMapper.readValue(columnsJson, listType); } catch (Exception e) { throw new RuntimeException("解析表["+ tableName +"]配置失败", e); } } @Override public <T> void updateColumnsByTableName(String tableName, List<T> columns) { Optional<ConfigEntity> entityOpt = configDAO.findByTableName(tableName); if (entityOpt.isEmpty()) { throw new IllegalArgumentException("配置表["+ tableName +"]不存在"); } ConfigEntity entity = entityOpt.get(); try { String json = objectMapper.writeValueAsString(columns); entity.setColumns(json); configDAO.save(entity); } catch (Exception e) { throw new RuntimeException("更新表["+ tableName +"]配置失败", e); } } }
3. 改造Controller层
直接调用Service层的泛型方法,返回解析后的columns列表即可:
import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/config") @RequiredArgsConstructor public class ConfigController { private final ConfigService configService; // 原有已实现接口保留 @GetMapping("/all") public ResponseEntity<List<Config>> getAll() { return ResponseEntity.ok(configService.getAllConfig()); } @GetMapping("/detail") public ResponseEntity<Config> getByTableName(@RequestParam String tableName) { return ResponseEntity.ok(configService.getConfigValueByTableName(tableName)); } // 查询columns接口 @GetMapping("/columns") public ResponseEntity<?> getColumns(@RequestParam String tableName) { return ResponseEntity.ok(configService.getColumnsByTableName(tableName)); } // 更新columns接口 @PutMapping("/columns") public ResponseEntity<Void> updateColumns( @RequestParam String tableName, @RequestBody List<?> columns ) { configService.updateColumnsByTableName(tableName, columns); return ResponseEntity.ok().build(); } }
注意事项
- 不要在业务代码中自行
new ObjectMapper(),直接注入Spring Boot自动配置的全局单例ObjectMapper,保证日期格式、空值处理、命名策略等和全局配置一致 - 编写对应POJO类时,如果JSON字段名和Java字段名不匹配,用
@JsonProperty注解做映射 - 后续新增配置表时,只需要编写对应columns结构的POJO类,再在
ConfigTypeMapping中追加表名和类的映射即可,不需要修改核心业务逻辑 - 之前写死类型的
getAnalyticIconValues方法可以直接删除,通用泛型方法会统一处理所有表的解析逻辑
内容的提问来源于stack exchange,提问作者Doncarlito87
相关产品推荐
相关产品推荐

