437

@ResponseBody次のようなベースのアプローチで、単純な JSON API に Spring MVC を使用しています。(JSON を直接生成するサービス層が既にあります。)

@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
    String json = matchService.getMatchJson(matchId);
    if (json == null) {
        // TODO: how to respond with e.g. 400 "bad request"?
    }
    return json;
}

質問は、特定のシナリオで、HTTP 400 エラーで応答する最も簡単でクリーンな方法は何ですか?

私は次のようなアプローチに出くわしました:

return new ResponseEntity(HttpStatus.BAD_REQUEST);

...しかし、メソッドの戻り値の型が ResponseEntity ではなく String であるため、ここでは使用できません。

4

14 に答える 14

693

戻り値の型を に変更するとResponseEntity<>、以下で 400 を使用できます

return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

そして正しい要求のために

return new ResponseEntity<>(json,HttpStatus.OK);

更新 1

spring 4.1 以降、ResponseEntity にヘルパー メソッドがあり、次のように使用できます。

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);

return ResponseEntity.ok(json);
于 2013-04-27T10:01:23.930 に答える
115

このようなものはうまくいくはずですが、もっと簡単な方法があるかどうかはわかりません:

@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId, @RequestBody String body,
            HttpServletRequest request, HttpServletResponse response) {
    String json = matchService.getMatchJson(matchId);
    if (json == null) {
        response.setStatus( HttpServletResponse.SC_BAD_REQUEST  );
    }
    return json;
}
于 2013-04-26T09:35:33.123 に答える
57

必ずしもこれを行う最もコンパクトな方法ではありませんが、非常にクリーンな IMO

if(json == null) {
    throw new BadThingException();
}
...

@ExceptionHandler(BadThingException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public @ResponseBody MyError handleException(BadThingException e) {
    return new MyError("That doesnt work");
}

Spring 3.1+を使用している場合は、例外ハンドラーメソッドで @ResponseBody を使用できます。それ以外の場合は、ModelAndViewまたは何かを使用します。

https://jira.springsource.org/browse/SPR-6902

于 2013-04-26T09:19:36.903 に答える
37

ここに別のアプローチがあります。Exception次のように、 で注釈を付けたカスタムを作成します@ResponseStatus

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not Found")
public class NotFoundException extends Exception {

    public NotFoundException() {
    }
}

そして、必要に応じて投げます。

@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
    String json = matchService.getMatchJson(matchId);
    if (json == null) {
        throw new NotFoundException();
    }
    return json;
}

ここで Spring のドキュメントを確認してください: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-annotated-exceptions

于 2016-08-05T16:20:39.640 に答える
26

最も簡単な方法は、ResponseStatusException

    @RequestMapping(value = "/matches/{matchId}", produces = "application/json")
    @ResponseBody
    public String match(@PathVariable String matchId, @RequestBody String body) {
        String json = matchService.getMatchJson(matchId);
        if (json == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
        return json;
    }
于 2020-01-15T12:58:05.100 に答える
11

これをスプリングブートアプリケーションで使用しています

@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public ResponseEntity<?> match(@PathVariable String matchId, @RequestBody String body,
            HttpServletRequest request, HttpServletResponse response) {

    Product p;
    try {
      p = service.getProduct(request.getProductId());
    } catch(Exception ex) {
       return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity(p, HttpStatus.OK);
}
于 2015-10-13T12:45:48.480 に答える
3

Spring Boot では、なぜこれが必要なのか完全にはわかりません (で定義されていた/errorにもかかわらず、フォールバックを取得しました)、次のこと自体は機能しませんでした。@ResponseBody@ExceptionHandler

@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorMessage handleIllegalArguments(HttpServletRequest httpServletRequest, IllegalArgumentException e) {
    log.error("Illegal arguments received.", e);
    ErrorMessage errorMessage = new ErrorMessage();
    errorMessage.code = 400;
    errorMessage.message = e.getMessage();
    return errorMessage;
}

リクエスト属性として生成可能なメディアタイプが定義されていなかったため、例外がスローされました。

// AbstractMessageConverterMethodProcessor
@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
        ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
        throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    Class<?> valueType = getReturnValueType(value, returnType);
    Type declaredType = getGenericType(returnType);
    HttpServletRequest request = inputMessage.getServletRequest();
    List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
    List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
if (value != null && producibleMediaTypes.isEmpty()) {
        throw new IllegalArgumentException("No converter found for return value of type: " + valueType);   // <-- throws
    }

// ....

@SuppressWarnings("unchecked")
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, Type declaredType) {
    Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    if (!CollectionUtils.isEmpty(mediaTypes)) {
        return new ArrayList<MediaType>(mediaTypes);

だから私はそれらを追加しました。

@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorMessage handleIllegalArguments(HttpServletRequest httpServletRequest, IllegalArgumentException e) {
    Set<MediaType> mediaTypes = new HashSet<>();
    mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
    httpServletRequest.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
    log.error("Illegal arguments received.", e);
    ErrorMessage errorMessage = new ErrorMessage();
    errorMessage.code = 400;
    errorMessage.message = e.getMessage();
    return errorMessage;
}

そして、これにより「サポートされている互換性のあるメディアタイプ」が得られましたが、それでも機能しませんでしたErrorMessage

public class ErrorMessage {
    int code;

    String message;
}

JacksonMapper は「変換可能」として処理しなかったため、getter/setter を追加する必要があり、@JsonPropertyアノテーションも追加しました

public class ErrorMessage {
    @JsonProperty("code")
    private int code;

    @JsonProperty("message")
    private String message;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

その後、意図したとおりにメッセージを受け取りました

{"code":400,"message":"An \"url\" parameter must be defined."}
于 2016-12-01T15:41:05.693 に答える
-1

このスレッドには、Spring が提供する JSON マーチャリング ツールを犠牲にしない、最も簡単でクリーンなソリューションがあると思います。

https://stackoverflow.com/a/16986372/1278921

于 2014-05-27T04:40:07.280 に答える