目录[-]
规则执行器接口
规则引擎接口
规则集对象
规则抽象类
MVEL方式的规则及其执行器
Mvel规则
Mvel规则执行器
Mvel上下文
规则引擎实现类
示例
定义规则
编写TestCase
总结
规则引擎适合于做业务规则频繁变化的场景,我们的业务在应用过程中,也经常要处理大量的业务规则,当然,也希望能有一套规则引擎来支撑,这样是再好不过的。
对一些常用的商业规则引擎做一下了解,感觉非常不错,但是太贵了。看一些开源的引擎吧,也不错,但是感觉相对于我们自己这么简单的需求,太复杂了。
于是就想着自己做个,试试看能不能解决了自己的这些简单的业务规则频繁变化的业务场景,嗯嗯,脑子里大概过了一下电影,感觉路是通的,主要有如下业务需求:
业务规则执行器需要支持多种,也应该支持业务人员自行扩展,原因是我自己设计的业务规则再完美,也不可能完美的适应所有人的胃口,所以这个默认可以有支持的,但是一定是可以扩展的
业务规则要支持优先级,也就是说有的业务规则先执行,有的业务规则后执行
业务规则允许排他规则,也就是说只要执行到排他规则,就可以马上结束
业务规则可以允许重复执行,这样才可以方便的进行循环处理
在规则引擎中,可以方便的使用Spring中的业务对象
于是就可以开始设计了:
规则执行器接口
由于业务规则执行器需要支持扩展,当然需要设计一个接口了:
/** * 规则执行器,可以有多种实现 */ public interface RuleExecutor<T extends Rule> { /** * 返回执行器类型 * * @return */ String getType(); /** * 执行规则,并把结果放到上下文上 * * @param context * @return 返回条件是否成立 */ boolean execute(Context context, T rule); }
一共就两方法,getType用来返回规则执行器的类型,以确定它是解决哪种类型的规则的。
execute方法用来执行规则,执行的结果是一个布尔值,表示此条规则是否有执行。
规则引擎接口
接下来就是设计规则引擎的接口了:
public interface RuleEngine { /** * 对指定上下文执行指定类型的规则 * * @param context * @param ruleSetName */ void execute(Context context, String ruleSetName); /** * 添加一组规则 * * @param ruleSet */ void addRules(RuleSet ruleSet); /** * 删除一组规则 * * @param ruleSet */ void removeRules(RuleSet ruleSet); /** * 添加规则执行器列表 * * @param ruleExecutors */ void addRuleExecutors(List<RuleExecutor> ruleExecutors); /** * 添加一个规则执行器 * * @param ruleExecutor */ void addRuleExecutor(RuleExecutor ruleExecutor); /** * 删除规则执行器列表 * * @param ruleExecutors */ void removeRuleExecutors(List<RuleExecutor> ruleExecutors); /** * 删除一个规则执行器 * * @param ruleExecutor */ void removeRuleExecutor(RuleExecutor ruleExecutor); /** * 设置一批规则执行器 * @param ruleExecutors */ void setRuleExecutors(List<RuleExecutor> ruleExecutors); }
如上面的代码一样,还是非常简单的。
execute用来执行一个规则集,其它的方法就是对规则集和规则执行器的管理,只要看一遍就一清二楚了。
规则集对象
@XStreamAlias("rule-set") public class RuleSet { /** * 同种名称的规则集会自动合并 */ @XStreamAsAttribute private String name; @XStreamImplicit private List<Rule> rules; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Rule> getRules() { if(rules==null){ rules = new ArrayList<Rule>(); } return rules; } public void setRules(List<Rule> rules) { this.rules = rules; } }
规则集就两属性,一个属性是规则集的名称,另外一个属性就是一组规则。规则集的名称用来表示一组相关的业务规则。
规则抽象类
根据上面的业务需求,抽象类Rule的结构如下:
它里面只有基本的几个属性:优先级,标识,是否排他,是否允许重复,描述,标题,类型,有效性。
说好的业务规则呢,怎么描述?
由于不同的规则执行器,它可以支持的规则也不一样,因此这里的规则抽象类只有基本的一些属性,怎么样描述规则由其子类决定。
MVEL方式的规则及其执行器
Mvel规则
/** * 采用MVEL表达式作为条件实现 * @author yancheng11334 * */ @XStreamAlias("mvel-rule") public class MvelRule extends Rule{ //匹配条件 private String condition; //后续操作 private String action; public String getCondition() { return condition; } public void setCondition(String condition) { this.condition = condition; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getType(){ return "mvel"; } public String toString() { return "MvelRule [condition=" + condition + ", action=" + action + ", type=" + getType() + ", id=" + getId() + ", priority="+ getPriority() +", multipleTimes="+isMultipleTimes()+",exclusive="+isExclusive()+"]"; } /** * 验证mvel规则的合法性 */ public boolean isVaild() { if(StringUtil.isEmpty(getCondition())){ throw new RuntimeException(String.format("规则[%s]的匹配条件为空", getId())); } if(StringUtil.isEmpty(getAction())){ throw new RuntimeException(String.format("规则[%s]的后续操作为空", getId())); } return true; } }
上面表示,这个规则的类型都是mvel,这个规则包含了两个属性:condition和action,condition表示条件,只有条件执行结果为真的时候,才执行action中的处理。
Mvel规则执行器
public class MvelRuleExecutor implements RuleExecutor<MvelRule>{ private EL el; public EL getEl() { return el; } public void setEl(EL el) { this.el = el; } public String getType() { return "mvel"; } public boolean execute(Context context, MvelRule rule) { try{ if(executeCondition(rule.getCondition(),context)){ executeAction(rule.getAction(),context); return true; }else{ return false; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new RuntimeException("Mvel规则引擎执行器发生异常:",e); } } /** * 判断条件是否匹配 * @param condition * @param context * @return */ protected boolean executeCondition(String condition,Context context){ try{ MvelContext mvelContext=null; if(context instanceof MvelContext){ mvelContext=(MvelContext) context; }else{ mvelContext=new MvelContext(context); } return (Boolean)el.execute(condition, mvelContext); }catch(Exception e){ throw new RuntimeException(String.format("条件[%s]匹配发生异常:", condition),e); } } /** * 执行条件匹配后的操作 * @param action * @param context */ protected void executeAction(String action,Context context) { try { MvelContext mvelContext = null; if (context instanceof MvelContext) { mvelContext = (MvelContext) context; } else { mvelContext = new MvelContext(context); } el.execute(action, mvelContext); } catch (Exception e) { throw new RuntimeException(String.format("后续操作[%s]执行发生异常:", action), e); } } }
execute方法的意思是:如果执行条件表达式且返回真,那么就执行action中的处理,并返回true,否则就返回false。
呵呵,这个逻辑也太简单了。对,tiny框架的一大特点就是用非常简单的逻辑来实现相对复杂的处理。
Mvel上下文
前面讲到,要方便的在表达式中调用Spring中托管的对象,这个的实现就要从上下文上作文章了:
public <T> T get(String name) { if(context.exist(name)){ return (T)context.get(name); }else{ //必须保存到上下文,否则每次返回不一定是同一个对象(scope可能是属性) T t = (T)beanContainer.getBean(name); context.put(name, t); return t; } }
主要的逻辑在上面,也就是说:如果上下文中有对像,那么就从上下文中取;如果没有,那么就从Spring容器中取。呵呵,这么高大上的功能,实现起来也这么简单。
规则引擎实现类
到上面为止,相关的准备工作都就绪了,规则引擎的实现类也可以现身了。其实这个类不贴吧,看文章的同学们一定说我藏着掖着,但是贴出来吧,真的没有啥技术含量:
public class RuleEngineDefault implements RuleEngine { private Map<String, List<Rule>> ruleSetMap = new ConcurrentHashMap<String, List<Rule>>(); private List<RuleExecutor> ruleExecutors = null; private Map<String, RuleExecutor> ruleExecutorMap = new ConcurrentHashMap<String, RuleExecutor>(); protected static Logger logger = LoggerFactory .getLogger(RuleEngineDefault.class); public void execute(Context context, String ruleSetName) { List<Rule> ruleSet = ruleSetMap.get(ruleSetName); if (ruleSet != null) { Vector<Rule> newSet = new Vector<Rule>(ruleSet); processRuleSet(context, newSet); } } private void processRuleSet(Context context, Vector<Rule> newSet) { //如果没有后续规则,则退出 if (newSet.size() == 0) { return; } Rule rule = newSet.get(0); RuleExecutor ruleExecutor = ruleExecutorMap.get(rule.getType()); if (ruleExecutor != null) { boolean executed = ruleExecutor.execute(context, rule); if (executed) { //如果 if (rule.isExclusive()) { //如果条件成立,则是独占条件,则直接返回 return; } else if (!rule.isMultipleTimes()) { //如果不是可重复执行的规则,则删除之 newSet.remove(0); } } else { //如果不匹配,则删除之 newSet.remove(0); } } else { throw new RuntimeException("找不到对应" + rule.getType() + "的执行器"); } processRuleSet(context, newSet); } public void addRules(RuleSet ruleSet) { List<Rule> rules = ruleSetMap.get(ruleSet.getName()); if (rules == null) { rules = new Vector<Rule>(); ruleSetMap.put(ruleSet.getName(), rules); } //检查规则 for(Rule rule:ruleSet.getRules()){ if(rule.isVaild()){ rules.add(rule); }else{ logger.logMessage(LogLevel.ERROR, String.format("规则[%s]检查无效.", rule.getId())); } rule.isVaild(); } Collections.sort(rules); } public void removeRules(RuleSet ruleSet) { List<Rule> rules = ruleSetMap.get(ruleSet.getName()); if (rules != null) { rules.removeAll(ruleSet.getRules()); } } public void setRuleExecutors(List<RuleExecutor> ruleExecutors) { this.ruleExecutors = ruleExecutors; for (RuleExecutor ruleExecutor : ruleExecutors) { ruleExecutorMap.put(ruleExecutor.getType(), ruleExecutor); } } public void addRuleExecutor(RuleExecutor ruleExecutor) { if (ruleExecutors == null) { ruleExecutors = new ArrayList<RuleExecutor>(); } ruleExecutors.add(ruleExecutor); ruleExecutorMap.put(ruleExecutor.getType(), ruleExecutor); } public void addRuleExecutors(List<RuleExecutor> ruleExecutors) { if(ruleExecutors!=null){ for(RuleExecutor ruleExecutor:ruleExecutors){ addRuleExecutor(ruleExecutor); } } } public void removeRuleExecutors(List<RuleExecutor> ruleExecutors) { if(ruleExecutors!=null){ for(RuleExecutor ruleExecutor:ruleExecutors){ removeRuleExecutor(ruleExecutor); } } } public void removeRuleExecutor(RuleExecutor ruleExecutor) { if (ruleExecutors == null) { ruleExecutors = new ArrayList<RuleExecutor>(); } ruleExecutors.remove(ruleExecutor); ruleExecutorMap.remove(ruleExecutor.getType()); } }
一大堆维护规则和规则执行器的代码就不讲了,关键的几个讲下:
public void execute(Context context, String ruleSetName) { List<Rule> ruleSet = ruleSetMap.get(ruleSetName); if (ruleSet != null) { Vector<Rule> newSet = new Vector<Rule>(ruleSet); processRuleSet(context, newSet); } }
查找规则集,如果能找到就执行规则集,否则啥也不干。
private void processRuleSet(Context context, Vector<Rule> newSet) { //如果没有后续规则,则退出 if (newSet.size() == 0) { return; } Rule rule = newSet.get(0); RuleExecutor ruleExecutor = ruleExecutorMap.get(rule.getType()); if (ruleExecutor != null) { boolean executed = ruleExecutor.execute(context, rule); if (executed) { //如果 if (rule.isExclusive()) { //如果条件成立,则是独占条件,则直接返回 return; } else if (!rule.isMultipleTimes()) { //如果不是可重复执行的规则,则删除之 newSet.remove(0); } } else { //如果不匹配,则删除之 newSet.remove(0); } } else { throw new RuntimeException("找不到对应" + rule.getType() + "的执行器"); } processRuleSet(context, newSet); }
}
执行规则集的逻辑是:
如果规则集合中没有规则了,表示规则集已经执行完毕,直接返回。否则获取优先级最高的规则,首先检查是否有对象的规则执行器,如果没有,则抛异常。如果有就开始执行。
如果执行返回true,说明此规则被成功执行,则判断其是否是排他规则,如果是,则返回;否则检查是否是可重复执行规则,如果是则返回继续执行,否则把此条规则删除,继续执行下一条规则。
示例
这里假定做一个计算个人所得税的规则实例
定义规则
<rule-set name="feerule" > <!-- 独占类条件(执行顺序交互不影响执行结果) --> <!--优先级,数值越小优先级越高,用户设置优先级必须大于0;如果没有设置,系统会随机分配一个优先级;同一个规则集不能出现两个相同优先级的规则--> <mvel-rule id="step1" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary<=3500]]></condition> <action><![CDATA[fee=0]]></action> </mvel-rule> <mvel-rule id="step2" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>3500 && salary<=5000]]></condition> <action><![CDATA[fee=(salary-3500)*0.03]]></action> </mvel-rule> <mvel-rule id="step3" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>5000 && salary<=8000]]></condition> <action><![CDATA[fee=(salary-3500)*0.1-105]]></action> </mvel-rule> <mvel-rule id="step4" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>8000 && salary<=12500]]></condition> <action><![CDATA[fee=(salary-3500)*0.2-555]]></action> </mvel-rule> <mvel-rule id="step5" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>12500 && salary<=38500]]></condition> <action><![CDATA[fee=(salary-3500)*0.25-1005]]></action> </mvel-rule> <mvel-rule id="step6" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>38500 && salary<=58500]]></condition> <action><![CDATA[fee=(salary-3500)*0.3-2755]]></action> </mvel-rule> <mvel-rule id="step7" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>58500 && salary<=83500]]></condition> <action><![CDATA[fee=(salary-3500)*0.35-5505]]></action> </mvel-rule> <mvel-rule id="step8" multipleTimes="false" exclusive="true"> <condition><![CDATA[salary>83500]]></condition> <action><![CDATA[fee=(salary-3500)*0.45-13505]]></action> </mvel-rule> </rule-set>
编写TestCase
public void testFeeRule(){ Context context = new MvelContext(); context.put("fee", 0.0); context.put("salary", 1000); ruleEngine.execute(context, "feerule"); assertEquals(0, context.get("fee")); context.put("salary", 4000); ruleEngine.execute(context, "feerule"); assertEquals(15.0, context.get("fee")); context.put("salary", 7000); ruleEngine.execute(context, "feerule"); assertEquals(245.0, context.get("fee")); context.put("salary", 21000); ruleEngine.execute(context, "feerule"); assertEquals(3370.0, context.get("fee")); context.put("salary", 40005); ruleEngine.execute(context, "feerule"); assertEquals(8196.50, context.get("fee")); context.put("salary", 70005); ruleEngine.execute(context, "feerule"); assertEquals(17771.75, context.get("fee")); context.put("salary", 100000); ruleEngine.execute(context, "feerule"); assertEquals(29920.00, context.get("fee")); }
看到这里的时候,我唯一的想法是:啥时我才可以一个月缴3万块的税呀。
总结
呵呵,按照Tiny惯例,传上代码统计数据:
至此,一个简单的规则引擎就实现了,总共代码行数不包含注释为:462行。可以较好的适应各种简单的业务逻辑频繁变化的业务场景。
欢迎登录关注:http://web.j2ee.top,本例涉及的代码和框架资料,将会在论坛分享。技术交流群:228977971,让我们一起动手,了解框架的奥秘!
相关推荐
书中探讨了如何利用Tiny框架的RuleEngine实现规则引擎的应用,以及如何通过Tiny框架编译器实现类似于SQL的数据库操作语言TinySqlDsl。此外,还详细介绍了Tiny框架的模板引擎、社区应用实践、2.0版的推出等内容。 2....
内容概要:本文详细介绍了多种图像处理技术的实际应用和实现方法,涵盖了边缘检测、分形维数计算、霍夫直线检测、伪彩色增强、PCA降维、图像配准以及水印嵌入等多个方面。每种技术不仅提供了具体的Python代码示例,还分享了作者在实践中积累的经验和技巧。例如,边缘检测部分强调了Sobel算子的正确使用方法及其注意事项;分形维数计算部分展示了如何通过盒计数法进行实现;霍夫直线检测部分讨论了参数选择的影响;伪彩色增强部分介绍了基于LUT的颜色映射方法;PCA降维部分讲解了人脸识别的具体步骤;图像配准部分探讨了SIFT算法的应用;水印嵌入部分则深入剖析了DCT域的方法。 适合人群:具有一定编程基础并希望深入了解图像处理技术的开发者和技术爱好者。 使用场景及目标:适用于需要快速掌握图像处理核心技术的研究人员、工程师和学生。目标是帮助读者理解并能够独立实现常见的图像处理任务,如边缘检测、特征提取、图像融合、降维、配准和水印嵌入等。 其他说明:文中提供的代码片段均经过实际验证,可以直接用于实验环境。此外,作者还分享了许多实用的小贴士,如避免常见错误、优化性能等,有助于提高读者的实际操作能力。
本书《What Is Generative AI》由Kyle Stratis撰写,旨在为商业和技术领导者提供生成式人工智能(Generative AI)的基础知识。生成式AI是一种能够创造新内容的技术,包括图像、文本和视频,与传统的判别式AI不同,后者主要用于分类和回归任务。书中介绍了生成式AI的历史、发展以及现代架构,如变分自编码器(VAE)、生成对抗网络(GAN)和Transformer模型,并探讨了其在商业和创意领域的应用。作者强调,尽管生成式AI在推动增长、增强创造力和简化运营方面具有巨大潜力,但实施时也面临着伦理、法律和技术挑战。本书旨在为读者提供必要的知识和见解,以便他们能够评估生成式AI的投资回报率,并在日常生活中、商业活动或创意工作中有效利用这项技术。
《伍德里奇计量经济学计算机习题解答与资源》为学习者提供全面的习题解答与实用资源,涵盖R语言实现,帮助巩固计量经济学理论知识并提升实操能力。适合自学或辅助课程学习,助你高效掌握数据分析与建模技巧。
基于深度学习的系统
内容概要:本文详细介绍了Asp.Net CRM客户关系管理系统的功能和实现细节。该系统不仅涵盖了客户信息管理、日程安排等功能,还展示了如何通过C#代码实现这些功能。此外,文章强调了系统的二次开发能力和扩展性,如通过创建新的数据库表和编写相应代码来满足特定行业需求。系统采用三层架构,将客户生命周期、销售流程、团队协同等功能模块有机结合,形成一个完整的业务协同平台。文中还探讨了销售漏斗的状态机实现、实时消息推送、动态加载模块等高级功能,突出了ASP.NET在企业级业务系统开发中的优势。 适合人群:对CRM系统开发感兴趣的软件工程师、项目经理和技术主管。 使用场景及目标:适用于希望提升客户管理和内部协作效率的企业,尤其是那些需要定制化解决方案的企业。通过实施该系统,企业可以更好地管理客户资源,优化销售流程,提高工作效率,最终增强市场竞争力。 其他说明:文章提供了大量实际代码示例,帮助读者深入理解系统的工作原理和实现方法。同时,强调了系统设计中的关键技术决策,如使用状态模式、依赖注入、实时通信等,使读者不仅能学到具体的技术实现,还能掌握系统设计的思想。
流固耦合仿真技术:流固耦合网格划分.zip
该资源为natsort-4.0.4-py2.py3-none-any.whl,欢迎下载使用哦!
内容概要:本文详细介绍了一款基于Qt和C++开发的温度湿度传感器上位机程序。该程序实现了串口通信获取传感器数据、数据记录与自动保存、超时提醒等功能。具体功能包括:通过QSerialPort进行串口通信,获取温度和湿度数据;封装独立的串口通信处理类,便于二次开发;提供控制台调试窗口,用于实时显示和发送数据;利用QSettings实现配置自动保存;通过QTimer实现超时提醒;以及使用QDateTime生成带有时间戳的文件名,确保数据安全保存。此外,文中还介绍了开发环境、代码结构和一些常见问题及其解决方案。 适合人群:具有一定C++和Qt基础的开发者,尤其是从事物联网、嵌入式开发的技术人员。 使用场景及目标:适用于需要开发温度湿度传感器上位机的应用场景,如智能家居、工业监控等。主要目标是帮助开发者理解和掌握如何通过Qt和C++实现传感器数据的采集、处理和展示。 其他说明:文中提供了详细的代码片段和解释,有助于读者更好地理解每个功能的具体实现方法。同时,文中还提到了一些常见的开发陷阱和优化建议,为实际项目开发提供了宝贵的实践经验。
内容概要:本文详细介绍了西门子S7-200PLC(224XP型号)与MM420变频器之间的三种控制方式:数字量控制、模拟量控制以及USS通讯控制。首先,数字量控制通过PLC的开关量输出控制变频器的不同预设速度,涉及参数设置如P0701和P0702。其次,模拟量控制利用PLC自带的模拟量输出模块进行频率调节,需注意量程转换和参数P0756的设置。最后,USS通讯采用西门子专用协议实现复杂控制,强调了初始化参数、轮询机制和状态互锁的重要性。此外,文中还提供了关于MCGS触摸屏的应用技巧,如变量绑定和实时数据显示方法。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉西门子PLC和变频器产品的使用者。 使用场景及目标:适用于希望深入了解PLC与变频器联合控制系统的设计与实现的技术人员。主要目标是在实际工程项目中灵活运用这三种控制方式,提高系统的可靠性和效率。 其他说明:文中附带了详细的代码片段和调试建议,帮助读者更好地理解和实践相关技术。同时提醒读者关注参数设置的一致性和安全性,以避免潜在的风险。
流变学仿真方法:流变学仿真结果分析.zip
内容概要:本文详细介绍了将西门子PLC 224XP和226型号主控替换为STM32F103RCT6的改造项目。主要内容涵盖硬件选型、双串口DMA传输配置、PLC指令系统的实现、浮点运算处理、密码保护机制以及协议兼容等方面。文中提供了丰富的代码示例和技术细节,如GPIO复用配置、USART1和USART3的DMA环形缓冲配置、浮点数比较指令处理、三级密码验证状态机、S7协议读取请求处理、梯形图编译器的状态机构建等。 适合人群:具备嵌入式开发经验,熟悉STM32和PLC编程的技术人员。 使用场景及目标:适用于希望深入了解PLC改造项目的工程师,旨在掌握如何利用STM32实现高效稳定的PLC功能替代,提高工业控制系统性能。 其他说明:作者分享了许多实际开发中的经验和技巧,如DMA环形缓冲配置、浮点运算优化、协议兼容处理等,有助于读者更好地理解和应用相关技术。
sdgasdfg
内容概要:本文深入剖析了一个完整的口罩机自动化项目,涵盖了从硬件选型、电路设计到软件编程的各个方面。主要内容包括三菱FX3U PLC的梯形图编程、威纶触摸屏的界面设计、伺服电机参数调整、安全回路设计以及详细的IO表规划。文中不仅提供了具体的代码实例和技术细节,还分享了许多实际调试过程中积累的经验教训,如伺服电机抖动问题的解决、急停按钮的正确连接方式、关键传感器的输入点分配等。此外,作者还强调了装配图和调试记录的重要性,指出这些资料对于理解和优化整个系统的性能至关重要。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些希望深入了解PLC编程和触摸屏应用的人群。 使用场景及目标:适用于正在开发或维护类似自动化设备的技术团队,帮助他们提高系统的稳定性和生产效率。通过对本文的学习,读者能够掌握如何将理论知识应用于实际项目中,避免常见的设计和调试误区。 其他说明:文章最后提供了一个完整的项目资料包下载链接,包含了所有相关文件和调试记录,方便读者进行实践操作。
内容概要:本文深入探讨了一个全开源淘客系统的实现细节和技术优化。系统采用Go语言重构淘宝联盟API网关,处理商品搜索接口的核心逻辑,确保参数签名安全、HTTP请求稳定以及数据格式转换正确。数据库设计方面,使用MySQL存储佣金结算数据,利用JSON类型保存结算规则快照,防止规则变更影响历史数据。前端部分基于Vue.js构建佣金日历组件,强调数据驱动UI和事件冒泡处理交互。部署环节涉及SSL证书链的手动更新,确保API通信的安全性和稳定性。此外,系统还提供了详细的错误码设计、调试工具、订单同步服务、SDK封装、热更新通道等功能,旨在降低开发和运维难度,提高系统的可扩展性和易用性。 适合人群:具备一定编程基础的技术人员,尤其是对淘客系统感兴趣的开发者。 使用场景及目标:适用于希望搭建高效、稳定的淘客系统的个人或团队。主要目标是帮助用户理解淘客系统的架构设计和技术实现,提供实际操作指导,减少开发和运维中的常见问题。 其他说明:文中提到的系统不仅关注技术实现,还注重用户体验和系统稳定性,提供了丰富的调试工具和详细的文档支持。
CursorUserSetup-x64-0.48.8
内容概要:本文档为电子硬件课程设计提供了全面的项目资源,涵盖典型课程设计项目示例、开源项目资源库、开发工具与文档以及拓展学习平台。典型项目包括物联网综合开发平台(如ESP32主控+墨水屏交互系统)、电机驱动与控制项目(如STM32F4系列开发板的PWM调速算法)、传感器融合系统(如PM2.5检测仪)。开源项目资源库列举了多个项目的核心技术及其适用场景,如CD4047逆变器设计适用于电源系统课程设计。开发工具与文档部分介绍了EDA工具包、编程框架等,如重庆大学硬件综合设计实验包、STM32-V5开发套件。拓展学习平台则推荐了硬件开发社区和在线课程资源。最后给出了项目设计建议,包括开发流程和文档规范。; 适合人群:电子工程专业学生、电子硬件初学者、高校教师。; 使用场景及目标:①为电子硬件课程设计提供详细的项目参考,帮助学生完成课程作业;②为教师提供教学资源,辅助课堂教学;③为初学者提供学习路径,便于自学入门。; 其他说明:本文档结合了2025年最新行业动态和教学实践,确保提供的资源具有前沿性和实用性。文档强调了从需求分析到系统联调的完整开发流程,并对文档规范提出了具体要求,确保项目实施的规范性和可追溯性。
2024300928刘君浩.rar
内容概要:本文详细介绍了如何利用MATLAB实现模拟退火(SA)算法来解决带容量限制的车辆路径问题(CVRP)。首先解释了CVRP的核心挑战,即在满足车辆载重量限制的情况下,规划最优运输路线以最小化总运输成本。文中提供了完整的MATLAB代码实现,涵盖了初始化解、邻域操作、成本计算以及退火过程等关键步骤。此外,还讨论了一些常见的调试陷阱和技术细节,如温度参数的选择、邻域操作的设计以及如何处理超载情况。最后,给出了可视化的路线展示方法,并分享了几点实战经验和改进建议。 适合人群:对运筹学、物流优化感兴趣的科研人员、学生以及从事相关领域的工程师。 使用场景及目标:适用于需要优化物流配送路线的实际应用场景,特别是在中小规模CVRP问题中表现出色。主要目标是帮助读者理解和掌握模拟退火算法的基本原理及其在CVRP问题中的具体应用。 其他说明:文中提到的代码可以直接用于实验环境,同时也鼓励读者在此基础上进一步探索和改进算法性能。对于更大规模的问题,建议结合其他启发式方法共同使用。
内容概要:本文详细介绍了利用组态王软件和三菱FX3U PLC构建真空封装设备监控系统的具体实施过程和技术要点。主要内容涵盖设备监控界面的设计(如动态加载子画面)、报警处理模块(采用SQLite进行本地缓存)、用户权限管理系统(基于XML配置文件)以及真空度趋势预测等功能的实现方法。此外,还探讨了通信配置、工艺流程控制逻辑、数据记录与查询等方面的技术细节,并分享了一些实用的操作技巧和注意事项。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些对组态王和PLC编程有一定了解的人群。 使用场景及目标:适用于需要搭建高效稳定的工业生产设备监控系统的场合,旨在提高生产效率、降低误操作风险并确保设备安全可靠地运行。 其他说明:文中提供了大量具体的代码片段作为实例,帮助读者更好地理解和掌握相关知识点。同时强调了在实际项目中应注意的问题,如避免过度依赖上位机处理业务逻辑等。