【问题标题】:Springboot error handlingSpringboot错误处理
【发布时间】:2018-05-25 00:47:03
【问题描述】:

我正在开发一个处理登录的示例 spring-boot API,该 API 工作正常,但是在错误处理期间我遇到了问题。我在教程中看到的所有错误处理都是在控制器中完成的,但是我的逻辑在服务中,这就是我想做错误处理的地方。

如何实现对服务中不同类型错误的错误处理,或者这样做被认为是不好的做法。我目前的问题是我的错误消息如下所示:

{

 "message": "Please Activate account before attempting to Sign in",
  "token": " ",
  "accountLocked": false,
  "accountEnabled": false,
  "status": false,
  "balance": " ",
  "profileImage": null,
  "roles": null,
  "baraAuthorities": null,
  "customerNumber": 0,
  "userEmail": "",
  "name": ""
}

但是我希望只显示消息和状态并在响应中隐藏其余部分,我该如何实现:

{
  "message": "Please Activate account before attempting to Sign in",
  "status": false
}

这是我的 LoginService 代码:

@Service
public class LoginService implements UserDetailsService {

    @Autowired
    private UserLoginRepository loginRepository;
    @Autowired
    private LoginInformationRepository logininfoRepository;

    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    String balance, message, pin, token, userEmail, name, profileImage = "";
    Boolean status, successStatus, accounState = false;
    int customerNumber, attempts;
    List<Roles> userRoles = new ArrayList();

    private boolean userNameExist(String username) {
        UserLogin user = loginRepository.findByUsername(username);
        if (user != null) {
            return true;
        }
        return false;
    }

    public LoginResponse verifyLoginDetails(LoginObject user) throws LoginException {

        AuthoritiesKeys userAuth = new AuthoritiesKeys();
        Merchant searchedMerchant = merchantRepository.findByUserlogin_LoginCredentialsID(userdetails.getLoginCredentialsID());
        DateUtility currentDate = new DateUtility();
        Boolean status = false;

        if (userdetails == null) {
            return new LoginResponse("Unable to Login. Please check login details and try again",status);
        } else {

            pin = user.getPassword();
            attempts = logininfoRepository.countByTodayDateAndUserLoginLoginCredentialsIDAndLoginSuccessStatusFalse(currentDate.getCurrentDate(), userdetails.getLoginCredentialsID());
            if (attempts < 3) {
                if (bCryptPasswordEncoder.matches(pin, userdetails.getPassword())) {

                    if (userdetails.isEnabled() == true) {
                        if (searchedMerchant != null) {

                            message = "Logged in Successfully";
                            status = userdetails.isAccountNonLocked();
                            accounState = userdetails.isEnabled();
                            userRoles = (List<Roles>) userdetails.getAuthorities();
                            balance = searchedMerchant.getAccount().getBalance().toString();
                            successStatus = true;
                            customerNumber = searchedMerchant.getMerchantNumber();
                            userEmail = searchedMerchant.getEmail();
                            name = searchedMerchant.getBusinessName();

                            return new LoginResponse(message, token, accounState, status, userRoles, successStatus, balance, userAuth, profileImage, customerNumber, userEmail, name);

                        } else {
                            return new LoginResponse("Error Merchant Information Error . Please contact the team",status);
                        }

                    } else {
                        return new LoginResponse("Please Activate account before attempting to Sign in",status);
                    }
                } else {
                    return new LoginResponse("Wrong Username or Password",status);
                }

            } else {
                userdetails.setAccountNonLocked(false);
                userdetails.setEnabled(false);
                loginRepository.save(userdetails);
                return new LoginResponse("Too many attempts account has been locked",status);
            }


        }

    }

这是我的 LoginResponse 代码:

 public class LoginResponse {

    private String message;
    private String token;
    private Boolean accountLocked;
    private Boolean accountEnabled;
    private Boolean status;
    private String balance;
    private String profileImage;
    List<Roles> roles = new ArrayList<>();
    AuthoritiesKeys baraAuthorities = new AuthoritiesKeys();
    private int customerNumber;
    private String userEmail;
    private String name;

    public LoginResponse() {
    }

    public LoginResponse(String message, Boolean status) {
        this.message = message;
        this.status = status;
    }

    public LoginResponse(String message, String token, Boolean accountLocked, Boolean accountEnabled, List<Roles> myroles, Boolean status, String balance, AuthoritiesKeys userBaraAuthorities, String profileImage, int customerNumber, String userEmail, String name) {
        this.message = message;
        this.token = token;
        this.accountLocked = accountLocked;
        this.accountEnabled = accountEnabled;
        this.status = status;
        this.balance = balance;
        this.roles = myroles;
        this.baraAuthorities = userBaraAuthorities;
        this.profileImage = profileImage;
        this.customerNumber = customerNumber;
        this.userEmail = userEmail;
        this.name = name;
    }

… // left getter and setters for brevity

}

这是我的 LoginController 代码:

@RestController
@Api(value = "Login API", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserLoginController {

    @Autowired
    private LoginService loginService;
    @RequestMapping(method = RequestMethod.POST, value = "/api/usermanagement/user/login")
    @ApiOperation("login registered user")
    @ApiResponses(value = {
        @ApiResponse(code = 200, message = "OK", response = ResponseMessage.class)})
    public LoginResponse Login(@Valid @RequestBody LoginObject credentails) throws LoginException {
        return loginService.verifyLoginDetails(credentails);

    }

}

【问题讨论】:

  • 错误处理应该在大多数级别进行,而且如果有错误,那么它是否与用户相关,如果是,您建议如何让他们知道吗?
  • 我更新了问题

标签: java spring-boot error-handling


【解决方案1】:

使用应该使用ResponseEntityExceptionHandler 类来处理如下异常

创建一个类GlobalControllerExceptionHandler

import javax.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation 
.ResponseEntityExceptionHandler;

@ControllerAdvice
public class GlobalControllerExceptionHandler extends 
ResponseEntityExceptionHandler {

private static final Logger LOGGER = 
LoggerFactory.getLogger(GlobalControllerExceptionHandler.class);

////////////  Globle exception handler  ///////////
@ExceptionHandler(Exception.class)
public ResponseEntity handleAnyException(final Exception e,final WebRequest 
request) {
    LOGGER.error("Error occurred while processing request: {}", 
e.getMessage());
    e.printStackTrace();
    ResponseDTO responseDTO = new ResponseDTO();
    responseDTO.setSuccess(false);
    responseDTO.setCode(500);
    responseDTO.setMessage(e.getMessage());
    return new ResponseEntity<>(responseDTO, 
HttpStatus.INTERNAL_SERVER_ERROR);
}

////////////Self define exception class handler  ///////////

@ExceptionHandler(InvalidCredentialException.class)
public ResponseEntity handleInvalidCredentialException(final 
InvalidCredentialException e,final WebRequest request) {
    LOGGER.error("Invalid Credential: "+ e.getCause());
    ResponseDTO responseDTO = new ResponseDTO();
    responseDTO.setSuccess(false);
    responseDTO.setCode(e.getErrorCode());
    responseDTO.setMessage(e.getMessage());
    return new ResponseEntity<>(responseDTO, HttpStatus.UNAUTHORIZED);
}}

创建类InvalidCredentialException

public class InvalidCredentialException extends RuntimeException {

private static final long serialVersionUID = -3338166707608147652L;
private int errorCode;

public InvalidCredentialException() {

}

public InvalidCredentialException(final Throwable cause) {
    super(cause);
}

public InvalidCredentialException(final String message) {
    super(message);
}

public InvalidCredentialException(final int errorCode, final String message) {
    super(message);
    this.setErrorCode(errorCode);
}

public InvalidCredentialException(final String message, final Throwable cause) {
    super(message, cause);
}

public int getErrorCode() {
    return errorCode;
}}

现在抛出如下错误

throw new InvalidCredentialException(401, "No project associated with this id");

我会建议你不要在代码中使用 try-catch 块(除非你需要),因为如果发生任何异常并且没有被 catch 块处理,那么它将进入全局异常类 Exception 处理程序。这里ResponseDTO 也是一个自定义类,它有一些变量,如errorCode,isSuccess,errorMessage 等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-19
    • 2020-10-27
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 2018-08-06
    相关资源
    最近更新 更多