公共依赖模块指的是多个模块之间共享的工具类、配置类、异常类、全局异常处理、全局返回值对象、公共依赖等。使用common模块应该尽可能的避免高耦合的情。下面我们来总结一下common模块的工作原理。
1. 打包方式
并不会使用spring-boot-maven-plugin打包插件来打包自己,而是使用Maven自带的打包方式,也就是:
<packaging>jar</packaging>
这种方式只会把类编译后生成的class文件打包在一个jar里,不会打包类包含的第三方依赖,并且在该项目里的pom.xml文件里面的声明的依赖也不会打包进来,这样就保证了common的轻量级。
2.配置文件
对于配置类,我们都会添加@Configuration这样的注解,只要我们类所在的包能被Spring扫描到,则我们的配置对象均会被Spring创建出来放在IOC容器里面。Spring默认的包扫描会扫面jar里面的配置类。
3.全局异常处理
全局异常处理使用@RestControllerAdvice 进行标记,它的工作方式也是将当前的类创建出来对象放在IOC里面
4.常用的常量
public class Constants {
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 成功标记
*/
public static final Integer SUCCESS = 200;
/**
* 失败标记
*/
public static final Integer FAIL = 500;
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 验证码有效期(分钟)
*/
public static final long CAPTCHA_EXPIRATION = 2;
}
5.统一的返回值对象
/**
* 公共的返回值对象
*
* @param <T>
*/
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 成功
*/
public static final int SUCCESS = Constants.SUCCESS;
/**
* 失败
*/
public static final int FAIL = Constants.FAIL;
private int code;
private String msg;
private T data;
public static <T> R<T> ok() {
return restResult(null, SUCCESS, null);
}
public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, null);
}
public static <T> R<T> ok(T data, String msg) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail() {
return restResult(null, FAIL, null);
}
public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data) {
return restResult(data, FAIL, null);
}
public static <T> R<T> fail(T data, String msg) {
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
6.公用的切面
web日志记录
@Aspect
@Component
@Order(1)
@Slf4j
public class WebLogAspect {
@Pointcut("execution( * com.bjsxt.controller.*.*(..))")
public void webLog() {
}
@Around(value = "webLog()")
public Object recordWebLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
StopWatch stopWatch = new StopWatch(); // 创建计时器
stopWatch.start(); // 开始计时器
result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); // 不需要我们自己处理这个异常
stopWatch.stop(); // 记时结束
// 获取请求的上下文
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 获取登录的用户
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 获取方法
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
// 获取方法上的ApiOperation注解
ApiOperation annotation = method.getAnnotation(ApiOperation.class);
// 获取目标对象的类型名称
String className = proceedingJoinPoint.getTarget().getClass().getName();
// 获取请求的url 地址
String requestUrl = request.getRequestURL().toString();
WebLog webLog = WebLog.builder()
.basePath(StrUtil.removeSuffix(requestUrl, URLUtil.url(requestUrl).getPath()))
.description(annotation == null ? "no desc" : annotation.value())
.ip(request.getRemoteAddr())
.parameter(getMethodParameter(method, proceedingJoinPoint.getArgs()))
.method(className + "." + method.getName())
.result(request == null ? "" : JSON.toJSONString(request))
.recodeTime(System.currentTimeMillis())
.spendTime(stopWatch.getTotalTimeMillis())
.uri(request.getRequestURI())
.url(request.getRequestURL().toString())
.username(authentication == null ? "anonymous" : authentication.getPrincipal().toString())
.build();
log.info(JSON.toJSONString(webLog, true));
return result;
}
/**
* {
* "":value,
* "":"value"
* }
*
* @param method
* @param args
* @return
*/
private Object getMethodParameter(Method method, Object[] args) {
LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(method);
HashMap<String, Object> methodParameters = new HashMap<>();
Parameter[] parameters = method.getParameters();
if (args != null) {
for (int i = 0; i < parameterNames.length; i++) {
methodParameters.put(parameterNames[i], args[i] == null ? "" : JSON.toJSONString(args[i]));
}
}
return methodParameters;
}
}
全局web的异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = ApiException.class)
public R handle(ApiException e) {
if (e.getErrorCode() != null) {
return R.fail(e.getErrorCode());
}
return R.fail(e.getMessage());
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String message = null;
if (bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null) {
message = fieldError.getField() + fieldError.getDefaultMessage();
}
}
return R.fail(message);
}
@ExceptionHandler(value = BindException.class)
public R handleValidException(BindException e) {
BindingResult bindingResult = e.getBindingResult();
String message = null;
if (bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null) {
message = fieldError.getField() + fieldError.getDefaultMessage();
}
}
return R.fail(message);
}
}