Springboot-주해-조작 로그 의 실현 방식

12787 단어 Springboot주해로그
이 구성 요소 가 해결 한 문 제 는:
누구?
이 구성 요 소 는 현재 Spring-boot 에 대해 Autoconfig 를 만 들 었 습 니 다.SpringMVC 라면 xml 에서 bean 을 초기 화 할 수 있 습 니 다.
사용 방식
기본 사용
maven 의존 SDK 의존 추가

  <dependency>
   <groupId>io.github.mouzt</groupId>
   <artifactId>bizlog-sdk</artifactId>
   <version>1.0.1</version>
  </dependency>
SpringBoot 입구 에서 스위치 를 열 고@EnableLogRecord 주 해 를 추가 합 니 다.
tenant 는 세입 자 를 대표 하 는 표지 로 보통 하나의 서비스 나 한 업무 에서 의 여러 서 비 스 는 하나의 tenant 를 쓰 면 된다.

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
@EnableLogRecord(tenant = "com.mzt.test")
public class Main {
 public static void main(String[] args) {
  SpringApplication.run(Main.class, args);
 }
}
로그 매 립 점
1.일반적인 기록 로그
pefix:bizNo 에 로그 로 연결 되 어 있 는 표지 입 니 다.bizNo 가 정수 ID 일 때 다른 업무 의 ID 와 중복 되 지 않도록 합 니 다.예 를 들 어 주문 ID,사용자 ID 등
bizNo:바로 업무 의 ID 입 니 다.예 를 들 어 주문 ID 입 니 다.저희 가 조회 할 때 bizNo 에 따라 관련 작업 로 그 를 조회 할 수 있 습 니 다.
success:방법 호출 성공 후 success 를 로그 내용 에 기록 합 니 다.
SpEL 표현 식:이중 괄호 로 둘러싸 인(예:{\#order.purchase Name})\#order.purchase Name 은 SpEL 표현 식 입 니 다.Spring 에서 지원 하 는 것 은 모두 지원 합 니 다.예 를 들 어 정적 방법,세 가지 표현 식 을 호출 합 니 다.SpEL 은 방법 중의 모든 인 자 를 사용 할 수 있 습 니 다.

 @LogRecordAnnotation(success = "{{#order.purchaseName}}      ,    「{{#order.productName}}」,    :{{#_ret}}",
    prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
 public boolean createOrder(Order order) {
  log.info("【    】orderNo={}", order.getOrderNo());
  // db insert order
  return true;
 }
이 때 작업 로 그 를 인쇄 합 니 다."장 3 에서 주문 서 를 내 렸 습 니 다.상품 을 구 매 합 니 다."초 특급 할인 불고기 세트"를 구 매 합 니 다.주문 결과:true"
2.실패 로 그 를 기록 하 기 를 원 합 니 다.이상 을 던 지면 fail 로 그 를 기록 하고 success 로 그 를 기록 하지 않 습 니 다.

 @LogRecordAnnotation(
   fail = "      ,    :「{{#_errorMsg}}」",
   success = "{{#order.purchaseName}}      ,    「{{#order.productName}}」,    :{{#_ret}}",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
 public boolean createOrder(Order order) {
  log.info("【    】orderNo={}", order.getOrderNo());
  // db insert order
  return true;
 }
그 중의\#errorMsg 는 이상 한 errorMessage 를 던 지 는 방법 입 니 다.
3.로그 지원 종류
예 를 들 어 주문 한 작업 로그,일부 작업 로 그 는 사용자 가 직접 작 동 합 니 다.일부 작업 은 시스템 운영 자가 수정 한 작업 로 그 를 만 들 었 습 니 다.저희 시스템 은 운영 로 그 를 사용자 에 게 노출 시 키 고 싶 지 않 습 니 다.
그러나 운영 은 사용자 의 로그 와 자신 이 조작 한 로 그 를 볼 수 있 기 를 기대 합 니 다.이 작업 로 그 를 운영 하 는 bizNo 는 모두 주문 번호 이기 때문에 형식 필드 를 확장 하기 위해 로 그 를 분류 하고 조회 가 편리 하 며 더 많은 업 무 를 지원 합 니 다.

 @LogRecordAnnotation(
   fail = "      ,    :「{{#_errorMsg}}」",
   category = "MANAGER",
   success = "{{#order.purchaseName}}      ,    「{{#order.productName}}」,    :{{#_ret}}",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
 public boolean createOrder(Order order) {
  log.info("【    】orderNo={}", order.getOrderNo());
  // db insert order
  return true;
 }
4.작업 의 상세 한 내용 이나 추가 정 보 를 기록 하 는 것 을 지원 합 니 다.
한 작업 이 많은 필드 를 수정 하 였 으 나,success 로그 모드 에 서 는 너무 길 지 않도록 수정 정 보 를 모두 보 여 주지 못 합 니 다.이 럴 때 수정 정 보 를 detail 필드 에 저장 해 야 합 니 다.
detail 은 String 입 니 다.스스로 정렬 해 야 합 니 다.여기\#order.toString()은 Order 의 toString()방법 을 호출 했 습 니 다.
JSON 을 저장 하면 Order 의 toString()방법 을 직접 다시 쓰 면 된다.

 @LogRecordAnnotation(
   fail = "      ,    :「{{#_errorMsg}}」",
   category = "MANAGER_VIEW",
   detail = "{{#order.toString()}}",
   success = "{{#order.purchaseName}}      ,    「{{#order.productName}}」,    :{{#_ret}}",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
 public boolean createOrder(Order order) {
  log.info("【    】orderNo={}", order.getOrderNo());
  // db insert order
  return true;
 }
5.로그 조작 자 를 어떻게 지정 합 니까?프레임 워 크 는 두 가지 방법 을 제공 했다.
첫 번 째:LogRecord 의 주석 에 수 동 으로 지정 합 니 다.이런 필요 한 방법 은 매개 변수 에 operator 가 있다.

 @LogRecordAnnotation(
   fail = "      ,    :「{{#_errorMsg}}」",
   category = "MANAGER_VIEW",
   detail = "{{#order.toString()}}",
   operator = "{{#currentUser}}",
   success = "{{#order.purchaseName}}      ,    「{{#order.productName}}」,    :{{#_ret}}",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
 public boolean createOrder(Order order, String currentUser) {
  log.info("【    】orderNo={}", order.getOrderNo());
  // db insert order
  return true;
 }
이 방법 은 수 동 으로 지정 되 며,방법 적 매개 변수 에 operator 인자 가 있 거나,SpEL 을 통 해 정적 방법 으로 현재 사용 자 를 가 져 올 수 있 습 니 다.
두 번 째:기본 구현 클래스 를 통 해 작업 자 를 자동 으로 가 져 옵 니 다.대부분의 웹 응용 프로그램 에서 현재 사용 자 는 하나의 스 레 드 컨 텍스트 에 저장 되 어 있 기 때문에 모든 주석 에 operator 를 추가 하여 작업 자 를 가 져 오 는 것 이 중복 되 어 있 기 때문에 확장 인 터 페 이 스 를 제공 하여 작업 자 를 가 져 옵 니 다.
프레임 워 크 는 확장 인 터 페 이 스 를 제공 합 니 다.프레임 워 크 를 사용 하 는 업 무 는 implements 라 는 인 터 페 이 스 를 사용 하여 현재 사용자 의 논 리 를 가 져 올 수 있 습 니 다.
Springboot 를 사용 하 는 것 은 IOperatorGetService 인 터 페 이 스 를 실현 한 다음 에 이 서 비 스 를 하나의 예 로 Spring 의 컨 텍스트 에 넣 어야 합 니 다.Spring Mvc 를 사용 하려 면 이 bean 들 을 직접 조립 해 야 합 니 다.

@Configuration
public class LogRecordConfiguration {
 @Bean
 public IOperatorGetService operatorGetService() {
  return () -> Optional.of(OrgUserUtils.getCurrentUser())
    .map(a -> new OperatorDO(a.getMisId()))
    .orElseThrow(() -> new IllegalArgumentException("user is null"));
 }
}
//      :
@Service
public class DefaultOperatorGetServiceImpl implements IOperatorGetService {
 @Override
 public OperatorDO getUser() {
  OperatorDO operatorDO = new OperatorDO();
  operatorDO.setOperatorId("SYSTEM");
  return operatorDO;
 }
}
6.로그 문안 조정
업데이트 등 방법 에 대해 방법의 매개 변 수 는 대부분 주문 ID 나 제품 ID 등 입 니 다.
예 를 들 어 다음 과 같은 예:로그 기록 의 success 내용 은"주문{\#orderId}을 업 데 이 트 했 습 니 다.업데이트 내용 은..."입 니 다.운영 이나 제품 에 있어 서 이해 하기 어렵 기 때문에 사용자 정의 함수 기능 을 도입 하 였 습 니 다.
사용 방법 은 원래 변수의 두 개의 큰 괄호 사이 에 함수 이름 을 추가 하 는 것 입 니 다.예 를 들 어"{ORDER{\#orderId}"그 중에서 ORDER 는 함수 이름 입 니 다.하나의 함수 이름 만 으로 는 부족 합 니 다.이 함수 의 정의 와 실현 을 추가 해 야 합 니 다.아래 의 예 를 볼 수 있다
사용자 정의 함 수 는 프레임 안의 IParse Function 인 터 페 이 스 를 실현 해 야 합 니 다.두 가지 방법 이 필요 합 니 다.
functionName()방법 은 주석 위의 함수 이름 을 되 돌려 줍 니 다.
apply()함수 인 자 는"{ORDER{\#orderId}}"에서 SpEL 이 해석 한\#orderId 의 값 입 니 다.여 기 는 숫자 1223110 입 니 다.다음은 실 현 된 클래스 에서 ID 를 읽 을 수 있 는 문자열 로 변환 하면 됩 니 다.
일반적으로 조사 문 제 를 편리 하 게 하기 위해 서 는 이름과 ID 를 모두 보 여 줘 야 한다.예 를 들 어'주문 이름(ID)'의 형식 이다.
여기에 문제 가 있 습 니 다.사용자 정의 함 수 를 추가 한 후에 프레임 워 크 를 어떻게 호출 할 수 있 습 니까?
답:Spring boot 애플 리 케 이 션 은 간단 합 니 다.Spring 의 컨 텍스트 에 만 노출 시 키 면 됩 니 다.Spring 의@Component 또는@Service 를 추가 하면 편리 합 니 다.😄。Spring mvc 응용 프로그램 은 스스로 Bean 을 조립 해 야 한다.

 //          
 @LogRecordAnnotation(success = "     {{#orderId}},     ....",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}",
   detail = "{{#order.toString()}}")
 public boolean update(Long orderId, Order order) {
  return false;
 }
 //        ,     {{#orderId}}          functionName
 @LogRecordAnnotation(success = "     ORDER{#orderId}},     ...",
   prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}",
   detail = "{{#order.toString()}}")
 public boolean update(Long orderId, Order order) {
  return false;
 }
 //           
 @Component
 public class OrderParseFunction implements IParseFunction {
  @Resource
  @Lazy //                Lazy,         
  private OrderQueryService orderQueryService;
  
  @Override 
  public String functionName() {
   //       ORDER
   return "ORDER";
  }
 
  @Override
  //    value     Order  JSON       ,                  
  public String apply(String value) {
   if(StringUtils.isEmpty(value)){
    return value;
   }
   Order order = orderQueryService.queryOrder(Long.parseLong(value));
   //             ,   ID      
   return order.getProductName().concat("(").concat(value).concat(")");
  }
 }
7.로그 문안 조정 은 SpEL 세 가지 표현 식 을 사용 합 니 다.

 @LogRecordAnnotation(prefix = LogRecordTypeConstant.CUSTOM_ATTRIBUTE, bizNo = "{{#businessLineId}}",
   success = "{{#disable ? '  ' : '  '}}      {ATTRIBUTE{#attributeId}}")
 public CustomAttributeVO disableAttribute(Long businessLineId, Long attributeId, boolean disable) {
  return xxx;
 }
프레임 의 확장 점
Operator GetServiceImpl 을 다시 쓰 고 컨 텍스트 를 통 해 사용자 의 확장 을 가 져 옵 니 다.예 는 다음 과 같 습 니 다.

@Service
public class DefaultOperatorGetServiceImpl implements IOperatorGetService {
 @Override
 public Operator getUser() {
   return Optional.ofNullable(UserUtils.getUser())
      .map(a -> new Operator(a.getName(), a.getLogin()))
      .orElseThrow(()->new IllegalArgumentException("user is null"));
  
 }
}
ILogRecordService 저장/조회 로그 의 예 를 들 어 사용 자 는 데이터 양 에 따라 데이터베이스/또는 ES 에 저장 할 수 있 습 니 다.스스로 저장 과 삭 제 를 하 시 면 됩 니 다.
또한 조회 의 인터페이스 만 실현 할 수 있다.왜냐하면 업무 의 저장 에 저장 되 어 있 기 때문에 조회 업 무 는 스스로 실현 할 수 있 고 ILogRecordService 라 는 인 터 페 이 스 를 가지 않 는 다.왜냐하면 제품 매니저 는 기괴 한 조회 수 요 를 제기 할 수 있 기 때문이다.

@Service
public class DbLogRecordServiceImpl implements ILogRecordService {
 @Resource
 private LogRecordMapper logRecordMapper;
 @Override
 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void record(LogRecord logRecord) {
  log.info("【logRecord】log={}", logRecord);
  LogRecordPO logRecordPO = LogRecordPO.toPo(logRecord);
  logRecordMapper.insert(logRecordPO);
 }
 @Override
 public List<LogRecord> queryLog(String bizKey, Collection<String> types) {
  return Lists.newArrayList();
 }
 @Override
 public PageDO<LogRecord> queryLogByBizNo(String bizNo, Collection<String> types, PageRequestDO pageRequestDO) {
  return logRecordMapper.selectByBizNoAndCategory(bizNo, types, pageRequestDO);
 }
}
IParseFunction 사용자 정의 변환 함수 인터페이스,IParseFunction 로그 레코드 주석 에 사용 할 함수 확장 실현
예:

@Component
public class UserParseFunction implements IParseFunction {
 private final Splitter splitter = Splitter.on(",").trimResults();
 @Resource
 @Lazy
 private UserQueryService userQueryService;
 @Override
 public String functionName() {
  return "USER";
 }
 @Override
 // 11,12    11(  ),12(  )
 public String apply(String value) {
  if (StringUtils.isEmpty(value)) {
   return value;
  }
  List<String> userIds = Lists.newArrayList(splitter.split(value));
  List<User> misDOList = userQueryService.getUserList(userIds);
  Map<String, User> userMap = StreamUtil.extractMap(misDOList, User::getId);
  StringBuilder stringBuilder = new StringBuilder();
  for (String userId : userIds) {
   stringBuilder.append(userId);
   if (userMap.get(userId) != null) {
    stringBuilder.append("(").append(userMap.get(userId).getUsername()).append(")");
   }
   stringBuilder.append(",");
  }
  return stringBuilder.toString().replaceAll(",$", "");
 }
}
변수 관련
LogRecordAnnotation 에서 사용 할 수 있 는 변 수 는 인자 가 나 와 도 반환 값 을 사용 할 수 있 습 니 다\#ret 변수 및 이상 한 오류 정보\#errorMsg,SpEL 의 T 방식 으로 정적 방법 을 호출 할 수 있 습 니 다.
확장 을 기다리다
Log 의 Context 를 실현 하면 방법 매개 변수 에 없 는 변 수 를 해결 할 수 있 지만 사용 하고 싶 은 문 제 를 해결 할 수 있 습 니 다.초보적인 아 이 디 어 는 방법 에서 add 변수의 형식 으로 실현 할 수 있 고 곧 실현 할 수 있 습 니 다.😄
주의 점:
전체 로그 차단 은 방법 이 실 행 된 후에 기록 되 기 때문에 방법 내부 에서 방법 매개 변 수 를 수정 한 후에 LogRecordAnnotation 의 주석 에 있 는 SpEL 이 변수 에 대한 추출 값 은 수 정 된 값 입 니 다~
소스 코드
https://github.com/mouzt/mzt-biz-log
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.만약 잘못 이 있 거나 완전히 고려 하지 않 은 부분 이 있다 면 아낌없이 가르침 을 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기