Java SpringBoot 프로젝트에서 작업 로깅을 우아하게 구현하는 방법은 무엇입니까?
1. AOP란 무엇인가요?
AOP(Aspect-Oriented 프로그래밍), AOP라고 하면 Spring 프레임워크를 연구한 거의 모든 사람이 이것이 Spring의 세 가지 핵심 아이디어(IOC: Inversion of Control, DI: 종속성 주입, AOP: Aspect Oriented) 중 하나라는 것을 알고 있습니다. 프로그램 작성). 비즈니스와 관련이 없지만 비즈니스 모듈에서 일반적으로 호출하는 로직이나 책임(트랜잭션 처리, 로그 관리, 권한 제어 등)을 캡슐화하여 시스템 내 코드 중복을 줄이고 비용을 줄일 수 있습니다. 모듈 간의 결합은 향후 확장성과 유지 관리에 도움이 됩니다.
2. AOP는 무슨 일을 했나요?
간단히 말하면 AOP는 크게 3가지 일을 한다.
1 어디를 잘라야 할지, 즉 로깅 같은 비즈니스 코드가 아닌 코드가 실행되는 곳이다.
2. 비즈니스 코드가 실행되기 전이나 후에 중단할 시기.
3. 권한 확인, 로그인 등 전환 후 해야 할 일
사진으로 이해 가능:
사진의 핵심 용어 설명:
Pointcut: cut point, 비즈니스 코드를 잘라낼 위치 결정 중간 (즉, 절단면에 짜여져 있음). 포인트컷은 실행 모드와 주석 모드로 구분됩니다. 실행 모드: 경로 표현식을 사용하여 측면에 짜여진 클래스를 지정할 수 있습니다. 주석 모드: 측면에 짜여진 주석 수정 코드를 지정할 수 있습니다.
Advice: 처리(처리 타이밍 및 콘텐츠 처리 포함). 콘텐츠를 처리한다는 것은 권한 확인, 로그 기록 등의 작업을 수행하는 것을 의미합니다. 처리 시점이란 처리 내용이 실행되는 시기를 말하며, 전처리(즉, 비즈니스 코드 실행 전), 후처리(비즈니스 코드 실행 후) 등으로 구분됩니다.
Aspect: Aspect, 즉 Pointcut 및 Advice입니다.
조인트 포인트: 조인트 포인트는 프로그램 실행 포인트입니다. 예를 들어 메서드 실행이나 예외 처리 등이 있습니다. Spring AOP에서 조인 포인트는 항상 메소드 실행을 나타냅니다.
Weaving: Weaving은 동적 프록시를 통해 대상 객체 방식으로 콘텐츠를 처리하는 과정입니다.
3. 구현 단계
(1) @Log 주석 사용자 정의 (2) 관점 클래스 생성, @Log 주석이 달린 메서드를 가로채는 컷 포인트 설정, 전달된 매개 변수를 가로채서 로깅 수행 (3) 변경 @ Log는 인터페이스에 표시됩니다
구체적인 구현 단계는 다음과 같습니다.
1. AOP 종속성 추가
코드는 다음과 같습니다(예).
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2. 일반적으로 주석은 로그 유형 포인트컷 표현식에 사용됩니다. 먼저 로그 주석을 생성합니다. 스프링 컨테이너가 이 주석으로 메서드를 스캔하면 성능이 향상됩니다.
코드는 다음과 같습니다(예제).@Target({ ElementType.PARAMETER, ElementType.METHOD }) // 注解放置的目标位置,PARAMETER: 可用在参数上 METHOD:可用在方法级别上
@Retention(RetentionPolicy.RUNTIME) // 指明修饰的注解的生存周期 RUNTIME:运行级别保留
@Documented
public @interface Log {
/**
* 模块
*/
String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
}
Aspect 클래스를 선언하고 이를 Spring 컨테이너에 넘겨 관리합니다.
코드는 다음과 같습니다(예):@Aspect
@Component
@Slf4j
public class LogAspect {
@Autowired
private IXlOperLogService operLogService;
/**
* 处理完请求后执行
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturnibng(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handleLog(joinPoint, controllerLog, null, jsonResult);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
// 获取当前的用户
JwtUser loginUser = SecurityUtils.getLoginUser();
// 日志记录
XlOperLog operLog = new XlOperLog();
operLog.setStatus(0);
// 请求的IP地址
String iP = ServletUtil.getClientIP(ServletUtils.getRequest());
if ("0:0:0:0:0:0:0:1".equals(iP)) {
iP = "127.0.0.1";
}
operLog.setOperIp(iP);
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
if (loginUser != null) {
operLog.setOperName(loginUser.getUsername());
}
if (e != null) {
operLog.setStatus(1);
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
operLog.setOperTime(new Date());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 保存数据库
operLogService.save(operLog);
} catch (Exception exp) {
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, XlOperLog operLog, Object jsonResult) throws Exception {
// 设置操作业务类型
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
operLog.setTitle(log.title());
// 是否需要保存request,参数和值
if (log.isSaveRequestData()) {
// 设置参数的信息
setRequestValue(joinPoint, operLog);
}
// 是否需要保存response,参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) {
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
}
}
/**
* 获取请求的参数,放到log中
* @param operLog 操作日志
* @throws Exception 异常
*/
private void setRequestValue(JoinPoint joinPoint, XlOperLog operLog) throws Exception {
String requsetMethod = operLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requsetMethod) || HttpMethod.POST.name().equals(requsetMethod)) {
String parsams = argsArrayToString(joinPoint.getArgs());
operLog.setOperParam(StringUtils.substring(parsams,0,2000));
} else {
Map<?,?> paramsMap = (Map<?,?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
operLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));
}
}
/**
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray) {
String params = "";
if (paramsArray != null && paramsArray.length > 0) {
for (Object object : paramsArray) {
// 不为空 并且是不需要过滤的 对象
if (StringUtils.isNotNull(object) && !isFilterObject(object)) {
Object jsonObj = JSON.toJSON(object);
params += jsonObj.toString() + " ";
}
}
}
return params.trim();
}
/**
* 判断是否需要过滤的对象。
* @param object 对象信息。
* @return 如果是需要过滤的对象,则返回true;否则返回false。
*/
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object object) {
Class<?> clazz = object.getClass();
if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
} else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) object;
for (Object value : collection) {
return value instanceof MultipartFile;
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) object;
for (Object value : map.entrySet()) {
Map.Entry entry = (Map.Entry) value;
return entry.getValue() instanceof MultipartFile;
}
}
return object instanceof MultipartFile || object instanceof HttpServletRequest
|| object instanceof HttpServletResponse || object instanceof BindingResult;
}
}
위 내용은 Java SpringBoot 프로젝트에서 작업 로깅을 우아하게 구현하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요! @Log(title = "代码生成", businessType = BusinessType.GENCODE)
@ApiOperation(value = "批量生成代码")
@GetMapping("/download/batch")
public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
String[] tableNames = Convert.toStrArray(tables);
byte[] data = genTableService.downloadCode(tableNames);
genCode(response, data);
}
해당 작업이 수행되면 로그가 기록되며, 일부 기본 정보가 데이터 테이블에 기록되어 저장됩니다.

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.
