Pertanyaan saya pada dasarnya adalah tindak lanjut dari pertanyaan ini .
@RestController
public class TestController
{
@RequestMapping("/getString")
public String getString()
{
return "Hello World";
}
}
Di atas, Spring akan menambahkan "Hello World" ke dalam isi respons. Bagaimana cara mengembalikan String sebagai respons JSON? Saya mengerti bahwa saya dapat menambahkan kutipan, tetapi itu lebih terasa seperti retasan.
Harap berikan contoh apa pun untuk membantu menjelaskan konsep ini.
Catatan: Saya tidak ingin ini ditulis langsung ke badan Respons HTTP, saya ingin mengembalikan String dalam format JSON (Saya menggunakan Pengontrol saya dengan RestyGWT yang memerlukan respons dalam format JSON yang valid).
Jawaban:
Baik kembali
text/plain
(seperti dalam Pesan string hanya mengembalikan dari Spring MVC 3 Controller ) ATAU bungkus String Anda adalah beberapa objekpublic class StringResponse { private String response; public StringResponse(String s) { this.response = s; } // get/set omitted... }
Setel jenis tanggapan Anda ke
MediaType.APPLICATION_JSON_VALUE
(="application/json"
)@RequestMapping(value = "/getString", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
dan Anda akan memiliki JSON yang terlihat seperti itu
{ "response" : "your string value" }
sumber
Collections.singletonMap("response", "your string value")
untuk mendapatkan hasil yang sama tanpa harus membuat kelas pembungkus.Collections.singleton("your string value")
JSON pada dasarnya adalah String dalam konteks PHP atau JAVA. Itu berarti string yang merupakan JSON valid dapat dikembalikan sebagai respons. Mengikuti harus bekerja.
@RequestMapping(value="/user/addUser", method=RequestMethod.POST) @ResponseBody public String addUser(@ModelAttribute("user") User user) { if (user != null) { logger.info("Inside addIssuer, adding: " + user.toString()); } else { logger.info("Inside addIssuer..."); } users.put(user.getUsername(), user); return "{\"success\":1}"; }
Ini tidak masalah untuk respon string sederhana. Tetapi untuk respon JSON yang kompleks, Anda harus menggunakan kelas pembungkus seperti yang dijelaskan oleh Shaun.
sumber
Dalam satu proyek kami menangani ini menggunakan JSONObject ( info ketergantungan maven ). Kami memilih ini karena kami lebih suka mengembalikan String sederhana daripada objek pembungkus. Kelas pembantu internal dapat dengan mudah digunakan jika Anda tidak ingin menambahkan dependensi baru.
Contoh Penggunaan:
@RestController public class TestController { @RequestMapping("/getString") public String getString() { return JSONObject.quote("Hello World"); } }
sumber
"\"Hello World\""
akan bekerja dengan baik tanpa ketergantungan ekstra - itu yangJSONObject.quote()
dilakukan, bukan?Anda dapat dengan mudah kembali
JSON
denganString
propertiresponse
sebagai berikut@RestController public class TestController { @RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE) public Map getString() { return Collections.singletonMap("response", "Hello World"); } }
sumber
Cukup batalkan pendaftaran
StringHttpMessageConverter
instance default :@Configuration public class WebMvcConfiguration extends WebMvcConfigurationSupport { /** * Unregister the default {@link StringHttpMessageConverter} as we want Strings * to be handled by the JSON converter. * * @param converters List of already configured converters * @see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List) */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.stream() .filter(c -> c instanceof StringHttpMessageConverter) .findFirst().ifPresent(converters::remove); } }
Diuji dengan metode penangan tindakan pengontrol dan penangan pengecualian pengontrol:
@RequestMapping("/foo") public String produceFoo() { return "foo"; } @ExceptionHandler(FooApiException.class) public String fooException(HttpServletRequest request, Throwable e) { return e.getMessage(); }
Catatan akhir:
extendMessageConverters
tersedia sejak Spring 4.1.3, jika berjalan pada versi sebelumnya Anda dapat menerapkan teknik yang samaconfigureMessageConverters
, hanya membutuhkan sedikit lebih banyak pekerjaan.sumber
converters.removeIf(c -> c instanceof StringHttpMessageConverter)
Saya tahu bahwa pertanyaan ini sudah lama tetapi saya ingin berkontribusi juga:
Perbedaan utama antara respons lainnya adalah pengembalian hashmap.
@GetMapping("...") @ResponseBody public Map<String, Object> endPointExample(...) { Map<String, Object> rtn = new LinkedHashMap<>(); rtn.put("pic", image); rtn.put("potato", "King Potato"); return rtn; }
Ini akan mengembalikan:
{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}
sumber
Menambahkan
produces = "application/json"
dalam@RequestMapping
penjelasan seperti:@RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")
Petunjuk: Sebagai nilai kembali, saya sarankan untuk menggunakan
ResponseEntity<List<T>>
tipe. Karena data yang dihasilkan dalam tubuh JSON harus berupa larik atau objek sesuai dengan spesifikasinya, bukan satu string sederhana . Kadang-kadang dapat menyebabkan masalah (misalnya Observables in Angular2).Perbedaan:
dikembalikan
String
sebagai json:"example"
dikembalikan
List<String>
sebagai json:["example"]
sumber
Sederhanakan:
@GetMapping("/health") public ResponseEntity<String> healthCheck() { LOG.info("REST request health check"); return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK); }
sumber
Tambahkan
@ResponseBody
anotasi, yang akan menulis data yang dikembalikan dalam aliran keluaran.sumber
@PostMapping(value = "/some-url", produces = APPLICATION_JSON_UTF8_VALUE)
Masalah ini membuat saya marah: Spring adalah alat yang ampuh, namun, hal sederhana seperti menulis String keluaran seperti JSON tampaknya tidak mungkin tanpa peretasan yang buruk.
Solusi saya (di Kotlin) yang menurut saya paling tidak mengganggu dan paling transparan adalah dengan menggunakan saran pengontrol dan memeriksa apakah permintaan tersebut mengarah ke serangkaian titik akhir tertentu (REST API biasanya karena kami paling sering ingin mengembalikan SEMUA jawaban dari sini sebagai JSON dan tidak membuat spesialisasi di frontend berdasarkan apakah data yang dikembalikan adalah string biasa ("Jangan lakukan deserialisasi JSON!") atau yang lain ("Lakukan deserialisasi JSON!")). Aspek positif dari ini adalah bahwa pengontrol tetap sama dan tanpa peretasan.
The
supports
Metode memastikan bahwa semua permintaan yang ditangani olehStringHttpMessageConverter
(misalnya konverter yang menangani output dari semua kontroler yang kembali string polos) diproses dan dalambeforeBodyWrite
metode, kita mengendalikan di mana kasus kita ingin menyela dan mengkonversi output ke JSON (dan ubah tajuk sesuai).@ControllerAdvice class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> { override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean = converterType === StringHttpMessageConverter::class.java override fun beforeBodyWrite( body: Any?, returnType: MethodParameter, selectedContentType: MediaType, selectedConverterType: Class<out HttpMessageConverter<*>>, request: ServerHttpRequest, response: ServerHttpResponse ): Any? { return if (request.uri.path.contains("api")) { response.getHeaders().contentType = MediaType.APPLICATION_JSON ob.writeValueAsString(body) } else body } }
Saya berharap kedepannya kita akan mendapatkan anotasi sederhana dimana kita dapat mengganti yang
HttpMessageConverter
seharusnya digunakan untuk keluaran.sumber
Tambahkan anotasi ini ke metode Anda
@RequestMapping(value = "/getString", method = RequestMethod.GET, produces = "application/json")
sumber