1. 程式人生 > 其它 >SpringBoot釋出事件,監聽事件

SpringBoot釋出事件,監聽事件

SpringBoot釋出事件,監聽事件

業務型別:像傳送郵箱,記錄登入日誌這種,程式可以不等待它們完成之後再返回響應。

  1. ApplicationEventPublisher 事件釋出介面
  2. @Async:非同步註解 可以加上執行緒池的名字
  3. @EventListener:監聽事件註解,加上此註解的方法才能監聽

這裡以記錄日誌為例

1.定義日誌實體類

/**
 * 賬戶登入日誌實體類
 *
 * @author 
 * @date 
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AccountLoginLog implements Serializable {
    private Long id;
    /**
     * 賬號id
     */
    private Long accountId;
    /**
     * 賬號名稱
     */
    private String accountName;
    /**
     * 手機號
     */
    private String accountMobile;
    /**
     * 單位名稱
     */
    private String departmentName;
    /**
     * ip地址
     */
    private String ip;
    /**
     * ip地址所在區域省
     */
    private String ipProvince;
    /**
     * ip地址所在區域市
     */
    private String ipCity;
    /**
     * 1登入/2登出
     */
    private Integer type;
    /**
     * 成功/失敗
     */
    private Boolean success;
    /**
     * 說明
     */
    private String memo;
    /**
     * 建立時間
     */
    private Date createdAt;
    /**
     * 修改時間
     */
    private Date updatedAt;


    /**
     * 登入日誌型別列舉
     *
     * @author 
     * @date 
     */
    @Getter
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public enum Type {
        /**
         * 登入
         */
        LOGIN(1, "登入"),
        /**
         * 退出
         */
        LOGOUT(2, "登出");


        private Integer code;
        private String value;

        public static String getName(int code) {
            Optional<Type> find = Arrays.stream(values()).filter(c -> Objects.equals(c.getCode(), code)).findFirst();
            return find.map(Type::getValue).orElse(null);
        }


        public static boolean isCodeLegal(int code) {
            Optional<?> find = Arrays.stream(values()).filter(c -> Objects.equals(c.getCode(), code)).findFirst();
            return find.isPresent();
        }
    }
}

2.將實體類再次進行封裝一層

沒有很複雜的邏輯可以不用

/**
 * 登入日誌記錄
 *
 * @author 
 * @date 
 */
@Data
@Builder
public class LoginLogEvent implements Serializable {

    /**
     * 登入日誌
     */
    private AccountLoginLog accountLoginLog;

}

3.定義事件釋出器

/**
 * 登入日誌記錄事件釋出
 *
 * @author 
 * @date 
 */
@Component
public class LoginLogEventPublisher {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    private DepartmentManager departmentManager;

    /**
     * 釋出登入成功日誌
     *
     * @param account  當前登入使用者
     * @param ipRegion IP
     * @param memo     說明
     */
    public void publishLoginSuccessLog(Account account, IPRegion ipRegion, String memo) {
        publishEvent(account.getId(), account.getName(), account.getMobile(),
                getDepartmentName(account.getDepartmentId()), ipRegion, AccountLoginLog.Type.LOGIN.getCode(), true, memo);
    }

    /**
     * 釋出登入失敗日誌
     *
     * @param account  當前登入使用者
     * @param ipRegion IP
     * @param memo     說明
     */
    public void publishLoginFailLog(Account account, IPRegion ipRegion, String memo) {
        publishEvent(account.getId(), account.getName(), account.getMobile(),
                getDepartmentName(account.getDepartmentId()), ipRegion, AccountLoginLog.Type.LOGIN.getCode(), false, memo);
    }

    /**
     * 釋出登出(退出登入)日誌
     *
     * @param account  登入使用者
     * @param ipRegion IP
     * @param memo     說明
     */
    public void publishLogout(Account account, IPRegion ipRegion, String memo) {
        publishEvent(account.getId(), account.getName(), account.getMobile(),
                getDepartmentName(account.getDepartmentId()), ipRegion, AccountLoginLog.Type.LOGOUT.getCode(), true, memo);
    }

    /**
     * 釋出登入事件
     *
     * @param accountId      使用者ID
     * @param accountName    使用者姓名
     * @param accountMobile  手機號
     * @param departmentName 單位部門
     * @param ipRegion       IP
     * @param type           型別
     * @param success        成功失敗
     * @param memo           說明
     */
    private void publishEvent(Long accountId, String accountName, String accountMobile,
                              String departmentName, IPRegion ipRegion,
                              int type, boolean success, String memo) {
        LoginLogEvent loginLogEvent = LoginLogEvent.builder()
                .accountLoginLog(AccountLoginLog.builder()
                        .accountId(accountId).accountName(accountName)
                        .accountMobile(accountMobile).departmentName(departmentName)
                        .ip(ipRegion.getIp()).ipProvince(ipRegion.getProvince()).ipCity(ipRegion.getCity())
                        .type(type).success(success).memo(memo)
                        .build())
                .build();
        applicationEventPublisher.publishEvent(loginLogEvent);
    }

    /**
     * 部門名稱
     */
    private String getDepartmentName(Long departmentId) {
        if (departmentId != null) {
            Department department = departmentManager.findOne(departmentId);
            return department != null ? department.getName() : null;
        } else {
            return null;
        }
    }
}

4.定義事件處理器

/**
 * 操作日誌記錄
 *
 * @author 
 * @date 
 */
@Component
public class LoginLogEventProcessor {
    @Autowired
    private AccountLoginLogManager accountLoginLogManager;

    @Async
    @EventListener
    public void handleLoginLogEvent(LoginLogEvent loginLogEvent) {
        //記錄日誌
        accountLoginLogManager.log(loginLogEvent.getAccountLoginLog());
    }

}

accountLoginLogManager為service提供者,提供處理日誌方法,這裡呼叫log方法將登入日誌儲存在mysql中以及es中,具體業務程式碼不再展示。