参考资料
import lombok.Data;
@Data
public class ErrorItemEntity {
// 错误信息ID
private String errorMessageId;
// 错误信息
private String errorMessage;
public static ErrorItemEntity of(String errorMessage, String errorItemId) {
ErrorItemEntity entity = new ErrorItemEntity();
entity.errorMessage = errorMessage;
entity.errorMessageId = errorItemId;
return entity;
}
}
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class ValidationException extends RuntimeException {
// 错误信息
private List<ErrorItemEntity> errors;
/**
* 生成ValidationException异常对象
*
* @param errors 业务异常信息
*/
public ValidationException(List<ErrorItemEntity> errors) {
super();
this.errors = errors;
}
}
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Titletitle>
head>
<body>
<button id="btn">点击发送请求button>
body>
<script src="/js/public/jquery-3.6.0.min.js">script>
<script th:inline="javascript">
function doAjax(url, data, callback) {
$.ajax({
url: url,
type: 'POST',
data: JSON.stringify(data),
contentType : 'application/json;charset=utf-8',
dataType: 'json',
success: function (data, status, xhr) {
if (!!callback) {
callback(data);
}
},
error: function (xhr, textStatus, errorMessage) {
if (xhr.status !== 400) {
location.href = "系统错误页面URL";
}
// 获取错误信息,根据错误ID将画面上的错误信息标记红色
const data = xhr.responseJSON;
console.log(data.errors);
}
});
}
$("#btn").click(() => {
const url = "http://localhost:8080/test3/check";
// 错误的数据,from的值不应该比to还要大
const info = {
from: 100,
to: 10
};
doAjax(url, info, function (data) {
if (!data.result) {
return;
}
console.log(data);
});
});
script>
html>
import lombok.Data;
@Data
public class Test3Form {
private Integer from;
private Integer to;
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/test3")
public class Test3Controller {
@Autowired
private Test3Service service;
@GetMapping("/init")
public ModelAndView init() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("test3");
return modelAndView;
}
@PostMapping("/check")
@ResponseBody
public void check(@RequestBody Test3Form form) throws ValidationException {
service.check(form);
}
}
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class Test3Service {
public void check(Test3Form form) throws ValidationException {
// 当from值 > to值的时候,抛出自定义的校验异常
if (form.getFrom() > form.getTo()) {
List<ErrorItemEntity> errors = Collections.singletonList(ErrorItemEntity.of("大小不对", "id名称"));
throw new ValidationException(errors);
}
}
}
@ConditionalOnProperty
注解一般用于控制配置类是否生效,prefix
为配置文件中的前缀,name 为配置的名称,havingValue
的值若与配置文件中相同,则配置文件生效;若值不同则配置类不生效,相当于该配置类并没有被Spring管理。custom:
log:
action: true
@AfterThrowing
注解的方法中执行,在该方法中可以做一些异常的处理逻辑。要注意的是 throwing 属性的值必须要和参数一致,否则会报错。@ConditionalOnProperty
注解的havingValue
值和配置文件中的值相同,所以下面所示方法中的定时任务会每隔5秒钟执行一次,并且切面也会执行。如果havingValue
的值和配置文件中的值不同的话,则下面类中的定时任务方法和所有的切面方法都不会执行。import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Aspect
@Component
@EnableScheduling
@ConditionalOnProperty(prefix = "custom.log", name = "action", havingValue = "true")
public class LogAspect {
// 定时任务, 每五秒执行一次。
@Scheduled(cron = "0/5 * * * * ?")
public void sendMail(){
System.out.println("模拟邮件已经发送出去");
}
@Before("execution(* com.example.jmw.controller..*(..))")
public void beforeInit(JoinPoint join) {
Signature signature = join.getSignature();
Class declaringType = signature.getDeclaringType();
String simpleName = declaringType.getSimpleName();
String name = declaringType.getName();
Logger log = LoggerFactory.getLogger(name);
log.info("====================================================================");
log.info("[" + simpleName + "." + name + "] START");
log.info("====================================================================");
}
@After("execution(* com.example.jmw.controller..*(..))")
public void afterInit(JoinPoint join) {
Signature signature = join.getSignature();
Logger log = LoggerFactory.getLogger(signature.getDeclaringType().getName());
log.info("====================================================================");
log.info("[" + signature.getDeclaringType().getSimpleName() + "." + signature.getName() + "] START");
log.info("====================================================================");
}
@AfterThrowing(value = "execution(* com.example.jmw.controller..*(..))", throwing = "ex")
public void afterExceptionThrowing(JoinPoint jp, Exception ex) {
// 如果抛出的是我们自定义的校验异常的话
if (ex instanceof ValidationException) {
// 获取出所有的异常信息
ValidationException exception = (ValidationException) ex;
List<ErrorItemEntity> errors = exception.getErrors();
String errorMsg = errors.stream().map(ErrorItemEntity::getErrorMessage).collect(Collectors.joining("-"));
Signature signature = jp.getSignature();
Logger log = LoggerFactory.getLogger(signature.getDeclaringType().getName());
log.info("====================================================================");
log.debug("[" + signature.getDeclaringType().getSimpleName() + "." + signature.getName() + "] Validation: {}", errorMsg);
log.info("====================================================================");
}
}
}