Spring Boot异常处理 -> 不返回通用异常

huangapple go评论86阅读模式
英文:

Spring Boot Exception Handling -> Not Return Generic Exception

问题

I understand that you're facing an issue with returning the ErrorDTO from a Generic Exception. To fix this, you can update the handleGenericException method in your GlobalExceptionHandler as follows:

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorDTO> handleGenericException(HttpServletRequest request, Exception ex) {

    List<String> details = new ArrayList<>();
    details.add(ex.getMessage());

    ErrorDTO error = ErrorDTO.builder()
            .timestamp(LocalDateTime.now())
            .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
            .errorDetails(details)
            .path(request.getServletPath())
            .httpStatus(HttpStatus.INTERNAL_SERVER_ERROR)
            .build();

    LOGGER.error("GlobalExceptionHandler | handleGenericException", error);

    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}

This modification ensures that the handleGenericException method returns a ResponseEntity<ErrorDTO> containing the error information. This way, it will return an ErrorDTO in response to the Generic Exception, as desired.

Please apply this change and test your application again. If you encounter any further issues, feel free to let me know.

英文:

I have a problem to return the ErrorDTO from Generic Exception.

When I send a request to http://localhost:8080/v1/locations with this response body shown below, I get this issue underneath GlobalExceptionHandler.

{
&#160;&#160;&#160;&#160;&quot;code&quot;&#160;:&#160;&quot;DELHI_IN_QWERTYUI&quot;, -&gt; IT thows an error because of its length (length is 12)
&#160;&#160;&#160;&#160;&quot;city_name&quot;&#160;:&#160;&quot;New&#160;Delhi&quot;,
&#160;&#160;&#160;&#160;&quot;region_name&quot;&#160;:&#160;&quot;Delhi&quot;,
&#160;&#160;&#160;&#160;&quot;country_name&quot;&#160;:&#160;&quot;India&quot;,
&#160;&#160;&#160;&#160;&quot;country_code&quot;&#160;:&#160;&quot;IN&quot;,
&#160;&#160;&#160;&#160;&quot;enabled&quot;&#160;:&#160;true
} 

Here is the method defined in controller shown below?

@PostMapping
    public ResponseEntity&lt;Location&gt; addLocation(@RequestBody @Valid Location location) {
        Location addedLocation = service.add(location);
        URI uri = URI.create(&quot;/v1/locations/&quot; + addedLocation.getCode());

        return ResponseEntity.created(uri).body(addedLocation);
    }

How can I fix the issue?

Here is the ErrorDTO below.

@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorDTO {

    private LocalDateTime timestamp;
    private int status;
    private String path;
    private HttpStatus httpStatus;
    List&lt;String&gt; errorDetails;

}

Here is the GlobalExceptionError shown below

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

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

    // handleMissingServletRequestParameter : triggers when there are missing parameters
    @Override
    protected ResponseEntity&lt;Object&gt; handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {

        List&lt;String&gt; details = new ArrayList&lt;String&gt;();
        StringBuilder builder = new StringBuilder();
        builder.append(ex.getMessage() + &quot; is not supported&quot;);
        details.add(builder.toString());

        HttpStatus httpStatus = HttpStatus.valueOf(status.value());

        ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
                .timestamp(LocalDateTime.now())
                .status(status.value())
                .errorDetails(details)
                .path(request.getContextPath())
                .httpStatus(httpStatus)
                .build();

        LOGGER.error(&quot;GlobalExceptionHandler | handleHttpRequestMethodNotSupported&quot;, error);

        return ResponseEntity.status(status).body(error);

    }

    // handleMethodArgumentNotValid : triggers when @Valid fails
    @Override
    protected ResponseEntity&lt;Object&gt; handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
        Map&lt;String, String&gt; errors = new HashMap&lt;&gt;();
        ex.getBindingResult().getFieldErrors().forEach(err -&gt; errors.put(err.getField(), err.getDefaultMessage()));

        LOGGER.error(&quot;GlobalExceptionHandler | handleMethodArgumentNotValid&quot;, errors);

        return ResponseEntity.badRequest()
                .body(errors);
    }

    // handleMissingServletRequestParameter : triggers when there are missing parameters
    @Override
    protected ResponseEntity&lt;Object&gt; handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {


        List&lt;String&gt; details = new ArrayList&lt;String&gt;();
        StringBuilder builder = new StringBuilder();
        builder.append(ex.getParameterName());
        details.add(builder.toString());

        HttpStatus httpStatus = HttpStatus.valueOf(status.value());

        ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
                .timestamp(LocalDateTime.now())
                .status(status.value())
                .errorDetails(details)
                .path(request.getContextPath())
                .httpStatus(httpStatus)
                .build();

        LOGGER.error(&quot;GlobalExceptionHandler | handleMissingServletRequestParameter&quot;, error);

        return ResponseEntity.status(status).body(error);

    }

    // handleHttpMessageNotReadable : triggers when the JSON is malformed
    @Override
    protected ResponseEntity&lt;Object&gt; handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {

        List&lt;String&gt; details = new ArrayList&lt;String&gt;();
        StringBuilder builder = new StringBuilder();
        builder.append(ex.getMessage());
        details.add(builder.toString());

        HttpStatus httpStatus = HttpStatus.valueOf(status.value());

        ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
                .timestamp(LocalDateTime.now())
                .status(status.value())
                .errorDetails(details)
                .path(request.getContextPath())
                .httpStatus(httpStatus)
                .build();

        LOGGER.error(&quot;GlobalExceptionHandler | handleHttpMessageNotReadable&quot;, error);

        return ResponseEntity.status(status).body(error);

    }


    @ExceptionHandler(Exception.class)
    public ErrorDTO handleGenericException(HttpServletRequest request, Exception ex) {

        List&lt;String&gt; details = new ArrayList&lt;String&gt;();
        details.add(ex.getMessage());

        ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
                .timestamp(LocalDateTime.now())
                .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .errorDetails(details)
                .path(request.getServletPath())
                .httpStatus(HttpStatus.INTERNAL_SERVER_ERROR)
                .build();

        LOGGER.error(&quot;GlobalExceptionHandler | handleGenericException&quot;, error);

        return error;
    }
}

Here is the error shown below.

{
&#160;&#160;&#160;&#160;&quot;timestamp&quot;:&#160;&quot;2023-02-17T12:56:02.341+00:00&quot;,
&#160;&#160;&#160;&#160;&quot;status&quot;:&#160;404,
&#160;&#160;&#160;&#160;&quot;error&quot;:&#160;&quot;Not&#160;Found&quot;,
&#160;&#160;&#160;&#160;&quot;trace&quot;:&#160;&quot;org.springframework.dao.DataIntegrityViolationException:&#160;could&#160;not&#160;execute&#160;statement;&#160;SQL&#160;[n/a]\r\n\tat&#160;org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:273)\r\n\tat&#160;org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)\r\n\tat&#160;org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566)\r\n\tat&#160;org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)\r\n\tat&#160;org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)\r\n\tat&#160;org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)\r\n\tat&#160;org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)\r\n\tat&#160;org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\r\n\tat&#160;org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\r\n\tat&#160;org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)\r\n\tat&#160;org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)\r\n\tat&#160;com.skyapi.weatherforecast.location.LocationService$$SpringCGLIB$$0.add(&lt;generated&gt;)\r\n\tat&#160;com.skyapi.weatherforecast.location.LocationApiController.addLocation(LocationApiController.java:21)\r\n\tat&#160;java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\r\n\tat&#160;java.base/java.lang.reflect.Method.invoke(Method.java:578)\r\n\tat&#160;org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)\r\n\tat&#160;org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)\r\n\tat&#160;org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat&#160;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)\r\n\tat&#160;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)\r\n\tat&#160;org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat&#160;org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)\r\n\tat&#160;org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)\r\n\tat&#160;org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)\r\n\tat&#160;org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)\r\n\tat&#160;jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731)\r\n\tat&#160;org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\r\n\tat&#160;jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat&#160;org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat&#160;org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat&#160;org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat&#160;org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat&#160;org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat&#160;org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat&#160;org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat&#160;org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat&#160;org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)\r\n\tat&#160;org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat&#160;org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat&#160;org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)\r\n\tat&#160;org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat&#160;org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat&#160;org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat&#160;org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)\r\n\tat&#160;org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat&#160;org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859)\r\n\tat&#160;org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734)\r\n\tat&#160;org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\r\n\tat&#160;org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat&#160;org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat&#160;org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat&#160;java.base/java.lang.Thread.run(Thread.java:1589)\r\nCaused&#160;by:&#160;org.hibernate.exception.DataException:&#160;could&#160;not&#160;execute&#160;statement\r\n\tat&#160;org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:53)\r\n\tat&#160;org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56)\r\n\tat&#160;org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)\r\n\tat&#160;org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)\r\n\tat&#160;org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)\r\n\tat&#160;org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3429)\r\n\tat&#160;org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:4058)\r\n\tat&#160;org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:103)\r\n\tat&#160;org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:612)\r\n\tat&#160;org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:483)\r\n\tat&#160;java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:729)\r\n\tat&#160;org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:480)\r\n\tat&#160;org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:329)\r\n\tat&#160;org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)\r\n\tat&#160;org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)\r\n\tat&#160;org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1425)\r\n\tat&#160;org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:477)\r\n\tat&#160;org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2234)\r\n\tat&#160;org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1930)\r\n\tat&#160;org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)\r\n\tat&#160;org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)\r\n\tat&#160;org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)\r\n\tat&#160;org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)\r\n\tat&#160;org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)\r\n\t...&#160;58&#160;more\r\nCaused&#160;by:&#160;com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:&#160;Data&#160;truncation:&#160;Data&#160;too&#160;long&#160;for&#160;column&#160;&#39;code&#39;&#160;at&#160;row&#160;1\r\n\tat&#160;com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104)\r\n\tat&#160;com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)\r\n\tat&#160;com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1061)\r\n\tat&#160;com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1009)\r\n\tat&#160;com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1320)\r\n\tat&#160;com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:994)\r\n\tat&#160;com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)\r\n\tat&#160;com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)\r\n\tat&#160;org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)\r\n\t...&#160;77&#160;more\r\n&quot;,
&#160;&#160;&#160;&#160;&quot;message&quot;:&#160;&quot;could&#160;not&#160;execute&#160;statement;&#160;SQL&#160;[n/a]&quot;,
&#160;&#160;&#160;&#160;&quot;path&quot;:&#160;&quot;/v1/locations&quot;
}

Here is the console output shown

org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation

It return this kind of exception message rather than ErrorDTO.

Here is the repo : Link

How can I fix the issue?

答案1

得分: 0

在ErrorDTO上添加@Data注解后,问题消失了。

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorDTO {

    private LocalDateTime timestamp;
    private int status;
    private String path;
    private HttpStatus httpStatus;
    List<String> errorDetails;

}
英文:

After adding @Data annotation to ErrorDTO, the issue disappeared.

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorDTO {
private LocalDateTime timestamp;
private int status;
private String path;
private HttpStatus httpStatus;
List&lt;String&gt; errorDetails;
}

huangapple
  • 本文由 发表于 2023年2月18日 04:21:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488929.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定