Camstar开发:缓存的设计与实现(整合Redis实例)

Camstar开发:缓存的设计与实现(整合Redis实例)目录 引言 实例描述 开发分析 4 实例类图 5 代码分析 5 1RedisHelper 2ReceiveOrde 3IReceiveOrd 4AbsReceiveO 5ConcreteRec 6ReceiveOrde 运行测试 6 1 辅助代码 7 总结 nbsp 引言本

目录

1引言

2实例描述

3开发分析

4 实例类图

5 代码分析

5.1 RedisHelper

5.2 ReceiveOrderCache

5.3 IReceiveOrder

5.4 AbsReceiveOrder

5.5 ConcreteReceiveOrder

5.6 ReceiveOrderImpl

6 运行测试

6.1 辅助代码

7 总结


 

1引言

本文分析和演示如何在Camstar的Web服务层加入缓存,具体的缓存方式有多种选择,本文选择使用Redis作为缓存中间件。并以一个具体的实例(模拟真实情况),演示用缓存的好处。本篇博文的理论基础是另一篇博文:Camstar 开发:缓存的作用与分析

2实例描述

假设已有生产订单从SAP系统调用MES系统的接口发推送到了MES系统,接口数据如表1所示。现需要在MES系统中开发一个接收页面,由生产调度员选择需要生产的订单,接收并下发到生产线。

表1
字段名 字段类型 字段描述
Order string 订单号
State string 订单状态,默认未接受
OtherInfo string 订单信息(其他信息不重要,统一成一个字段)

原型设计界面如图1所示。

Camstar开发:缓存的设计与实现(整合Redis实例)

图1

上方区域为待接收的生产订单的过滤条件,下方区域为推送到MES系统的生产订单信息。用户点击查询按钮,根据筛选条件查询符合条件的生产订单;用户选择表格生产订单点击接收,将选择的生产订单接收并下发到生产线。

3开发分析

开发背景:目前接口具体数据尚未明确,表1中的数据只是预计必有的一些字段,系统接口实际也未搭建,即数据来源不确定。订单接收后数据流向无需考虑,本页面只需修改订单的状态从“未接受”到“已接收”。

 

本页面功能很简单,从开发角度来说,就是一个查询功能和一个修改功能。困难点在于上游数据不确定,作为Camstar开发很难确定在Designer中的建模。假设本页面所有操作都做缓存处理,不需要穿透到数据库,并且缓存不过期。那么,可以设计如表2的缓存结构。

 

表2
Key Value
Order State和OtherInfo等信息的对象

4 实例类图

经过分析该实例,画出实例类图,如图2。可以看出,系统类从通常的1个变成了5个,类数量大幅度增加,但是各个类的职责更加明确,实际代码并没有增加很多。

Camstar开发:缓存的设计与实现(整合Redis实例)

图2

整体结构中,主要使用了桥接模式,将穿透到Camstar服务的代码和访问缓存的代码解耦;在抽象类AbsReceiveOrder中又使用模板方法模式,控制整个服务的执行逻辑骨架。而具体的逻辑则交给子类实现抽象方法,钩子方法和接口实现来反向控制。

根据实例类图,具体实现代码,项目工程树如图3所示。

Camstar开发:缓存的设计与实现(整合Redis实例)

图3

5 代码分析

5.1 RedisHelper

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Reflection; using ServiceStack.Redis; ///  /// Summary description for RedisHelper ///  public class RedisHelper { #region Single private static RedisHelper instance; private static readonly object locker = new object(); public static RedisHelper Instance { get { if (instance == null) lock (locker) { if (instance == null) instance = new RedisHelper(); } return instance; } } private RedisHelper() { // // TODO: Add constructor logic here // } #endregion private RedisClient redisClient = new RedisClient("localhost", 6379); public RedisClient RedisClient { get { return redisClient; } } }

RedisHelper是采用单例模式设计的Redis辅助类,为了保证同一个Web服务端只有一个Redis的客户端。其中,将Redis服务地址和端口以及密码等信息写入配置文件,可以在运行期指向不同的Redis服务实例。 本类中硬编码了。

5.2 ReceiveOrderCache

 

using System; using System.Collections.Generic; using System.Linq; using System.Web; ///  /// Summary description for ReceiveOrderCacheh ///  public class ReceiveOrderCache { public ReceiveOrderCache() { // // TODO: Add constructor logic here // } //订单号 key private string order; //订单类型 private string orderType; //任务号 private string taskNo; //产品名称 private string productDesc; //产品代号 private string productType; //产品型号 private string productCode; //零部件图号 private string productName; //零部件名称 private string partName; //零部件版本 private string partRev; //工艺编号 private string workflow; //工艺版本 private string workflowRev; //计划数量 private int planQty; //计划开始日期 private DateTime planStartDate; //计划完成日期 private DateTime planEndDate; //计划状态 private string state; //接收时间 private DateTime receiveDate; //车间调度员 private string productionControler; //主制车间 private string factory; public string ProductionControler { get { return productionControler; } set { productionControler = value; } } public DateTime ReceiveDate { get { return receiveDate; } set { receiveDate = value; } } public string State { get { return state; } set { state = value; } } public DateTime PlanEndDate { get { return planEndDate; } set { planEndDate = value; } } public DateTime PlanStartDate { get { return planStartDate; } set { planStartDate = value; } } public int PlanQty { get { return planQty; } set { planQty = value; } } public string WorkflowRev { get { return workflowRev; } set { workflowRev = value; } } public string Workflow { get { return workflow; } set { workflow = value; } } public string PartRev { get { return partRev; } set { partRev = value; } } public string PartName { get { return partName; } set { partName = value; } } public string ProductName { get { return productName; } set { productName = value; } } public string ProductCode { get { return productCode; } set { productCode = value; } } public string ProductType { get { return productType; } set { productType = value; } } public string ProductDesc { get { return productDesc; } set { productDesc = value; } } public string TaskNo { get { return taskNo; } set { taskNo = value; } } public string OrderType { get { return orderType; } set { orderType = value; } } public string Order { get { return order; } set { order = value; } } public string Factory { get { return factory; } set { factory = value; } } }

ReceiveOrderCache为接口数据交互类,是我直接从原有代码复制的,所以属性较多。本例用到的属性只有Order,State。其他信息同一用OtherInfo代表。 

5.3 IReceiveOrder

using System; using System.Collections.Generic; using System.Linq; using System.Web; using Camstar.WCF.ObjectStack; ///  /// Summary description for IReceiveOrder ///  public interface IReceiveOrder { Dictionary 
   
     GetDataFromCamstar(); ResultStatus UpdateOrderInfo(string order, string state); } 
   

 在IReceiveOrder接口中定义需要穿透到Camstar服务的方法,其中GetDataFromCamstar()方法用于返回订单信息,UpdateOrderInfo()方法用于修改订单信息(修改订单状态)。

5.4 AbsReceiveOrder

using System; using System.Collections.Generic; using System.Linq; using System.Web; using Camstar.WCF.ObjectStack; using Camstar.WebPortal.WebPortlets; ///  /// Summary description for ReceiveOrderDemo ///  public abstract class AbsReceiveOrder:MatrixWebPart { private IReceiveOrder camstar; public IReceiveOrder Camstar { get { if (camstar == null) camstar = new ReceiveOrderImpl(); return camstar; } } private Dictionary 
   
     orderInfo; public Dictionary 
    
      OrderInfo { get { if(orderInfo == null) { orderInfo = GetDataFromCahce(); if(orderInfo == null && Hook()) { orderInfo = Camstar.GetDataFromCamstar(); } } return orderInfo; } } protected abstract Dictionary 
     
       GetDataFromCahce(); protected virtual bool Hook() { return false; } protected abstract ResultStatus ReceiveOrder(); public AbsReceiveOrder() { // // TODO: Add constructor logic here // } } 
      
     
   

 抽象类定义了整个业务逻辑的骨架,其中获取OrderInfo中使用了模板方法模式,定义逻辑:如果缓存为空则穿透。

值得一提的是,在该模板方法种还定义了Hook()钩子方法,即便是缓存为空,如果钩子方法没有重写,那么可能依然不会穿透。在本例中,钩子方法默认返回了false,实际上,应该将这个返回值写入配置文件中,这样,子类就可以有3种不同的处理方式:

1)什么都不做,那么将默认读取配置文件中的值,这个值可以是全局控制系统是否读缓存。

2)重写返回false,意味着该业务永不穿透到Camstar服务。

3)重写返回True,这是最有可能的情况,意味着穿透到Camstar服务的代码已经有相关开发者实现了,那么当缓存未命中时候,则穿透到Camstar服务。

该类种还组合使用了桥接模式,将穿透Camstar服务的代码和访问缓存的代码解耦,这样,就可以让俩边的代码交给不同的开发者开发了。其中写死了camstar = new ReceiveOrderImpl();这里只要采用反射的方式实例化,即可完全解耦。代码中采用New的方式是为了演示方便。

5.5 ConcreteReceiveOrder

using System; using System.Collections.Generic; using System.Linq; using System.Web; using Camstar.WCF.ObjectStack; using Camstar.WebPortal.FormsFramework.WebGridControls; using System.Data; ///  /// Summary description for ConcreteReceiveOrder ///  public class ConcreteReceiveOrder : AbsReceiveOrder { protected virtual JQDataGrid Grid_list { get { return Page.FindCamstarControl("grid_list") as JQDataGrid; } } public ConcreteReceiveOrder() { // // TODO: Add constructor logic here // } public void Select() { DataTable dt = new DataTable(); dt.Columns.Add("ORDER", typeof(string)); dt.Columns.Add("STATE", typeof(string)); dt.Columns.Add("OTHERINFO", typeof(string)); foreach (string key in OrderInfo.Keys) { DataRow dr = dt.NewRow(); dr["ORDER"] = key; dr["STATE"] = OrderInfo[key].State; dr["OTHERINFO"] = OrderInfo[key].ReceiveDate; dt.Rows.Add(dr); } Grid_list.Data = dt; } public void Receive() { //结果展示在页面 Page.DisplayMessage(ReceiveOrder()); //刷新页面 Select(); } protected override Dictionary 
   
     GetDataFromCahce() { Dictionary 
    
      data = new Dictionary 
     
       (); RedisHelper.Instance.RedisClient.Db = 0; byte[][] byteKeys = RedisHelper.Instance.RedisClient.Keys("receivedOrder:*"); foreach (byte[] key in byteKeys) { string keyStr = System.Text.Encoding.Default.GetString(key); data.Add(keyStr, RedisHelper.Instance.RedisClient.Get 
      
        (keyStr)); } return data; } protected override ResultStatus ReceiveOrder() { //页面被选定的订单信息,此处懒得写代码获取页面被选定的行,写死,看得懂就行。 ReceiveOrderDTO data = new ReceiveOrderDTO(); data.OtherInfo = "略略略"; data.State = "已接收"; string orderChecked = "Order66"; //穿透到Camstar服务 ResultStatus rs = Camstar.UpdateOrderInfo(orderChecked, "已接收"); //如果执行成功,则更新缓存 if (rs.IsSuccess) { RedisHelper.Instance.RedisClient.Set 
       
         ("ReceiveOrder:" + orderChecked, data); } return rs; } } 
        
       
      
     
   

 子类具体实现访问缓存的方法,以及定义Select和Receive方法用于和前端交互。

5.6 ReceiveOrderImpl

using System; using System.Collections.Generic; using System.Linq; using System.Web; using Camstar.WCF.ObjectStack; using System.Data; ///  /// Summary description for ReceiveOrderFromCamstar ///  public class ReceiveOrderImpl:IReceiveOrder { public ReceiveOrderImpl() { // // TODO: Add constructor logic here // } public Dictionary 
   
     GetDataFromCamstar() { throw new NotImplementedException(); } public ResultStatus UpdateOrderInfo(string order,string state) { ResultStatus rs = new ResultStatus(); rs.IsSuccess = true; rs.Message = "默认调用成功"; return rs; } } 
   

 接口具体实现访问Camstar服务的方法。这里由于笔者时间有限,并没有实际调用Camstar服务。

6 运行测试

 

6.1 辅助代码

由于代码默认不穿透到数据库,因此,需要手动添加缓存。这里采用简单的控制台循环插入不过期的缓存数据。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ServiceStack.Redis; namespace RedisDataHelper { class Program { static void Main(string[] args) { RedisClient redisClient = new RedisClient("localhost", 6379); for (int i = 0; i < 100; i++) { ReceiveOrderCache data = new ReceiveOrderCache(); data.Order = "order" + i; data.OrderType = i % 2 == 0 ? "STDA" : "STDB"; data.PartName = "PartName" + i; data.PartRev = "PartRev" + i; data.PlanEndDate = DateTime.Now.AddDays(i + i); data.PlanQty = i + 10; data.PlanStartDate = DateTime.Now.AddDays(i); data.ProductCode = "ProductCode" + i; data.ProductDesc = "ProductDesc" + i; data.ProductName = "ProductName" + i; data.ProductType = "ProductType" + i; data.ReceiveDate = DateTime.Now; data.State = "未接受"; data.TaskNo = "TaskNo" + i; data.Workflow = "Workflow" + i; data.WorkflowRev = "WorkflowRev" + i; data.Factory = i % 2 == 0 ? "Test" : "PRO"; redisClient.Set 
   
     ("receivedOrder:" + data.Order, data); } } } } 
   

运行Camstar页面,点击查询按钮。

 Camstar开发:缓存的设计与实现(整合Redis实例)

代码能正常运行,并且数据是从缓存中获取的。如果需要穿透到数据库,只需要修改配置文件即可,无需修改任何代码。且穿透到Camstar服务的代码也可以完全交给熟悉Camstar的开发人员。

7 总结

由于笔者的个人时间问题,实例并没有将修改完全做出来,而是采用伪代码的形式。但是这个例子想表达的效果相信已经可以完全体现。Camstar 开发:缓存的设计于分析

后续有空我会把源码整理出来上传到资源共享中。并附上连接

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206111.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午4:27
下一篇 2026年3月19日 下午4:27


相关推荐

  • ILA(集成逻辑分析器)的使用

    ILA(集成逻辑分析器)的使用本文内容学习自正点原子 ZYNQ 领航者 FPGA 视频 P71 ILA 介绍 nbsp ILA IntegratedLo 集成逻辑分析器 即 Vivado 的在线逻辑分析仪 其借用了传统逻辑分析仪的理念以及大部分的功能 并利用 FPGA 中的逻辑资源 将这些功能植入到 FPGA 的设计当中 ILA 是用 IP 核的形式实现的

    2026年3月19日
    2
  • Mac系统下完全卸载PyCharm的步骤

    Mac系统下完全卸载PyCharm的步骤小编的系统是 MacOS10 15 4 之前是去官网下载安装了 PyCharm2020 1 2 现在想把它完全卸载了 方法如下 1 打开访达 应用程序 找到 PyCharm 应用图标 右键移到废纸篓 2 清理缓存 参数以及日志相关配置文件 cd Library Preferences rm rfJetBrains PyCharm2020 1 cd Library Logsrm rfJetBrains PyCharm2020 1 cd L

    2026年3月18日
    2
  • html超链接样式设置「建议收藏」

    html超链接样式设置「建议收藏」type=”text/css”>A {FONT-SIZE: 16px; FONT-FAMILY: 宋体}A:link {COLOR: #0055bb; TEXT-DECORATION: none}A:visited {COLOR: #0077bb; TEXT-DECORATION: none}A:hover {COLOR: #ff0000

    2022年7月19日
    16
  • mac phpstorm激活码2021【在线注册码/序列号/破解码】[通俗易懂]

    mac phpstorm激活码2021【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    42
  • [文摘]上软解散相关

    [文摘]上软解散相关真实系列文摘之上海软星仙剑开发组解散真正内幕—–附.上软人最后留给玩家的话我不是个疯狂的仙剑迷,但我有朋友是;我不是个对看不管惯的社会现象能挺身而出的人,但还是喜欢去在意去关心那些事…下面这个算不上是什么新闻了,但如过是玩过仙剑系列觉得还不错的人,对游…

    2022年5月19日
    48
  • SQLite下载、安装和使用并Qt链接SQLIte全部教程(windows)

    SQLite下载、安装和使用并Qt链接SQLIte全部教程(windows)第一步 下载 SQLIte 下载地址 https www sqlite org download html 下载两个内容 sqlite dll win64 x64 3360000 zipsqlite tools win32 x86 3360000 zip 下载完后直接解压 放到到一个文件夹下 这个文件夹可以随便在哪里 如下图 第二步 使用 SQLite 网上好多教程都是到这一步就配置环境变量 不知道他们脑子咋想的 轻量级数据库 SQLIte 本来就应该随着项目到处走 直接在解压且合并后

    2025年7月21日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号