Project framework construction
This section is used to prepare for the construction of general projects, mainly including new projects, configuration files, public return classes, exception handling and logs;
These should be common to all projects. Put it here.
1. New project
Select components, generally Spring boot devtools, Mysql Driver, Mybatis framework, Thymeleaf, Spring web and lombok.
First configure the file and then test whether it can be started
(1) Configuration file application.yml
What to do:
- Create an application.yml that manages public configuration
- Create the configuration files of development environment application-dev.yml, production environment application-pro.yml and [test environment application-test.yml];
Note: these two files are respectively connected to the database, redis, rabbitmq and other services of the corresponding environment. Different ports and log output levels are set to correspond to their environment
2. Configuration file
1. Common configuration application.yml
spring: #If there is thymeleaf template engine thymeleaf: mode: HTML cache: false #Close cache # Which configuration file to choose corresponds to the files of application-dev.yml and application-pro.yml profiles: active: dev # If you use mybatis plus, change to the following #mybatis-plus: mybatis: # Package of the corresponding entity class type-aliases-package: com.tab.entity #The package of the corresponding mapper file is under the resources folder mapper-locations: classpath:mapper/*.xml configuration: #Underline hump mapping relationship map-underscore-to-camel-case: true
The following examples show that the development environment and production environment are actually different
2. Development environment application-dev.yml
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver # xxxx corresponds to the name of the database to be connected, followed by optional configuration information to be modified according to the actual situation, such as time zone, etc url: jdbc:mysql://localhost:3306/xxxx?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 'root' #Database connection pool hikari: hikari: pool-name: DateHikariCP #Minimum number of links minimum-idle: 5 #Maximum idle link lifetime, default idle-timeout: 1000000 #maximum connection maximum-pool-size: 10 #Connections returned from the connection pool are automatically submitted auto-commit: true #Maximum connection lifetime; 0 persistent default max-lifetime: 1000000 #Connection timeout, 30 by default connection-timeout: 30000 # Test whether the connection can be used #connection-init-sql: SELECT 1 #Log output level, file logging: level: root: info com.tab: debug file: path: log/blog-dev.log #Service port server: port: 1316
3. Production environment (log level can be set higher)
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/xxxx?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 'root' #Database connection pool hikari: hikari: pool-name: DateHikariCP #Minimum number of links minimum-idle: 5 #Maximum idle link lifetime, default idle-timeout: 1000000 #maximum connection maximum-pool-size: 10 #Connections returned from the connection pool are automatically submitted auto-commit: true #Maximum connection lifetime; 0 permanent lifetime default max-lifetime: 1000000 #Connection timeout, 30 by default connection-timeout: 30000 # Test whether the connection can be used #connection-init-sql: SELECT 1 logging: level: root: warn com.tab: info file: path: log/blog-pro.log server: port: 1317
After the configuration file is ready, you can try to open the project. Success indicates that the database connection is ok;
3. Create public return results
The public return result contains status information and transfer information, which is convenient for subsequent use as the return value in the controller layer;
To create two, one RespBeanEnum and one RespBean;
RespBeanEnum: set some status codes
package com.tab.seckilltest.dto; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; @AllArgsConstructor @Getter @ToString public enum RespBeanEnum { //General status code SUCCESS(200, "success"), ERROR(500, "Server exception"); //Login module status code private final Integer code; private final String meesage; }
RespBean sets the general function of the returned status information
/** * projectName: SeckillTest * fileName: RespBean.java * packageName: com.tab.seckilltest.dto * date: 2021-10-03 21:05 * copyright(c) 2017-2020 xxx company */ package com.tab.seckilltest.dto; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @version: V1.0 * @author: Tab * @className: RespBean * @packageName: com.tab.seckilltest.dto * @description: Returned result object * @data: 2021-10-03 21:05 **/ @AllArgsConstructor @NoArgsConstructor @Data public class RespBean { private long code; private String message; private Object obj; public static RespBean success(){ return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMeesage(), null); } public static RespBean success(Object obj){ return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMeesage(), obj); } public static RespBean error(RespBeanEnum respBeanEnum){ return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMeesage(),null); } }
4. Global exception handling
Spin MVC decouples all types of exception handling from each processing process, and realizes the unified processing and maintenance of exception information;
There are various ways to handle Springboot global exceptions
- Use @ ControllerAdvice and @ ExceptionHandler annotations
- Use the ErrorController class to implement
difference:
1. The @ ControllerAdvice method can only handle the exceptions thrown by the controller. At this time, the request has entered the controller.
2. The errorcontroller class can handle all exceptions, including errors that do not enter the controller, such as 404, 401 and other errors.
3. If the two exist together in the application, the exception thrown by the controller is handled in @ ControllerAdvice mode, and the ErrorController handles the exception that does not enter the controller;
4. The @ ControllerAdvice method can define multiple interceptor methods to intercept different exception classes, and can obtain the thrown exception information with greater freedom;
(1) We create a custom global exception class (we can define different exception classes according to the actual situation) and a GlobalException to handle global exceptions;
This class has a member RespBeanEnum (see above), which contains exception information;
/** * projectName: SeckillTest * fileName: GlobalException.java * packageName: com.tab.seckilltest.exception * date: 2021-10-03 21:27 * copyright(c) 2017-2020 xxx company */ package com.tab.seckilltest.exception; import com.tab.seckilltest.dto.RespBeanEnum; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; /** * @version: V1.0 * @author: Tab * @className: GlobalException * @packageName: com.tab.seckilltest.exception * @description: Set a member variable of an exception type * @data: 2021-10-03 21:27 **/ @Data @Getter @NoArgsConstructor @AllArgsConstructor public class GlobalException extends RuntimeException{ private RespBeanEnum respBeanEnum; }
(2)GlobalExceptionHandler
You can throw custom type exception information directly in the controller (you should also return RespBean object). The front end can obtain information and present it to the user, such as user name and password error;
/** * projectName: SeckillTest * fileName: GlobalExceptionHandler.java * packageName: com.tab.seckilltest.exception * date: 2021-10-03 21:30 * copyright(c) 2017-2020 xxx company */ package com.tab.seckilltest.exception; import com.tab.seckilltest.dto.RespBean; import com.tab.seckilltest.dto.RespBeanEnum; import org.springframework.validation.BindException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; /** * @version: V1.0 * @author: Tab * @className: GlobalExceptionHandler * @packageName: com.tab.seckilltest.exception * @description: * @data: 2021-10-03 21:30 **/ @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public RespBean ExceptionHandler(Exception e){ //If it is a custom exception, its exception information is returned if(e instanceof GlobalException){ GlobalException ex = (GlobalException) e; return RespBean.error(ex.getRespBeanEnum()); } //If it is an exception bound by the springboot framework, handle it else if(e instanceof BindException){ BindException ex = (BindException) e; RespBean respBean = RespBean.error(RespBeanEnum.BIND_ERROR); respBean.setMessage("Parameter verification exception" + ex.getBindingResult().getAllErrors().get(0).getDefaultMessage()); return respBean; } //Return error return RespBean.error(RespBeanEnum.ERROR); } }
5. Log processing
If we want to know the user's access to some information, such as url, ip, classMethod, args, etc., we can use aop to intercept the information when the user accesses the Controller;
/** * projectName: SeckillTest * fileName: LogAspect.java * packageName: com.tab.seckilltest.aspect * date: 2021-10-03 21:58 * copyright(c) 2017-2020 xxx company */ package com.tab.seckilltest.aspect; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /** * @version: V1.0 * @author: Tab * @className: LogAspect * @packageName: com.tab.seckilltest.aspect * @description: * @data: 2021-10-03 21:58 **/ @Slf4j @Aspect @Component public class LogAspect { //Define the facet to the controller package @Pointcut("execution(* com.tab.seckilltest.controller.*.*(..))") public void log(){} //Define request information class @AllArgsConstructor @Data @ToString @NoArgsConstructor private class RequestLog{ private String url; private String ip; private String classMethod; private Object[] args; } @Before("log()") public void doBefore(JoinPoint joinPoint){ log.info("-----doBefore-----"); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String url = request.getRequestURL().toString(); String ip = request.getRemoteAddr(); String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); RequestLog requestLog = new RequestLog(url,ip,classMethod,args); log.info("Request : {}", requestLog); } @After("log()") public void doAfter(JoinPoint joinpoint){ log.info("-----doAfter-----"); } }