【问题标题】:Spring returns a modified JSONObject with @ResponseBodySpring 使用 @ResponseBody 返回一个修改后的 JSONObject
【发布时间】:2016-10-12 03:05:29
【问题描述】:

我正在使用 Spring MVC 并尝试从我的控制器返回一个 JSONObject 作为响应。我用 @ResponseBody 注释了该方法,以便它将控制器返回的 JSONObject 放入 ResponseBody。 这是我的控制器:

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private JSONObject getStudentDetails(@PathVariable(value="roll") String roll) {
    JSONObject response = new JSONObject();
    Student student = studentDAO.getStudent(roll);
    response.put("firstName",student.getFirstName());
    response.put("lastName",student.getLastName());
    response.put("roll",student.getRoll());
    response.put("email",student.getEmail());
    response.put("course",student.getCourse());
    response.put("stream",student.getStream());
    response.put("year",student.getYear());
    response.put("gender",student.getGender());
    String date = null;
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
        date = String.valueOf(df.parse(student.getSignUpDate()).getTime());
    } catch (ParseException e) {
        e.printStackTrace();
    }
    response.put("signUpDate", date);
    System.out.println("Response Body::::: "+response.toString());
    return response;
}

一个有效的响应应该是这样的:

{
  "firstName": "John",
  "lastName": "Doe",
  "gender": "M",
  "stream": "cse",
  "year": 3,
  "roll": "2013BT2011",
  "course": "btech",
  "signUpDate": "1476224877000",
  "email": "john@doe.com"
}

但我得到了这个:

{
  "map": {
    "firstName": "John",
    "lastName": "Doe",
    "gender": "M",
    "stream": "cse",
    "year": 3,
    "roll": "2013BT2011",
    "course": "btech",
    "signUpDate": "1476224877000",
    "email": "john@doe.com"
  }
}

这里,我的控制器返回的对象被包装成一个ma​​p对象,然后由Spring返回。

谁能告诉我这里出了什么问题。 任何帮助,将不胜感激。 :)

【问题讨论】:

  • 返校生会好的 ;)

标签: java json spring rest


【解决方案1】:

spring mvc 使用 jackson databind 将 Object 序列化为 JSON /将 JSON 反序列化为 Object。 因此不需要使用@ResponseBody 返回 JSONObject。 有一些办法:

用需要字段定义一个类(视图对象),然后 new ,填充一个实例并返回它。

使用 java.util.Map。所以你的代码将如下所示:

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private Map<String, Object> getStudentDetails(@PathVariable(value="roll") String roll) {
      Map<String, Object> response = new HashMap<>();
  Student student = studentDAO.getStudent(roll);
  response.put("firstName",student.getFirstName());
  response.put("lastName",student.getLastName());
  response.put("roll",student.getRoll());
  response.put("email",student.getEmail());
  response.put("course",student.getCourse());
  response.put("stream",student.getStream());
  response.put("year",student.getYear());
  response.put("gender",student.getGender());
  String date = null;
  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  try {
    date = String.valueOf(df.parse(student.getSignUpDate()).getTime());
  } catch (ParseException e) {
    e.printStackTrace();
  }
  response.put("signUpDate", date);
  System.out.println("Response Body::::: "+response.toString());
  return response;
}

您可以在 Student 类 (https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations) 上返回带有正确 Jackson 注释的 Student(PO)。如果要限制返回字段,可以添加JsonView注解。

public class Student {
  public static class Response {}
  private String firstName;
  private String lastName;
  private String roll;
  private String email;
  private String course;
  private String stream;
  private String year;
  private String gender;

  private Date getSignUpDate;

  @JsonView(Response.class)
  public String getFirstName() {
    return firstName;
  }

  @JsonView(Response.class)
  public String getLastName() {
    return lastName;
  }

  @JsonView(Response.class)
  public String getRoll() {
    return roll;
  }

  @JsonView(Response.class)
  public String getEmail() {
    return email;
  }

  @JsonView(Response.class)
  public String getCourse() {
    return course;
  }

  @JsonView(Response.class)
  public String getStream() {
    return stream;
  }

  @JsonView(Response.class)
  public String getYear() {
    return year;
  }

  @JsonView(Response.class)
  public String getGender() {
    return gender;
  }

  @JsonView(Response.class)
  @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
  public Date getGetSignUpDate() {
    return getSignUpDate;
  }
  /// setters are not written.
}


public class StudentCtl {

  @GetMapping(value="/student/{roll}",produces="application/json")
  @ResponseBody
  @JsonView(Student.Response.class)
  private Map<String, Object> getStudentDetails(@PathVariable(value="roll") String roll) {
    return studentDAO.getStudent(roll);
  }
}

【讨论】:

  • 同意。 @ResponseBody 已经隐含地做到了。无需在您的方法中重新实现它。
  • 谢谢。只是一个跟进。所以基本上,这意味着我需要返回我的对象​​的 Map 表示或表示响应的模型,并且 @ResponseBody 注释负责从该对象中生成 JSON 响应。
  • 正如 Tharsan Sivakumar 所提到的,您可以直接使用带有正确 Jackson 注释的 Student。
【解决方案2】:

假设您已经有具有这些属性的学生班级。因此,您可以做的就是简单地返回对象,如下所示,希望这应该可以工作。

private JSONObject getStudentDetails(@PathVariable(value="roll") String roll) {
    Student student = studentDAO.getStudent(roll);
    System.out.println("Response Body::::: "+response.toString());
    return student ;
}

即使你想更改这些字段的名称,你也可以像这样注释它们

class Student {
 @JsonProperty("firstName")
 private String fname;

 @JsonProperty("signUpDate") 
 @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss") 
  private Date date; 
 //getters
 //setters
}

【讨论】:

  • 'DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");尝试 { date = String.valueOf(df.parse(student.getSignUpDate()).getTime()); } catch (ParseException e) { e.printStackTrace(); }'
  • 在上面的代码行中,我还在返回实际响应之前格式化了日期。那么在返回对象之前修改现有的学生对象并更改日期是否是一个好主意。我的意思是,这是好的编程实践还是不好的实践。请原谅一连串的cmets;我是评论和提问的新手,只是开始习惯评论的 SO 语义。
  • 自Jackson v2.0 起,您可以直接在Object 成员上使用@JsonFormat 注解。因此,您可以在您的学生课程中自行格式化,如下所示。 @JsonProperty("signUpDate") @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss") 私人日期日期;
  • 在答案中使用格式化的日期编辑了上面的学生类
  • 谢谢@Tharsan 我是否需要在我的 maven 中添加 Jackson 依赖项,因为它不会采用 @JsonProperty 还是我的项目有问题?跨度>
【解决方案3】:

您可以简单地从 Controller 方法中返回 student,spring 将进行编组。

   @GetMapping(value="/student/{roll}",produces="application/json")
    @ResponseBody
    private Student getStudentDetails(@PathVariable(value="roll") String roll) {
       return studentDAO.getStudent(roll);            
    }

但由于您正在进行日期格式设置,我还建议您创建一个单独的类,例如 StudentView 并将学生映射到 StudentView

  class StudentView{
    private String signUpDate;
    ......
    ......
    }

并从控制器返回 studentView。所以它会是这样的

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private StudentView getStudentDetails(@PathVariable(value="roll") String roll) {
   Student student=studentDAO.getStudent(roll);            
   return toStudentView(student);
}

private static StudentView toStudentView(Student stu){
  ......
}

【讨论】:

    猜你喜欢
    • 2013-10-12
    • 2014-12-06
    • 2023-03-19
    • 2020-10-12
    • 2014-10-22
    • 1970-01-01
    • 2015-09-23
    • 2021-11-17
    • 2016-04-25
    相关资源
    最近更新 更多