Criar um diretório chamado exception dentro do diretório convention, e adicionar as classes AbstractException, ClientException, ServiceException e RemoteException.
/**
* Sistema abstrato de exceções para o projeto com três categorias:
* exceções do cliente, exceções do servidor e exceções de chamadas remotas
*
* @see ClientException
* @see ServiceException
* @see RemoteException
*/
@Getter
public abstract class AbstractException extends RuntimeException {
public final String codigoErro;
public final String mensagemErro;
public AbstractException(String mensagem, Throwable causa, ICodigoErro codigoErro) {
super(mensagem, causa);
this.codigoErro = codigoErro.codigo();
this.mensagemErro = Optional.ofNullable(StringUtils.hasLength(mensagem) ? mensagem : null)
.orElse(codigoErro.mensagem());
}
}
/**
* Exceção do cliente
*/
public class ClientException extends AbstractException {
public ClientException(ICodigoErro codigoErro) {
this(null, null, codigoErro);
}
public ClientException(String mensagem) {
this(mensagem, null, BaseErrorCode.CLIENT_ERROR);
}
public ClientException(String mensagem, ICodigoErro codigoErro) {
this(mensagem, null, codigoErro);
}
public ClientException(String mensagem, Throwable causa, ICodigoErro codigoErro) {
super(mensagem, causa, codigoErro);
}
@Override
public String toString() {
return "ClientException{" +
"codigo='" + codigoErro + "'," +
"mensagem='" + mensagemErro + "'" +
'}';
}
}
/**
* Exceção de chamada remota
*/
public class RemoteException extends AbstractException {
public RemoteException(String mensagem) {
this(mensagem, null, BaseErrorCode.REMOTE_ERROR);
}
public RemoteException(String mensagem, ICodigoErro codigoErro) {
this(mensagem, null, codigoErro);
}
public RemoteException(String mensagem, Throwable causa, ICodigoErro codigoErro) {
super(mensagem, causa, codigoErro);
}
@Override
public String toString() {
return "RemoteException{" +
"codigo='" + codigoErro + "'," +
"mensagem='" + mensagemErro + "'" +
'}';
}
}
/**
* Exceção do serviço
*/
public class ServiceException extends AbstractException {
public ServiceException(String mensagem) {
this(mensagem, null, BaseErrorCode.SERVICE_ERROR);
}
public ServiceException(ICodigoErro codigoErro) {
this(null, codigoErro);
}
public ServiceException(String mensagem, ICodigoErro codigoErro) {
this(mensagem, null, codigoErro);
}
public ServiceException(String mensagem, Throwable causa, ICodigoErro codigoErro) {
super(Optional.ofNullable(mensagem).orElse(codigoErro.mensagem()), causa, codigoErro);
}
@Override
public String toString() {
return "ServiceException{" +
"codigo='" + codigoErro + "'," +
"mensagem='" + mensagemErro + "'" +
'}';
}
}
O UserServiceImpl pode ser modificado da seguinte forma:
O trecho de código implementa um método getUserByUsername da interface UserService, responsável por obter informações do usuário com base no nome de usuário e retornar um objeto UserRespDTO. O método inclui uma verificação condicional if (usuarioDO == null) para tratar o caso em que o usuário não existe (quando o objeto usuarioDO é nulo, indica que não há registros correspondentes no banco de dados).
Caso a verificação if (usuarioDO == null) seja removida, quando não for encontrado nenhum registro correspondente no banco de dados, a variável usuarioDO será atribuída como nula. A subsequente chamada BeanUtils.copyProperties(usuarioDO, resultado) falhará, pois o método tentará acessar as propriedades de usuarioDO para copiar para o objeto resultado. Se usuarioDO for nulo, isso causará uma NullPointerException.
Criar a classe Results no diretório result para simplificar o UserController.
No diretório common, criar um subdiretório web e adicionar o GlobalExceptionHandler. Este interceptador global de exceções é necessário porque é impossível capturar todas as exceções na lógica do código. Por exemplo, se esquecermos de escrever return null, ocorrerá uma exceção de ponteiro nulo. Nesse momento, o interceptador pode capturar esses erros e rpeortar as exceções.
/**
* Manipulador global de exceções
*
*/
@Component
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* Intercepta exceções de validação de parâmetros
*/
@SneakyThrows
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result validacaoExcecaoHandler(HttpServletRequest requisicao, MethodArgumentNotValidException ex) {
BindingResult resultadoVinculo = ex.getBindingResult();
FieldError primeiroErroCampo = CollectionUtil.getFirst(resultadoVinculo.getFieldErrors());
String strExcecao = Optional.ofNullable(primeiroErroCampo)
.map(FieldError::getDefaultMessage)
.orElse(StrUtil.EMPTY);
log.error("[{}] {} [ex] {}", requisicao.getMethod(), getUrl(requisicao), strExcecao);
return Results.falha(BaseErrorCode.CLIENT_ERROR.codigo(), strExcecao);
}
/**
* Intercepta exceções lançadas na aplicação
*/
@ExceptionHandler(value = { AbstractException.class })
public Result excecaoAbstrata(HttpServletRequest requisicao, AbstractException ex) {
if (ex.getCause() != null) {
log.error("[{}] {} [ex] {}", requisicao.getMethod(), requisicao.getRequestURL().toString(), ex.toString(),
ex.getCause());
return Results.falha(ex);
}
log.error("[{}] {} [ex] {}", requisicao.getMethod(), requisicao.getRequestURL().toString(), ex.toString());
return Results.falha(ex);
}
/**
* Intercepta exceções não capturadas
*/
@ExceptionHandler(value = Throwable.class)
public Result manipuladorErroPadrao(HttpServletRequest requisicao, Throwable throwable) {
log.error("[{}] {} ", requisicao.getMethod(), getUrl(requisicao), throwable);
return Results.falha();
}
private String getUrl(HttpServletRequest requisicao) {
if (StringUtils.isEmpty(requisicao.getQueryString())) {
return requisicao.getRequestURL().toString();
}
return requisicao.getRequestURL().toString() + "?" + requisicao.getQueryString();
}
}