Spring возвращает измененный JSONObject с помощью @ResponseBody

#java #json #spring #rest

#java #json #spring #rest

Вопрос:

Я использую 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"
  }
}
  

Здесь объект, возвращаемый моим контроллером, оборачивается в объект map, а затем возвращается Spring.

Может кто-нибудь сказать мне, что здесь не так. Любая помощь будет оценена. 🙂

Комментарии:

1. Вернуть ученика будет в порядке 😉

Ответ №1:

spring mvc использует привязку данных Джексона для сериализации объекта в JSON / десериализации JSON в объект. Поэтому нет необходимости возвращать JSONObject с помощью @ResponseBody . Есть какой-то способ:

Определите класс (объект просмотра) с необходимыми полями, затем создайте, заполните экземпляр и верните его.

Используйте 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(PO) с надлежащими аннотациями Джексона для класса Student(https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations ). Если вы хотите ограничить возвращаемые поля, вы можете добавить аннотацию 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);
  }
}
  

Комментарии:

1. Согласен. @ResponseBody уже делает это неявно. Нет необходимости повторно реализовывать его внутри вашего метода.

2. Спасибо. Просто продолжение. Итак, по сути, это означает, что мне нужно вернуть представление карты моего объекта или модели, которая представляет ответ, а аннотация @ ResponseBody позаботится о создании ответа JSON из этого объекта.

3. Как упоминал Тарсан Сивакумар, вы можете использовать Student напрямую с надлежащими аннотациями Джексона.

Ответ №2:

Предположим, у вас уже есть класс student с этими свойствами. Следовательно, то, что вы можете сделать, это просто вернуть объект, как показано ниже, надеюсь, это должно сработать.

 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
}
  

Комментарии:

1. ‘DateFormat df = new SimpleDateFormat(«гггг-ММ-дд ЧЧ:мм:сс»); попробуйте { date = String.valueOf(df.parse(student.getSignUpDate()).getTime()); } catch (ParseException e) { e.printStackTrace(); }’

2. В приведенных выше строках кода я также форматирую дату, прежде чем возвращать фактический ответ. Так что было бы неплохо изменить существующий объект student и изменить дату, прежде чем возвращать объект. Я имею в виду, это хорошая практика программирования или плохая практика. Простите за цепочку комментариев; Я новичок в комментировании и задании вопросов и только начинаю привыкать к семантике комментариев SO.

3. Начиная с версии Jackson v2.0, вы можете использовать аннотацию @JsonFormat непосредственно для членов объекта. Следовательно, вы можете отформатировать его в своем классе Student самостоятельно, как показано ниже. @JsonProperty(«signUpDate») @JsonFormat(форма=JsonFormat. Форма. СТРОКА, шаблон=»гггг-ММ-дд ЧЧ: мм: сс») частная дата дата;

4. Отредактировал класс Student выше в ответе с отформатированной датой

5. спасибо @Tharsan Нужно ли мне добавлять зависимость Джексона в мой maven, потому что он не будет использовать @JsonProperty или что-то не так с моим проектом?

Ответ №3:

Вы можете просто вернуть student из метода контроллера, который spring выполнит маршалинг.

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

Но поскольку вы выполняете форматирование даты, я также предлагаю вам создать отдельный класс, что-то вроде StudentView и сопоставить student с 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){
  ......
}