收集了之前的一些模板方法模式的使用案例,核心就是抽象类

/**
@author mifuRD
@date 2023/06/05
@desc 统一定义钉钉事件处理,需处理具体事件,继承该类重写定义要处理的事件类型types后,重写对应方法
 */
abstract class AbstractDingtalkEventListener: ApplicationListener<DingtalkEvent> {

    private val log = LoggerFactory.getLogger(this::class.java)

    var types: Set<DingEventTypeEnum>? = null

    private val eventLockMap = ConcurrentHashMap<String, String>()

    final override fun onApplicationEvent(event: DingtalkEvent) {
        onEvent(event)
    }

    private fun onEvent(event: DingtalkEvent) {
        val eventType = DingEventTypeEnum.enumOf(event.eventType)
        if(types == null || types!!.contains(eventType)) {
            val eventId = event.eventId
           synchronized(getLockByEventId(eventId)) {
               try {
                   // 判断事件是否处理
                   when (eventType) {
                       DingEventTypeEnum.USER_ADD_ORG -> addUser(event)
                       DingEventTypeEnum.USER_MODIFY_ORG -> modifyUser(event)
                       DingEventTypeEnum.USER_LEAVE_ORG -> leaveUser(event)
                       DingEventTypeEnum.USER_ACTIVE_ORG -> activeUser(event)
                       DingEventTypeEnum.ORG_ADMIN_ADD -> addAdmin(event)
                       DingEventTypeEnum.ORG_ADMIN_REMOVE -> removeAdmin(event)
                       DingEventTypeEnum.ORG_DEPT_CREATE -> addDept(event)
                       DingEventTypeEnum.ORG_DEPT_MODIFY -> modifyDept(event)
                       DingEventTypeEnum.ORG_DEPT_REMOVE -> removeDept(event)
                       DingEventTypeEnum.ORG_REMOVE -> removeOrg(event)
                       DingEventTypeEnum.ORG_CHANGE -> modifyOrg(event)
                       DingEventTypeEnum.LABEL_USER_CHANGE -> changeUserLabel(event)
                       DingEventTypeEnum.LABEL_CONF_ADD -> addLabel(event)
                       DingEventTypeEnum.LABEL_CONF_DEL -> deleteLabel(event)
                       DingEventTypeEnum.LABEL_CONF_MODIFY -> modifyLabel(event)
                       DingEventTypeEnum.ATTENDANCE_CHECK_RECORD -> attendanceCheck(event)
                       DingEventTypeEnum.ATTENDANCE_SCHEDULE_CHANGE -> attendanceChangeSchedule(event)
                       DingEventTypeEnum.ATTENDANCE_OVERTIME_DURATION -> attendanceOvertime(event)
                       DingEventTypeEnum.CHECK_IN -> checkIn(event)

                       DingEventTypeEnum.BPMS_INSTANCE_CHANGE -> processInstanceChange(event)
                       DingEventTypeEnum.BPMS_TASK_CHANGE -> processTaskChange(event)
                       else -> {
                           log.warn("暂不支持的钉钉事件: {},不处理", event.eventType)
                       }
                   }
               } finally {
                   unLockByEventId(eventId)
               }
           }
        }
    }

    open fun processInstanceChange(event: DingtalkEvent) {
        log.debug("处理钉钉审批实例开始、结束事件")
    }

    open fun processTaskChange(event: DingtalkEvent) {
        log.debug("处理钉钉审批任务开始、结束、转交事件")
    }

    open fun checkIn(event: DingtalkEvent) {
        log.debug("处理钉钉用户签到事件")
    }

    open fun attendanceOvertime(event: DingtalkEvent) {
        log.debug("处理钉钉员工加班事件")
    }

    open fun attendanceChangeSchedule(event: DingtalkEvent) {
        log.debug("处理钉钉员工排班变更事件")
    }

    open fun attendanceCheck(event: DingtalkEvent) {
        log.debug("处理钉钉员工打卡事件事件")
    }

    open fun modifyLabel(event: DingtalkEvent) {
        log.debug("处理钉钉修改角色或者角色组事件")
    }

    open fun deleteLabel(event: DingtalkEvent) {
        log.debug("处理钉钉删除角色或者角色组事件")
    }

    open fun addLabel(event: DingtalkEvent) {
        log.debug("处理钉钉增加角色或者角色组事件")
    }

    open fun changeUserLabel(event: DingtalkEvent) {
        log.debug("处理钉钉员工角色信息发生变更事件")
    }

    open fun modifyOrg(event: DingtalkEvent) {
        log.debug("处理钉钉企业信息发生变更事件")
    }

    open fun removeOrg(event: DingtalkEvent) {
        log.debug("处理钉钉企业被解散事件")
    }

    open fun removeDept(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录企业部门删除事件")
    }

    open fun modifyDept(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录企业部门修改事件")
    }

    open fun addDept(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录企业部门创建事件")
    }

    open fun removeAdmin(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录用户被取消设置管理员事件")
    }

    open fun addAdmin(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录用户被设为管理员事件")
    }

    open fun activeUser(event: DingtalkEvent) {
        log.debug("处理钉钉加入企业后用户事件")
    }

    open fun leaveUser(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录用户离职事件")
    }

    open fun modifyUser(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录用户更改事件")
    }

    open fun addUser(event: DingtalkEvent) {
        log.debug("处理钉钉通讯录用户增加事件")
    }


    private fun getLockByEventId(eventId: String): Any {
        eventLockMap.putIfAbsent(eventId, eventId)
        return eventLockMap[eventId]!!
    }

    private fun unLockByEventId(eventId: String) {
        eventLockMap.remove(eventId)
    }



}
/**
@author mifuRD
@date 2024/3/4
@desc 用于获取客户服务器的基本信息,如:IP、Mac地址、CPU序列号、主板序列号等
 */
abstract class AbstractServerInfo {

    private val log = LoggerFactory.getLogger(this::class.java)

    /**
     * 组装需要额外校验的License参数
     * @return demo.LicenseCheckModel
     */
    fun getServerInfo(): LicenseCheckModel? {
        var result: LicenseCheckModel? = null
        try {
            result = LicenseCheckModel().apply {
                ipAddress = getIpAddress()
                macAddress = getMacAddress()
                cpuSerial = getCPUSerial()
                mainBoardSerial = getMainBoardSerial()
            }

        } catch (e: Exception) {
            log.error("获取服务器硬件信息失败", e)
        }
        return result
    }

    /**
     * 获取IP地址
     *
     */
    @Throws(Exception::class)
    abstract fun getIpAddress(): List<String>

    /**
     * 获取Mac地址
     */
    @Throws(Exception::class)
    abstract fun getMacAddress(): List<String>

    /**
     * 获取CPU序列号
     */
    @Throws(Exception::class)
    abstract fun getCPUSerial(): String

    /**
     * 获取主板序列号
     */
    @Throws(Exception::class)
    abstract fun getMainBoardSerial(): String

    /**
     * 获取当前服务器所有符合条件的InetAddress
     */
    @Throws(Exception::class)
    open fun getLocalAllInetAddress(): List<InetAddress> {
        val result = ArrayList<InetAddress>()
        // 遍历所有的网络接口
        val networkInterfaces = NetworkInterface.getNetworkInterfaces()
        while (networkInterfaces.hasMoreElements()) {
            val iface = networkInterfaces.nextElement() as NetworkInterface
            // 在所有的接口下再遍历IP
            val inetAddresses = iface.inetAddresses
            while (inetAddresses.hasMoreElements()) {
                val inetAddr = inetAddresses.nextElement() as InetAddress
                //排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
                if (!inetAddr.isLoopbackAddress /*&& !inetAddr.isSiteLocalAddress()*/
                    && !inetAddr.isLinkLocalAddress && !inetAddr.isMulticastAddress
                ) {
                    result.add(inetAddr)
                }
            }
        }
        return result
    }

    /**
     * 获取某个网络接口的Mac地址
     */
    protected fun getMacByInetAddress(inetAddr: InetAddress): String? {
        try {
            val mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress()
            val stringBuffer = StringBuffer()
            for (i in mac.indices) {
                if (i != 0) {
                    stringBuffer.append("-")
                }

                //将十六进制byte转化为字符串
                val temp = Integer.toHexString(mac[i].toInt() and 0xff)
                if (temp.length == 1) {
                    stringBuffer.append("0$temp")
                } else {
                    stringBuffer.append(temp)
                }
            }
            return stringBuffer.toString().uppercase(Locale.getDefault())
        } catch (e: SocketException) {
            log.error("获取某个网络接口的Mac地址异常", e)
        }
        return null
    }

}


/**
@author mifuRD
@date 2024/3/4
@desc 获取Linux服务器信息
 */
class LinuxServerInfo : AbstractServerInfo() {

    override fun getIpAddress(): List<String> {
        val inetAddresses = getLocalAllInetAddress()
        return if (inetAddresses.isNotEmpty()) {
             inetAddresses.mapNotNull { it.hostAddress }.distinct().map { it.lowercase() }
        } else emptyList()
    }

    override fun getMacAddress(): List<String> {
        //1. 获取所有网络接口
        val inetAddresses = getLocalAllInetAddress()
        return if (inetAddresses.isNotEmpty()) {
            //2. 获取所有网络接口的Mac地址
            inetAddresses.mapNotNull { getMacByInetAddress(it) }.distinct()
        } else emptyList()
    }

    override fun getCPUSerial(): String {
        //使用dmidecode命令获取CPU序列号
        val shell = arrayOf("/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1")
        val process = Runtime.getRuntime().exec(shell)
        process.outputStream.close()
        val reader = BufferedReader(InputStreamReader(process.inputStream))
        if(reader.readLine() == null) return ""
        val line = reader.readLine().trim { it <= ' ' }
        reader.close()
        return line
    }

    override fun getMainBoardSerial(): String {
        //使用dmidecode命令获取主板序列号
        val shell = arrayOf("/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1")
        val process = Runtime.getRuntime().exec(shell)
        process.outputStream.close()
        val reader = BufferedReader(InputStreamReader(process.inputStream))
        if(reader.readLine() == null) return ""
        val line = reader.readLine().trim { it <= ' ' }
        reader.close()
        return line
    }
}

/**
@author mifuRD
@date 2024/3/4
@desc 获取Windows服务器信息
 */
class WindowsServerInfo : AbstractServerInfo() {

    override fun getIpAddress(): List<String> {
        val inetAddresses = getLocalAllInetAddress()
        return if (inetAddresses.isNotEmpty()) {
             inetAddresses.mapNotNull { it.hostAddress }.distinct().map { it.lowercase() }
        } else emptyList()
    }

    override fun getMacAddress(): List<String> {
        //1. 获取所有网络接口
        val inetAddresses = getLocalAllInetAddress()
        return if (inetAddresses.isNotEmpty()) {
            //2. 获取所有网络接口的Mac地址
            inetAddresses.mapNotNull { getMacByInetAddress(it) }.distinct()
        } else emptyList()
    }

    override fun getCPUSerial(): String {
        //使用WMIC获取CPU序列号
        var serialNumber = ""
        val process = Runtime.getRuntime().exec("wmic cpu get processorid")
        process.outputStream.close()
        val scanner = Scanner(process.inputStream)
        // 输出位两行获取第二行的值
        //ProcessorId
        //178BFBFF00A50F00
        if (scanner.hasNext()) {
            scanner.next()
            serialNumber = scanner.next().trim()
        }
        scanner.close()
        return serialNumber
    }

    override fun getMainBoardSerial(): String {
        //序列号
        var serialNumber = ""
        //使用WMIC获取主板序列号
        val process = Runtime.getRuntime().exec("wmic baseboard get serialnumber")
        process.outputStream.close()
        val scanner = Scanner(process.inputStream)
        // 输出位两行获取第二行的值
        //SerialNumber
        //MMG5S00000977189P0054
        if (scanner.hasNext()) {
            scanner.next()
            serialNumber = scanner.next().trim()
        }
        scanner.close()
        return serialNumber
    }
}

/**
@author mifuRD
@date 2024/1/4
@desc 资产扫描器
 */
interface AssetScanner {

    /**
     * 执行扫描任务
     */
    fun scan(scanParam : ScannerParam)

    /**
     * 获取扫描状态和进度
     */
    fun getProgress(scanId: String) : ScanProgress

    /**
     * 进度缓存key
     */
    fun getProgressKey(scanId: String) = SystemConstants.getRedisKey("internal.asset.scan:$scanId")

    /**
     * 更新扫描进度
     */
    fun updateScanProgress(progress: ScanProgress) {
        RedisUtils.set(getProgressKey(progress.scanId), progress)
        SpringUtil.getBean(IFwTaskExecRecordService::class.java).updateStatus(progress.scanId, progress.status, progress.tipMsg)
    }

    fun stopExec(scanId: String) : Boolean

}

// 对应不同的执行器扫描逻辑
public abstract class AbstractPayService implements PayService {

    @Override
    public void pay(PayRequest payRequest) {
      	//前置检查
        validateRequest(payRequest);
      	//支付核心逻辑
        doPay(payRequest);
      	//后置处理
        postPay(payRequest);
    }

    public abstract void doPay(PayRequest payRequest);

    private void postPay(PayRequest payRequest) {
        //支付成功的后置处理
    }

    public void validateRequest(PayRequest payRequest) {
        //参数检查
    }
}