如何替换异常处理结构

时间:2019-06-22 18:31:20

标签: java spring-boot spring-security

我尝试实现spring security + jwt。我完成了登录和注销方法,配置了jwt filter,provider和Web config。因此,主要问题是我的控制器以及如何向用户返回错误消息,例如,如果用户键入了错误的密码/用户名或用户帐户被禁止等。 我有一个基于异常处理的结构,看起来很糟糕。

控制器

@PostMapping("/log-in")
    public ResponseEntity logIn(@RequestBody UserDto userDto) {
        log.info("[LOG-IN] user with username " + userDto.getUsername());
        try {
            HashMap<String, String> response = userService.logIn(userDto);
            return ResponseEntity.ok(response);

        } catch (UserStatusException ex) {
            return ResponseEntity.badRequest().body("Account is Pending");
        } catch (UsernameNotFoundException ex) {
            return ResponseEntity.badRequest().body("Could not find account!");
        } catch (AuthenticationException ex) {
            log.error("Wrong username or password!");
            return ResponseEntity.badRequest().body("Wrong username or password!");
        }
    }

服务

@Override
    public HashMap<String, String> logIn(UserDto userDto)throws AuthenticationException, UserStatusException{
        User user = findByUsername(userDto.getUsername());

        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userDto.getUsername(), userDto.getPassword())); //login

        checkUserStatus(user);              //check if user pending or banned
        user.setUserStatus(UserStatus.ACTIVE);

        String token = jwtTokenProvider.createToken(user.getUsername(), user.getUserRoles());
        HashMap<String, String> response = new HashMap<>();
        response.put("token", token);
        response.put("username", user.getUsername());
        userRepository.save(user);
        return response;
    }
@Override
    public User findByUsername(String username)throws UsernameNotFoundException {
        log.info("[UserService, findByUsername]");
        User user = userRepository.findByUsername(username);
        if(user == null){
            log.error("User not found with {} username: ", username);
            throw new UsernameNotFoundException("User not found!");
        }
        log.info("User {} successfully loaded ",username);
        return user;
    }
@Override
    public void checkUserStatus(User user)throws UserStatusException {
        if (user.getUserStatus().equals(UserStatus.BANNED)
           || user.getUserStatus().equals(UserStatus.PENDING)) {
            throw new UserStatusException("Not confirmed");
        }
    }

还有其他方法可以代替此结构吗?

2 个答案:

答案 0 :(得分:4)

您应该使用ControllerAdvice(请参阅教程here)。

这是一个特殊的类

@ControllerAdvice
public class ControllerAdvice {

   @ExceptionHandler(PersonNotFoundException.class) 
   public ResponseEntity <VndErrors > notFoundException(final PersonNotFoundException e) {

    return error(e, HttpStatus.NOT_FOUND, e.getId().toString());

   }

}

它将允许您将特定的返回码和响应绑定到需要处理的每个异常,并且它将自动捕获控制器返回的所有异常。这也是在同一位置处理所有异常的好方法,而不是对每个异常进行处理...

我不确定,但是我认为您甚至可以将其绑定到API的特定映射以获取更多的粒度。

希望这项帮助!玩得开心!

答案 1 :(得分:2)

您可以将休养状态直接添加到您的自定义异常类中:

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class UsernameNotFoundException extends RuntimeException {
    public UsernameNotFoundException(String message) {
        super(message);
    }

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

通过这种方式,您不再需要在控制器中捕获它们并将消息和状态添加到ResponseEntity中。