java annotation AOP's method for exception handling

  • 2020-06-07 04:28:37
  • OfStack

1. Introduction

When the project was first developed, it was not well prepared. At the level of 1 you don't realize that there are still 1 problem to be solved. For example, today I want to talk about one problem: exception handling. When I write a program, I usually pass try... catch... finally handles exceptions, but can we really write a program that handles all possible exceptions? And what logic to execute when an exception occurs, what message to return, what page to jump to, all these should be taken into account.

2. @ControllerAdvice (enhanced controller) based exception handling

The @ES12en annotation internally USES the @ExceptionHandler, @InitBinder, @ModelAttribute annotation methods to apply to all @RequestMapping annotated methods. In this example, ExceptionHandler is applied to all @RequestMapping annotations to handle the exceptions that occur.

Sample code:


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

@ResponseBody
public class ExceptionAdvice {
 private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionAdvice.class);

 /**
  *  intercept web Layer exceptions, log exceptions, and return friendly information to the front end 
  *  So far only intercept Exception , whether to intercept Error Think again 
  *
  * @param e  The exception object 
  * @return  Abnormal prompt 
  */
 @ExceptionHandler(Exception.class)
 public ResponseEntity<String> handleException(Exception e) {
  // There's no need to record it ServiceException Because, in service The abnormal section has been recorded 
  if (!(e instanceof ServiceException)) {
   LOGGER.error(ExceptionUtils.getExcTrace(e));
  }

  HttpHeaders headers = new HttpHeaders();
  headers.set("Content-type", "text/plain;charset=UTF-8");
  headers.add("icop-content-type", "exception");
  String message = StringUtils.isEmpty(e.getMessage()) ? " A system exception !!" : e.getMessage();
  return new ResponseEntity<>(message, headers, HttpStatus.OK);
 }
}

If this does not work, check the spring-ES25en configuration file for the following configuration of ControllerAdvice


<context:component-scan base-package="com.sishuok.es" use-default-filters="false"> 
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
  <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> 
 </context:component-scan> 

3. AOP-based exception handling

1. Handle exceptions at controller layer WebExceptionAspect.ES35en


import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * web Abnormal section 
 *  The default spring aop Don't intercept controller Layer, using the class required in spring Inject changes in the public configuration file bean . 
 *  You also need to configure <aop:aspectj-autoproxy proxy-target-class="true"/>
 */
@Aspect
public class WebExceptionAspect {
 private static final Logger LOGGER = LoggerFactory.getLogger(WebExceptionAspect.class);

 @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
 private void webPointcut() {}

 /**
  *  intercept web Layer exceptions, log exceptions, and return friendly information to the front end 
  *  So far only intercept Exception , whether to intercept Error Think again 
  *
  * @param e  The exception object 
  */
 @AfterThrowing(pointcut = "webPointcut()", throwing = "e")
 public void handleThrowing(Exception e) {
  // There's no need to record it ServiceException Because, in service The abnormal section has been recorded 
  if (!(e instanceof ServiceException)) {
   LOGGER.error(ExceptionUtils.getExcTrace(e));
  }

  String errorMsg = StringUtils.isEmpty(e.getMessage()) ? " A system exception " : e.getMessage();
  writeContent(errorMsg);
 }

 /**
  *  Output the content to the browser 
  *
  * @param content  output 
  */
 private void writeContent(String content) {
  HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
  response.reset();
  response.setCharacterEncoding("UTF-8");
  response.setHeader("Content-Type", "text/plain;charset=UTF-8");
  response.setHeader("icop-content-type", "exception");
  PrintWriter writer = null;
  try {
   writer = response.getWriter();
  } catch (IOException e) {
   e.printStackTrace();
  }
  writer.print(content);
  writer.flush();
  writer.close();
 }
}

2. Handle exceptions at service layer ES40en.java


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

@Aspect
public class ServiceExceptionAspect {
 private static final Logger LOGGER = LoggerFactory.getLogger(ServiceExceptionAspect.class);

 /**
  * @within(org.springframework.stereotype.Service) , intercept tape  @Service  Annotate all methods of the class 
  * @annotation(org.springframework.web.bind.annotation.RequestMapping) , intercept tape @RquestMapping The annotation method of 
  */
 @Pointcut("@within(org.springframework.stereotype.Service) && execution(public * *(..))")
 private void servicePointcut() {}

 /**
  *  intercept service Layer exception, record the exception log, and set the corresponding exception information 
  *  So far only intercept Exception , whether to intercept Error Think again 
  *
  * @param e  The exception object 
  */
 @AfterThrowing(pointcut = "servicePointcut()", throwing = "e")
 public void handle(JoinPoint point, Exception e) {
  LOGGER.error(ExceptionUtils.getExcTrace(e));

  String signature = point.getSignature().toString();
  String errorMsg = getMessage(signature) == null ? (StringUtils.isEmpty(e.getMessage()) ? " Service exceptions " : e.getMessage()) : getMessage(signature);
  throw new ServiceException(errorMsg, e);
 }

 /**
  *  Gets the prompt message corresponding to the method signature 
  *
  * @param signature  The method signature 
  * @return  The prompt message 
  */
 private String getMessage(String signature) {
  return null;
 }
}

3. Usage: Add the following configuration in the public configuration file of spring:


<aop:aspectj-autoproxy proxy-target-class="true" />
<bean class="com.hjz.exception.aspect.ServiceExceptionAspect" />
<bean class="com.hjz.exception.aspect.WebExceptionAspect" />

Or customize one of the registration classes, ServiceExceptionAspect. java and WebExceptionAspect. java with the @Component annotation


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 *  Abnormal related bean registered 
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.hjz.exception.aspect")
public class ExceptionConfig {

}

@Aspect
@Component
public class WebExceptionAspect {
 .......... 
}


@Aspect
@Component
public class ServiceExceptionAspect {
 .........
}

4. Confused

@ within (org springframework. stereotype. Service), intercept with @ Service annotate the class all the way

@ annotation (org. springframework. web. bind. annotation. RequestMapping), intercept with @ RquestMapping annotation methods

5. Test

Write the exception test class of controller layer and service layer respectively. This is easy, just throw 1 exception in the method. Finally, check 1 to see if @es82EN is executed when an exception occurs. I wrote demo, hey, hey, hey!!

Full project download address: ES86en-AOP_jb51.rar


Related articles: