Back-end framework for developing a few things to pay attention

Back-end framework for developing a few things to pay attention

The author writing skill is still shallow, if wrong, please point out the generosity, will be grateful

Stumbled on the road programmers also have a year's time, and slowly feel that this year most of their time is spent in a simple CRUD, whereas sometimes much repetitive code that we have in the CRUD it? Every time we write some code that requires repetitive write once, not only a waste of time, but also for their own lift and there is not much improved. Accidentally saw programmers Why are you so tired after article before their senses, why do we work so long without some public part extracted, reducing the amount of code to make us more focused on improving technology or business is not it?

In conjunction with the above-mentioned article in question described, and they combine some of my experience the last year, so in the back-end development framework that can be drawn out of the public part of the following section

  • Custom enumeration class
  • Custom exception information
  • Unified return information
  • Global exception handler
  • Unified log Print

Custom enumeration class

For some error we often returned, we can be extracted into a common part of the package, and then passed as a parameter change. For example, we in the business often have to check whether a field is empty, if empty, then we should return an error message xxx field can not be empty, so why do not we will xxx variable as a parameter passed over it. So I thought enumeration class defined by the abnormality information, and then String.format()escaped method

public enum ResponseInfoEnum {

    SUCCESS(ResponseResult.OK,"处理成功"),
    PARAM_LENGTH_ERROR(ResponseResult.ERROR, "参数:%s,长度错误,max length: %s"),
    REQ_PARAM_ERROR(ResponseResult.ERROR, "请求报文必填参数%s缺失"),;

    private Integer code;
    private String message;

    ResponseInfoEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

}

复制代码

Use the following method

String.format(ResponseInfoEnum.REQ_PARAM_ERROR.getMessage(),"testValue")

复制代码

We can see the error message is generated请求报文必填参数testValue缺失

Custom exception information

First of all we need to know why we use custom exception message? Use it what good is it?

  1. First, we must be the development of sub-module development, so first we unified the custom exception class to unify the external display unusual way.
  2. Use custom exception inherited abnormalities related to thrown processed information can hide the underlying abnormality, which is more secure, more intuitive information is also abnormal. Information can throw custom exception throw us they want, the location information can be distinguished by the thrown exception it occurs, according to the exception name we can know where the abnormal changes in procedures carried out in accordance with an exception message.
  3. Sometimes we encounter some check or problem that requires immediate end off the current request, it will be ready to end by throwing a custom exception if you are using a relatively new project version SpringMVC words have enhanced controller , a controller can be written annotations @ControllerAdvice enhanced custom classes to intercept and respond to the abnormality information to the corresponding distal end.

We need to inherit custom exceptionRuntimeException

public class CheckException extends RuntimeException{

    public CheckException() {
    }

    public CheckException(String message) {
        super(message);
    }

    public CheckException(ResponseInfoEnum responseInfoEnum,String ...strings) {
        super(String.format(responseInfoEnum.getMessage(),strings));
    }
}

复制代码

Unified return information

Most of the project in the year I started to work, that is in contact with the front and rear ends of the interaction of the project. So there is a unified return information is not only more convenient for the front, the back of our AOP proxy is also a great advantage.

@Data
@NoArgsConstructor
public class ResponseResult<T> {
    public static final Integer OK = 0;
    public static final Integer ERROR = 100;

    private Integer code;
    private String message;
    private T data;
}

复制代码

So that the front and rear end when interacting will be more convenient, if you want to take business data then taken from the data, the flag went to take if successful, would take the code from the code, if you want to take the information returned by the backend, then he took it from the message in.

Global exception handler

Before the project I each Controllermethod are filled with try....catch...code, and the code after the catch are similar, are packaging a bit like an error message is returned. So why did not these codes extracted using Spring's global exception handler simplify our code?

@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {


    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseResult<String> defaultErrorHandler(HttpServletRequest request, Exception exception){
        log.error(ControllerLog.getLogPrefix()+"Exception: {}"+exception);
        return handleErrorInfo(exception.getMessage());
    }

    @ExceptionHandler(CheckException.class)
    @ResponseBody
    public ResponseResult<String> checkExceptionHandler(HttpServletRequest request, CheckException exception){
        return handleErrorInfo(exception.getMessage());
    }

    private ResponseResult<String> handleErrorInfo(String message) {
        ResponseResult<String> responseEntity = new ResponseResult<>();
        responseEntity.setMessage(message);
        responseEntity.setCode(ResponseResult.ERROR);
        responseEntity.setData(message);
        ControllerLog.destoryThreadLocal();
        return responseEntity;
    }
}

复制代码

Where the global exception handler, the exception is our custom log does not print, because for custom exception we are known exception, and the error message has also been very clear returns. For example, an unknown anomaly Exceptionbelongs to an unknown anomaly, we need to print the log, if there are special needs, such as text messaging, e-mail notifying people, then there can also be global configuration.

Unified log Print

Unified logging print only the project of public printing logs extracted using AOP to print, for example, we project substantially into the reference method for each Controller and the reference prints, so this part drawn out unified management.

@Slf4j
@Aspect
@Component
public class ControllerLog {

    private static final ThreadLocal<Long> START_TIME_THREAD_LOCAL =
            new NamedThreadLocal<>("ThreadLocal StartTime");

    private static final ThreadLocal<String> LOG_PREFIX_THREAD_LOCAL =
            new NamedThreadLocal<>("ThreadLocal LogPrefix");

    /**
     * <li>Before       : 在方法执行前进行切面</li>
     * <li>execution    : 定义切面表达式</li>
     * <p>public * com.example.javadevelopmentframework.javadevelopmentframework.controller..*.*(..))
     *      <li>public :匹配所有目标类的public方法,不写则匹配所有访问权限</li>
     *      <li>第一个* :方法返回值类型,*代表所有类型 </li>
     *      <li>第二个* :包路径的通配符</li>
     *      <li>第三个..* :表示impl这个目录下所有的类,包括子目录的类</li>
     *      <li>第四个*(..) : *表示所有任意方法名,..表示任意参数</li>
     * </p>
     * @param
     */
    @Pointcut("execution(public * com.example.javadevelopmentframework.javadevelopmentframework.controller..*.*(..))")
    public void exectionMethod(){}


    @Before("exectionMethod()")
    public void doBefore(JoinPoint joinPoint){
        START_TIME_THREAD_LOCAL.set(System.currentTimeMillis());
        StringBuilder argsDes = new StringBuilder();
        //获取类名
        String className = joinPoint.getSignature().getDeclaringType().getSimpleName();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取传入目标方法的参数
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            argsDes.append("第" + (i + 1) + "个参数为:" + args[i]+"\n");
        }
        String logPrefix = className+"."+methodName;
        LOG_PREFIX_THREAD_LOCAL.set(logPrefix);
        log.info(logPrefix+"Begin 入参为:{}",argsDes.toString());
    }

    @AfterReturning(pointcut="exectionMethod()",returning = "rtn")
    public Object doAfter(Object rtn){
        long endTime = System.currentTimeMillis();
        long begin = START_TIME_THREAD_LOCAL.get();
        log.info(LOG_PREFIX_THREAD_LOCAL.get()+"End 出参为:{},耗时:{}",rtn,endTime-begin);
        destoryThreadLocal();
        return rtn;
    }

    public static String getLogPrefix(){
        return LOG_PREFIX_THREAD_LOCAL.get();
    }

    public static void destoryThreadLocal(){
        START_TIME_THREAD_LOCAL.remove();
        LOG_PREFIX_THREAD_LOCAL.remove();
    }

}

复制代码

test

We Conrollerwrite the following test

@RestController
public class TestFrameworkController {

    @RequestMapping("/success/{value}")
    public String success(@PathVariable String value){
        return "Return "+value;
    }

    @RequestMapping("/error/{value}")
    public String error(@PathVariable String value){
        int i = 10/0;
        return "Return "+value;
    }
}

复制代码

Unit test code is as follows

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = JavadevelopmentframeworkApplication.class)
@AutoConfigureMockMvc
public class JavadevelopmentframeworkApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void success() throws Exception {
		mockMvc.perform(get("/success/11"));
		mockMvc.perform(get("/error/11"));
	}

}

复制代码

Printing can be seen as

2019-09-03 20:38:22.248  INFO 73902 --- [           main] c.e.j.j.aop.ControllerLog                : TestFrameworkController.successBegin 入参为:第1个参数为:11
2019-09-03 20:38:22.257  INFO 73902 --- [           main] c.e.j.j.aop.ControllerLog                : TestFrameworkController.successEnd 出参为:Return 11,耗时:10
2019-09-03 20:38:22.286  INFO 73902 --- [           main] c.e.j.j.aop.ControllerLog                : TestFrameworkController.errorBegin 入参为:第1个参数为:11
2019-09-03 20:38:22.288 ERROR 73902 --- [           main] c.e.j.j.aop.ControllerExceptionHandler   : TestFrameworkController.errorException: {}java.lang.ArithmeticException: / by zero

复制代码

You can see each method to access the Controller to the Senate, the Senate and the execution time of the whole process have been printed out. Also in the method of the second capture test and the abnormality information to the printing log.

The complete code

to sum up

In the coding process, we also need to constantly sum up, whether it is set up or change system needs, we need to consider which part is which part of the change is constant, the same extracted, change the package together. So in the future system expansion or whether it needs to change, we are able to minimize the cost to complete the task.

Guess you like

Origin juejin.im/post/5d6e6077f265da039a28a49f