상세 한 설명 은 SpringBoot 를 바탕 으로 AOP 기술 을 사용 하여 작업 로그 관 리 를 실현 합 니 다.

작업 로 그 는 프로그래머 나 관리자 에 게 시스템 과 관련 된 작업 을 신속하게 찾 을 수 있 지만 작업 로그 의 관리 실현 에 정상 적 인 업무 실현 에 영향 을 줄 수 없습니다.그렇지 않 으 면 단일 원칙 을 만족 시 키 지 못 하고 후속 코드 유지 에 어려움 을 초래 할 수 있 습 니 다.따라서 저 희 는 AOP 절단면 기술 을 사용 하여 로그 관리 에 대한 실현 을 고려 합 니 다.
글 의 대략적인 내용:
1.기본 개념
2.기본 응용
3.일지 관리 실전
이 부분 을 이해 하면 AOP 에 대한 애플 리 케 이 션 이 수월 할 것 이다.
기본 개념
항목
묘사 하 다.
Aspect(절단면)
여러 가지 관심 사 를 뛰 어 넘 는 모듈 화,절단면 은 알림 과 접점 의 결합 이다.통지 와 접점 은 절단면 의 모든 내용 인 그것 이 무엇 인지,언제 어디서 그 기능 을 완성 하 는 지 를 공동으로 정의 했다.트 랜 잭 션 처리 와 로그 처 리 는 절단면 으로 이해 할 수 있다.
조인 트 포인트(연결 점)
프로그램의 실행 과정 중 하나,예 를 들 어 방법의 실행 이나 이상 한 처리
조언(알림)
절단면 이 특정 연결 점 에서 취 하 는 동작
포인트 컷(접점)
연결 점 에 일치 하 는 단언.알림 은 삽입점 표현 식 과 연결 되 어 있 으 며,삽입점 과 일치 하 는 모든 연결 점 에서 실 행 됩 니 다(예 를 들 어 특정한 이름 을 가 진 방법의 실행).접점 표현 식 과 일치 하 는 연결 점 개념 은 AOP 의 핵심 이 며,Spring 은 기본적으로 AspectJ 접점 표현 식 언어 를 사용 합 니 다.
소개(인용)
형식 에 다른 방법 이나 필드 를 설명 합 니 다.Spring AOP 는 모든 제안 대상 에 게 새로운 인 터 페 이 스 를 도입 할 수 있 습 니 다(해당 되 는 구현 과).예 를 들 어,bean 이 IsModified 인 터 페 이 스 를 실현 하도록 소 개 를 사용 하여 캐 시 를 간소화 할 수 있 습 니 다.
대상 개체(대상)
하나 이상 의 절단면 으로 알려 진 대상.알림 대상 이 라 고도 부른다.Spring AOP 는 실행 시 대 리 를 통 해 이 루어 지기 때문에 이 대상 은 항상 대리 대상 입 니 다.
AOP 프 록 시(에이전트)
AOP 프레임 워 크 가 절단면 계약(알림 방법 실행 등)을 실현 하기 위해 만 든 대상.Spring 프레임 워 크 에서 AOP 에이 전 트 는 JDK 동적 에이전트 또는 CGLIB 에이전트 입 니 다.
Weaving(짜 임)
직 입 은 대상 클래스 의 구체 적 인 연결 점 에 알림 을 추가 하 는 과정 으로 컴 파일 할 때(예 를 들 어 AspectJ 컴 파일 러 사용),불 러 올 때 또는 실행 할 때 완료 할 수 있 습 니 다.
Spring 절단면 은 5 가지 유형의 알림 을 사용 할 수 있 습 니 다.
  • 사전 알림(Before):목표 방법 이 호출 되 기 전에 알림 을 호출 합 니 다
  • 후 설치 알림(After):목표 방법 이 완 료 된 후에 호출 알림(정상 이 든 이상 이 든 종료)
  • 반환 알림(After-returning):목표 방법 이 성공 적 으로 실 행 된 후에 호출 알림
  • 이상 알림(After-throwing):목표 방법 에 이상 을 던 진 후 호출 알림
  • 서 라운드 알림(Around):통 지 된 방법 을 알 리 고 통 지 된 방법 이 호출 되 기 전과 호출 된 후에 사용자 정의 행 위 를 수행 합 니 다
  • 그 실행 순 서 는 다음 과 같다.
    在这里插入图片描述
    在这里插入图片描述
    후속 적 인 기본 응용 은 서 라운드 알림,사전 알림,사후 알림,반환 알림,이상 알림 을 실현 하고 실행 순 서 를 보 여 줍 니 다.
    2.기본 응용
    성명 통지
    아래 코드 를 복사 해서 위의 실행 순 서 를 검증 할 수 있 습 니 다.
    
    @Aspect
    public class Test {
     private static int step = 0;
    
     @Pointcut("@annotation(com.chenyanwu.erp.erpframework.annotation.Log)") // the pointcut expression
     private void operation() {}
    
     @Before("operation()")
     public void doBeforeTask() {
      System.out.println(++step + "     ");
     }
    
     @After("operation()")
     public void doAfterTask() {
      System.out.println(++step + "     ");
     }
    
     @AfterReturning(pointcut = "operation()", returning = "retVal")
     public void doAfterReturnningTask(Object retVal) {
      System.out.println(++step + "     ,    :" + retVal.toString());
     }
    
     @AfterThrowing(pointcut = "operation()", throwing = "ex")
     public void doAfterThrowingTask(Exception ex) {
      System.out.println(++step + "     ,     :" + ex.getMessage());
     }
    
     /**
      *         ProceedingJoinPoint      
      *                ProceedingJoinPoint                  
      *            ,            
      */
     //@Around("operation()")
     public Object doAroundTask(ProceedingJoinPoint pjp) {
      String methodname = pjp.getSignature().getName();
      Object result = null;
      try {
       //     
       System.out.println("    " + methodname + "  ,   " + Arrays.asList(pjp.getArgs()));
       //       
       result = pjp.proceed();
       //     
       System.out.println("    " + methodname + "    ,  " + result);
      } catch (Throwable e) {
       //     
       System.out.println("    " + methodname + "    : " + e.getMessage());
      }
      //     
      System.out.println("    " + methodname + "  ");
      return result;
     }
    }
    그 중에서 주의해 야 할 것 은 삽입점:@Pointcut 의 표현 식 입 니 다.
    형식:
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
    괄호 안의 각 pattern 은 각각 다음 과 같이 표시 합 니 다.
  • 수정자 일치(modifier-pattern?)
  • 반환 값 일치(ret-type-pattern)는*로 모든 반환 값,전체 경로 의 클래스 이름 등 을 표시 할 수 있 습 니 다
  • 클래스 경로 일치(declaring-type-pattern?)방법 명 일치(name-pattern)는 방법 명 을 지정 하거나 모든 것 을 대표 할 수 있 습 니 다.set 는 set 로 시작 하 는 모든 방법 을 대표 합 니 다
  • 매개 변수 매 칭(param-pattern)은 구체 적 인 매개 변수 유형 을 지정 할 수 있 고 여러 매개 변수 간 에','분리'를 사용 할 수 있 으 며 각 매개 변 수 는'''로 표시 할 수 있 습 니 다.예 를 들 어(String)은 하나의 String 매개 변수 와 일치 하 는 방법 을 표시 합 니 다.(..String)두 개의 매개 변 수 를 일치 시 키 는 방법 을 표시 합 니 다.첫 번 째 매개 변 수 는 임의의 유형 일 수 있 고 두 번 째 매개 변 수 는 String 형식 입 니 다.0 개 또는 여러 개의 임 의 매개 변 수 를 표시 할 수 있 습 니 다
  • 이상 유형 일치(throws-pattern?)그 중 뒤 에는'?'옵션
    예시:
    1)execution(* (…))
    //일치 하 는 모든 방법 을 표시 합 니 다.
    2)execution(public * com. savage.service.UserService.(…))
    //com.savage.server.UserService 에 일치 하 는 모든 공유 방법 을 표시 합 니 다.
    3)execution(* com.savage.server….(…))
    //com.savage.server 패키지 와 하위 패키지 에 일치 하 는 모든 방법 을 표시 합 니 다.
    3.일지 관리 실전
    위의 기본 적 인 응용 에 대한 이해 가 생 겼 습 니 다.지금 우 리 는 바로 코드 를 붙 입 니 다.
    1,의존 하 는 jar 가방
    
    <!-- aop   -->
    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    2.사용자 정의 주석
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Log {
     String value() default "";
    }
    
    3.절단면 실현
    
    @Aspect
    @Order(5)
    @Component
    public class LogAspect {
    
     private Logger logger = LoggerFactory.getLogger(LogAspect.class);
    
     @Autowired
     private ErpLogService logService;
    
     @Autowired
     ObjectMapper objectMapper;
    
     private ThreadLocal<Date> startTime = new ThreadLocal<Date>();
    
     @Pointcut("@annotation(com.chenyanwu.erp.erpframework.annotation.Log)")
     public void pointcut() {
    
     }
    
     /**
      *     , Controller      
      *
      * @param joinPoint    
      */
     @Before("pointcut()")
     public void doBefore(JoinPoint joinPoint) {
      //         
      startTime.set(new Date());
     }
    
     /**
      *       
      *
      * @param joinPoint    
      * @param rvt      
      */
     @AfterReturning(pointcut = "pointcut()", returning = "rvt")
     public void doAfter(JoinPoint joinPoint, Object rvt) throws Exception {
      handleLog(joinPoint, null, rvt);
     }
    
     /**
      *       
      *
      * @param joinPoint
      * @param e
      */
     @AfterThrowing(pointcut = "pointcut()", throwing = "e")
     public void doAfter(JoinPoint joinPoint, Exception e) throws Exception {
      handleLog(joinPoint, e, null);
     }
    
     @Async
     private void handleLog(final JoinPoint joinPoint, final Exception e, Object rvt) throws Exception{
      //     
      Method method = getMethod(joinPoint);
      Log log = getAnnotationLog(method);
      if (log == null) {
       return;
      }
      Date now = new Date();
      //         
      ErpLog erpLog = new ErpLog();
      erpLog.setErrorCode(0);
      erpLog.setIsDeleted(0);
      //     
      HttpServletRequest request = ToolUtil.getRequest();
      erpLog.setType(ToolUtil.isAjaxRequest(request) ? "Ajax  " : "    ");
      erpLog.setTitle(log.value());
      erpLog.setHost(request.getRemoteHost());
      erpLog.setUri(request.getRequestURI().toString());
    //  erpLog.setHeader(request.getHeader(HttpHeaders.USER_AGENT));
      erpLog.setHttpMethod(request.getMethod());
      erpLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
      //         
      Object[] args = joinPoint.getArgs();
      //          
      LocalVariableTableParameterNameDiscoverer u
        = new LocalVariableTableParameterNameDiscoverer();
      String[] paramNames = u.getParameterNames(method);
      if (args != null && paramNames != null) {
       StringBuilder params = new StringBuilder();
       params = handleParams(params, args, Arrays.asList(paramNames));
       erpLog.setParams(params.toString());
      }
      String retString = JsonUtil.bean2Json(rvt);
      erpLog.setResponseValue(retString.length() > 5000 ? JsonUtil.bean2Json("            ") : retString);
      if (e != null) {
       erpLog.setErrorCode(1);
       erpLog.setErrorMessage(e.getMessage());
      }
      Date stime = startTime.get();
      erpLog.setStartTime(stime);
      erpLog.setEndTime(now);
      erpLog.setExecuteTime(now.getTime() - stime.getTime());
      erpLog.setUsername(MySysUser.loginName());
      HashMap<String, String> browserMap = ToolUtil.getOsAndBrowserInfo(request);
      erpLog.setOperatingSystem(browserMap.get("os"));
      erpLog.setBrower(browserMap.get("browser"));
      erpLog.setId(IdUtil.simpleUUID());
      logService.insertSelective(erpLog);
     }
    
     /**
      *       ,       
      */
     private Log getAnnotationLog(Method method) {
      if (method != null) {
       return method.getAnnotation(Log.class);
      }
      return null;
     }
    
     private Method getMethod(JoinPoint joinPoint) {
      Signature signature = joinPoint.getSignature();
      MethodSignature methodSignature = (MethodSignature) signature;
      Method method = methodSignature.getMethod();
      if (method != null) {
       return method;
      }
      return null;
     }
    
     private StringBuilder handleParams(StringBuilder params, Object[] args, List paramNames) throws JsonProcessingException {
      for (int i = 0; i < args.length; i++) {
       if (args[i] instanceof Map) {
        Set set = ((Map) args[i]).keySet();
        List list = new ArrayList();
        List paramList = new ArrayList<>();
        for (Object key : set) {
         list.add(((Map) args[i]).get(key));
         paramList.add(key);
        }
        return handleParams(params, list.toArray(), paramList);
       } else {
        if (args[i] instanceof Serializable) {
         Class<?> aClass = args[i].getClass();
         try {
          aClass.getDeclaredMethod("toString", new Class[]{null});
          //      NoSuchMethodException       toString    ,   writeValueAsString ,     Object  toString  
          params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i]));
         } catch (NoSuchMethodException e) {
          params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i].toString()));
         }
        } else if (args[i] instanceof MultipartFile) {
         MultipartFile file = (MultipartFile) args[i];
         params.append(" ").append(paramNames.get(i)).append(": ").append(file.getName());
        } else {
         params.append(" ").append(paramNames.get(i)).append(": ").append(args[i]);
        }
       }
      }
      return params;
     }
    }
    4,대응 코드 추가 설명
    
    @Log("    ")
     @RequestMapping(value = "/create", method = RequestMethod.POST)
     @ResponseBody
     public ResultBean<String> create(@RequestBody @Validated ErpStudent item) {
      if(service.insertSelective(item) == 1) {
       //   
       insertErpSFamilyMember(item);
       return new ResultBean<String>("");
      }
    
      return new ResultBean<String>(ExceptionEnum.BUSINESS_ERROR, "      !", "    !", "");
     }
    업 무 를 조작 한 후에 데이터 베 이 스 를 기록 하고 인터페이스 조회:
    在这里插入图片描述
    로그 관리의 전체 코드 는 git 에서 가 져 올 수 있 습 니 다:
    https://github.com/chyanwu/erp-framework
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기