You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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!).

1. Quick JSend Recap

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 }
    
2. Build a Generic JSend Response DTO

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; }
}
3. Update Your Controller to Use the DTO

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)));
    }
}
4. Add Global Exception Handling for Consistency

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:36:48