Pregunta

I use the following code to handle rest calls using Spring MVC.

@RequestMapping(value = "login", method = RequestMethod.GET)
public @ResponseBody
User login(@RequestParam String username, @RequestParam String password) {
    User user = userService.login(username, password);
    if (user == null)
        ...
    return user;
} 

I would like to send the client customer http codes for wrong username, wrong passwords, password changed and password expire conditions. How can I modify the existing code to send these error codes to the client?

No hay solución correcta

Otros consejos

You can use controller advice to map exception thrown within controller to some client specific data at runtime. For example if user is not found, your controller should throw some exception (custom or existed one)

@RequestMapping(value = "login", method = RequestMethod.GET)
@ResponseBody
public User login(@RequestParam String username, @RequestParam String password) {
    User user = userService.login(username, password);
    if (user == null)
        throw new UserNotFoundException(username); //or another exception, it's up to you
    return user;
   } 
}

Then you should add @ControllerAdvice that will catch controller exceptions and make 'exception-to-status' mapping (pros: you will have single point of responsibility for 'exception-to-status-mapping'):

@ControllerAdvice
public class SomeExceptionResolver {

    @ExceptionHandler(Exception.class)
    public void resolveAndWriteException(Exception exception, HttpServletResponse response) throws IOException {

        int status = ...; //you should resolve status here

        response.setStatus(status); //provide resolved status to response
        //set additional response properties like 'content-type', 'character encoding' etc.

        //write additional error message (if needed) to response body   
        //for example IOUtils.write("some error message", response.getOutputStream());
    }
}

Hope this helps.

One way is to add some additional classes for returning HTTP error. Your code will looks like this:

@RequestMapping(value = "login", method = RequestMethod.GET)
@ResponseBody
public User login(@RequestParam String username, @RequestParam String password) {
    User user = userService.login(username, password);
    if (user == null)
        throw new UnauthorizedException();
    return user;
   } 
}

@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException{
}

In this case user will get 401 response status code

I hope it helps

You can return an HTTP 500 or code of your choosing (from the org.springframework.http.HttpStatus enumeration) and use a custom error to emulate something like a SOAP fault within the JSON response.

For example:

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(YourTargetException.class)
@ResponseBody
Fault caughtYourTargetException(HttpServletRequest req, Exception ex) {

    String code = ex.getClass().getName();
    String reason = "Caught YourTargetException."
    return new Fault(code, reason);
}

The Fault class could look something like this (inspired by http://www.w3.org/TR/soap12-part1/#soapfault):

/**
 * A Fault is an object that can be serialized as JSON when expected errors    occur.
*/
public class Fault {

  @JsonProperty("faultCode")
  private final String code;

  @JsonProperty("faultReason")
  private final String reason;

  @JsonProperty("faultDetails")
  private final List<String> details = new ArrayList<>();

  public Fault(String code, String reason) {
    this.code = code;
    this.reason = reason;
  }

  public Fault(String code, String reason, String... detailEntries) {
    this.code = code;
    this.reason = reason;
    details.addAll(Arrays.asList(detailEntries));
  }

  public String getCode() {
      return code;
  }

  public String getReason() {
      return reason;
  }

  /**
   * Zero or more details may be associated with the fault. It carries 
   * additional information relative to the fault. For example, the Detail
   * element information item might contain information about a message
   * not containing the proper credentials, a timeout, etc.
   * @return Zero or more detail entries.
   */
  public Iterable<String> getDetails() {
      return details;
  }

  @Override
  public String toString() {
      return String.format("Fault %s occurred. The reason is %s.", getCode(), 
          getReason());
  }
}

You could use one of the existing SOAPFaults in Java frameworks, but I have found they don't play well in REST. Creating my own simple version turned out to be simpler.

You can define your own status code and returning objects. In your code throw custom exceptions and then define an exception handler as follows:

@ControllerAdvice
public class GlobalControllerExceptionHandler {

@ExceptionHandler(MyException.class)
public ResponseEntity<MyRetObject> handleControllerError(HttpServletRequest req, MyException ex) {
    LOG.warn("My error", ex);
    MyRetObject errorMessage = new MyRetObject(ex.getMessage());
    return ResponseEntity.status(600).body(errorMessage);
}

}

In your case replace MyExeption.class by UserNotFoundException.class and build your customer error response object and error code

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top