收集了之前的一些模板方法模式的使用案例,核心就是抽象类
/**
@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) {
//参数检查
}
}