如何将JPA控制器返回的JSON转换为JSend标准格式?
Got it, let's get your JPA controller responses aligned with the JSend standard. I'll walk you through a clean, reusable approach that works seamlessly in Spring Boot (since you're using JPA, that's a safe assumption!).
First, let's make sure we're on the same page with the three core JSend statuses:
- Success: For successful requests that return data
{ "status": "success", "data": { "country": [ {"id": 1, "name": "Canada"}, {"id": 2, "name": "USA"} ] } } - Fail: For invalid requests (like missing required fields) where the client can fix the issue
{ "status": "fail", "data": { "title": "A title is required" } } - Error: For server-side issues (like database errors) where the client can't resolve the problem on their own
{ "status": "error", "message": "An unexpected error occurred", "data": null }
Create a reusable class to wrap all your responses—this avoids repeating the same structure across every controller method. You can use Lombok to simplify boilerplate, but I'll include the full code just in case:
public class JSendResponse<T> { private String status; private T data; private String message; // Only used for "error" status // Private constructor to force using our factory methods private JSendResponse(String status, T data, String message) { this.status = status; this.data = data; this.message = message; } // Factory method for success responses public static <T> JSendResponse<T> success(T data) { return new JSendResponse<>("success", data, null); } // Factory method for fail responses (validation errors, etc.) public static <T> JSendResponse<T> fail(T data) { return new JSendResponse<>("fail", data, null); } // Factory method for error responses public static <T> JSendResponse<T> error(String message, T data) { return new JSendResponse<>("error", data, message); } // Getters and setters (or add @Data from Lombok to skip these) public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
Now modify your existing controller methods to return this wrapper class instead of raw entities/lists. Here's how it looks with your country example:
@RestController @RequestMapping("/countries") public class CountryController { @Autowired private CountryRepository countryRepo; // Success response example @GetMapping public JSendResponse<Map<String, List<Country>>> getAllCountries() { List<Country> countries = countryRepo.findAll(); // Wrap the list in a map with "country" key as per your example Map<String, List<Country>> responseData = Collections.singletonMap("country", countries); return JSendResponse.success(responseData); } // Fail response example (validation errors) @PostMapping public JSendResponse<Map<String, String>> createCountry( @Valid @RequestBody Country country, BindingResult bindingResult ) { if (bindingResult.hasErrors()) { Map<String, String> errorMap = new HashMap<>(); bindingResult.getFieldErrors().forEach(error -> errorMap.put(error.getField(), error.getDefaultMessage()) ); return JSendResponse.fail(errorMap); } countryRepo.save(country); // Return success with the created country if needed return JSendResponse.success(Collections.singletonMap("country", List.of(country))); } }
To ensure even unexpected errors follow JSend, add a global exception handler. This way, any uncaught exceptions will automatically be wrapped in an error response:
@ControllerAdvice public class GlobalJSendExceptionHandler { // Handle resource not found errors @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity<JSendResponse<Void>> handleNotFound(EntityNotFoundException ex) { JSendResponse<Void> response = JSendResponse.error("Requested resource not found", null); return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); } // Handle validation errors (matches the fail example above) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<JSendResponse<Map<String, String>>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, String> errorMap = new HashMap<>(); ex.getBindingResult().getFieldErrors().forEach(error -> errorMap.put(error.getField(), error.getDefaultMessage()) ); JSendResponse<Map<String, String>> response = JSendResponse.fail(errorMap); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } // Catch-all for other server errors @ExceptionHandler(Exception.class) public ResponseEntity<JSendResponse<Void>> handleGenericError(Exception ex) { // In production, replace ex.getMessage() with a user-friendly message! JSendResponse<Void> response = JSendResponse.error("An unexpected error occurred", null); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } }
This setup ensures every response from your API follows the JSend standard, making it predictable for frontend teams to work with.
内容的提问来源于stack exchange,提问作者George

