返回 JSON 作为响应 Spring Boot

Posted

技术标签:

【中文标题】返回 JSON 作为响应 Spring Boot【英文标题】:Returning JSON as Response Spring Boot 【发布时间】:2019-07-27 14:31:29 【问题描述】:

我正在尝试以 json 形式获取休息响应,而不是以字符串形式获取。

控制器

@RestController
@RequestMapping("/api/")
public class someController

  @Autowired
  private SomeService someService;

  @GetMapping("/getsome")
  public Iterable<SomeModel> getData()
    return someService.getData();
  

服务

@Autowired
private SomeRepo someRepo;

public Iterable<someModel> getData()
  return someRepo.findAll();

存储库

public interface SomeRepo extends CrudRepository<SomeModel,Integer>


模型

@Entity
@Table(name="some_table")
public class SomeModel

  @Id
  @Column(name="p_col", nullable=false)
  private Integer id;
  @Column(name="s_col")
  private String name
  @Column(name="t_col")
  private String json;   // this column contains json data

  //constructors, getters and setters

当我运行 localhost:8080/api/getsome 我得到:

[
 
    "p_col":1,
    "s_col":"someName",
    "t_col":" 
\r\n\t"school_name\":\"someSchool\",\t\r\n\t"grade\":"A\",\r\n\t\"class\": 
 [\"course\":"abc",\t"course_name\":\"def" ]"
  
]

字段 t_col 正在返回字符串而不是 json。如何获取 json 对象作为响应?

对于数据库,三列分别是int、varchar和varchar。

任何帮助将不胜感激。谢谢!!

【问题讨论】:

您必须管理从其余端点接收到的 json 到您将其存储在数据库中的字符串字段的转换。 Couriosuly 我几天前在下一个问题***.com/questions/54975002/… 中回答了同样的问题 【参考方案1】:

将您的 DB 答案从 findAll 转换为对象类型列表,例如 (List of Sometype),然后返回数据。这将解决您的问题。

【讨论】:

【参考方案2】:

像这样改变你的一些模型类

@Entity
@Table(name="some_table")
public class SomeModel 

    @Id
    @Column(name="p_col", nullable=false)
    private Integer id;
    @Column(name="s_col")
    private String name
    @Column(name="t_col")
    private String json;   // this column contains json data

    @Column(name = "t_col", columnDefinition = "json")
    @Convert(attributeName = "data", converter = JsonConverter.class)
    private Map<String, Object> json = new HashMap<>();

    //constructors
    //getters and setters

编写一个 json 转换器类。

@Converter
public class JsonConverter
                    implements AttributeConverter<String, Map<String, Object>> 



    @Override
    public Map<String, Object> convertToDatabaseColumn(String attribute)
    
        if (attribute == null) 
           return new HashMap<>();
        
        try
        
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(attribute, HashMap.class);
        
        catch (IOException e) 
        
        return new HashMap<>();
    

    @Override
    public String convertToEntityAttribute(Map<String, Object> dbData)
    
        try
        
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(dbData);
        
        catch (JsonProcessingException e)
        
            return null;
        
    

它将数据库 json 属性转换为您想要的结果。谢谢

【讨论】:

【参考方案3】:

您需要将您的 json 属性定义为 JsonNode,以便 jackson 可以将其读取并转发,但标记为 @Transient,因此 JPA 不会尝试将其存储在数据库中。

然后您可以为 JPA 编写 getter/setter 代码,您可以在其中从 JsonNode 来回转换为 String。您定义了一个 getter getJsonStringJsonNode json 转换为 String。那个可以映射到一个表列,比如'json_string',然后你定义一个setter,在那里你从JPA接收String并将它解析为JsonNode,这对jackson可用,然后jackson会将它转换为一个json对象不是你提到的字符串。

@Entity
@Table(name = "model")
public class SomeModel 

  private Long id;
  private String col1;

  //  Attribute for Jackson 
  @Transient
  private JsonNode json;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public Long getId() 
    return id;
  

  @Column(name ="col1")
  public String getCol1() 
    return col1;
  

  // Getter and setter for name

  @Transient
  public JsonNode getJson() 
    return json;
  

  public void setJson(JsonNode json) 
    this.json = json;
  

  // Getter and Setter for JPA use
  @Column(name ="jsonString")
  public String getJsonString() 
    return this.json.toString();
  

  public void setJsonString(String jsonString) 
    // parse from String to JsonNode object
    ObjectMapper mapper = new ObjectMapper();
    try 
      this.json = mapper.readTree(jsonString);
     catch (Exception e) 
      e.printStackTrace();
    
  

注意,@Column 是在 gettter 中定义的,因为我们需要指示 JPA 使用 getJsonString,而 JPA 需要一致性,因此所有列的 getter 都必须用 @Columns 标记。

【讨论】:

谢谢,它对我有用!如果我需要将 json 输入作为字符串保存在数据库中,它是如何工作的? 该部分已包含在解决方案中,您会看到当 JPA 尝试将 POJO 转换为插入语句时,它将执行 getJsonString 方法,因为它标记为 @Column like to jsonString 专栏。所以只要你有这样的 json/jsonString getter/setter,它就会像你预期的那样工作。 我尝试了各种方法使用 JsonNode 将原始 Json 对象保存到字符串,但无法正常工作。我收到以下错误“状态”:400、“错误”:“错误请求”、“消息”:“JSON 解析错误:无法从 START_OBJECT 令牌中反序列化 java.util.ArrayList 的实例;嵌套异常是 com.fasterxml.jackson。 databind.exc.MismatchedInputException: 无法在 [Source: (PushbackInputStream); line: 1, column: 1]", "trace": "org.springframework.http.converter. HttpMessageNotReadableException:JSON 解析 e 您需要更具体地了解您正在尝试制作的实现,在您提供的示例中,没有包含数组的元素。 对于 POST 映射,我提供以下控制器:@PostMapping("/saverawjson") public void saveRawJson(@RequestBody SomeModel someModel) //..... someRepository.save(someModel)我正在使用以下回购公共接口 SomeRepo extends CrudRepository【参考方案4】:
  @RequestMapping(value = "/getsome", method = RequestMethod.POST, consumes = 
  "application/json;")
 public @ResponseBody
  ModelAndView getSome(@RequestBody List<Map<String, String>> request) 
 request.stream().forEach(mapsData->
    mapsData.entrySet().forEach(mapData -> 
      System.Out.Println("key :"+mapData.getKey() + " " + 
        " value : " +mapData.getValue());
    );
  
);
return new ModelAndView("redirect:/home");

【讨论】:

【参考方案5】:

在您的控制器中添加 json 响应:

 @RequestMapping(value = "/getsome", method = RequestMethod.GET, produces = "application/json"

并将 getData 字符串包装为响应

    public class StringResponse 

        private String response;

        public StringResponse(String s)  
           this.response = s;
        


【讨论】:

有趣的快速修复,但在调用我的 API 时出现错误 406。它到底在等什么?

以上是关于返回 JSON 作为响应 Spring Boot的主要内容,如果未能解决你的问题,请参考以下文章

SpringDoc (spring boot) utf-8 json 标头响应文档

如何在 Spring Boot 中返回 JSON 响应?

Spring boot @ExceptionHandler 将响应返回为 html

在 Spring Boot OAUTH2 中返回 RESTful/json 响应而不是登录表单

如何在 Spring Boot 中覆盖默认 JSON 响应

Spring Boot 在 json 中包含 ID 字段