c
#ifndef CACHEDATAMANAGER_H
#define CACHEDATAMANAGER_H
#if defined(QTFRAMEWORKHOST_LIBRARY)
# define QTFRAMEWORKHOST_EXPORT Q_DECL_EXPORT
#else
# define QTFRAMEWORKHOST_EXPORT Q_DECL_IMPORT
#endif
#include <QMap>
#include <QString>
#include <QVariant>
/*!
* @class CacheDataManager
* @brief 全局数据管理器,缓存临时配置数据、保存配置文件
* 需要获取实时修改信息,请订阅主题为CacheDataChangedEvent关键字为group的事件
* @author zhoubo
* @version 1.0.1
*/
class QTFRAMEWORKHOST_EXPORT CacheDataManager
{
public:
/*!
* @name addCacheData
* @brief 设置或更新需要缓存的信息
* @param group->组信息(不要包含特殊字符)
* @param key->关键字(不要包含特殊字符)
* @param value->对应值
* @param issave->是否保存到文件中,保存后下次会自动导入
* @param modifyKey->修改秘钥,只有使用相同秘钥才能被修改
* @return 是否添加成功,如果失败可能是修改秘钥错误导致
*/
virtual bool addCacheData(const QString &group,const QString &key,const QVariant &value,bool issave = false,QString modifyKey="*")=0;
/*!
* @name addCacheData
* @brief 设置或更新需要缓存的信息
* @param group->组信息(不要包含特殊字符)
* @param value->设置或更新的键值对,key关键字(不要包含特殊字符)
* @param issave->是否保存到文件中,保存后下次会自动导入
* @param modifyKey->修改秘钥,只有使用相同秘钥才能被修改
*/
virtual void addCacheData(const QString &group,const QMap<QString,QVariant> &value,bool issave = false,QString modifyKey="*")=0;
/*!
* @name cacheData
* @brief 获取其他数据
* @param key->关键字
* @param value->对应值
* @return 存在key为true,否则为false
*/
virtual bool cacheData(const QString &group,const QString &key,QVariant &value)=0;
/*!
* @name cacheData
* @brief 获取其他数据
* @param key->关键字
* @param group->组名
* @return 值
*/
virtual QVariant cacheData(const QString &group,const QString &key)=0;
/*!
* @name cacheData
* @brief 获取group下的配置信息
* @param group->组名
* @return 所有其他数据
*/
virtual QMap<QString,QVariant> cacheData(const QString &group)=0;
/*!
* @name remove
* @brief 移除数据,只能移除修改秘钥为*的项
*/
virtual void remove()=0;
/*!
* @name remove
* @brief 移除数据
* @param group->组名
* @param modifyKey->修改秘钥,只有使用相同秘钥才能被删除
* @return 移除为true,否则为false
*/
virtual bool remove(const QString &group,const QString modifyKey="*")=0;
/*!
* @name remove
* @brief 移除数据
* @param group->组名
* @param key->关键字
* @param modifyKey->修改秘钥,只有使用相同秘钥才能被删除
* @return 移除为true,否则为false
*/
virtual bool remove(const QString &group,const QString &key,const QString modifyKey="*")=0;
/*!
* @name groups
* @brief 获取所有组名称
* @return 所有组名称
*/
virtual QStringList groups()=0;
/*!
* @name begingroups
* @brief 获取以begin开始的所有组名称
* @param begin->以begin结尾的所有组
* @return 所有组名称
*/
virtual QStringList begingroups(const QString &begin)=0;
/*!
* @name endgroups
* @brief 获取以end结尾的所有组名称
* @param end->以end结尾的所有组
* @return 所有组名称
*/
virtual QStringList endgroups(const QString &end)=0;
/*!
* @name keys
* @brief 获取group所有关键字
* @param group->组名
* @return 组中所有关键字
*/
virtual QStringList keys(const QString& group)=0;
/*!
* @name instance
* @brief 获取CacheDataManager的实例
* @return CacheDataManager的实例
*/
static CacheDataManager* instance();
};
#endif // CACHEDATAMANAGER_H
c
#include "cachedatamanager.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMutex>
#include <QRegularExpression>
namespace {
/**
* @brief 内部实现类,仅cpp文件可见,不对外导出
*/
class CacheDataManagerImpl : public CacheDataManager
{
public:
CacheDataManagerImpl();
~CacheDataManagerImpl() override;
bool addCacheData(const QString &group, const QString &key, const QVariant &value, bool issave, QString modifyKey) override;
void addCacheData(const QString &group, const QMap<QString, QVariant> &value, bool issave, QString modifyKey) override;
bool cacheData(const QString &group, const QString &key, QVariant &value) override;
QVariant cacheData(const QString &group, const QString &key) override;
QMap<QString, QVariant> cacheData(const QString &group) override;
void remove() override;
bool remove(const QString &group, const QString modifyKey) override;
bool remove(const QString &group, const QString &key, const QString modifyKey) override;
QStringList groups() override;
QStringList begingroups(const QString &begin) override;
QStringList endgroups(const QString &end) override;
QStringList keys(const QString &group) override;
private:
mutable QMutex m_mutex;
/// group -> key -> <value, modifyKey>
QMap<QString, QMap<QString, QPair<QVariant, QString>>> m_memoryData;
/// 需要持久化保存的标记 group/key
QSet<QString> m_saveMark;
QString getSaveFilePath() const;
void loadFromFile();
void saveToFile();
void notifyDataChanged(const QString &group);
bool checkGroupNameValid(const QString &group);
bool checkKeyNameValid(const QString &key);
};
static CacheDataManagerImpl* g_instance = nullptr;
static QMutex g_instanceMutex;
CacheDataManagerImpl::CacheDataManagerImpl()
{
loadFromFile();
}
CacheDataManagerImpl::~CacheDataManagerImpl()
{
saveToFile();
}
bool CacheDataManagerImpl::addCacheData(const QString &group, const QString &key, const QVariant &value, bool issave, QString modifyKey)
{
QMutexLocker lock(&m_mutex);
if(!checkGroupNameValid(group) || !checkKeyNameValid(key))
return false;
auto &groupData = m_memoryData[group];
QString fullKey = QString("%1||%2").arg(group, key);
// 如果该key已存在,校验modifyKey
if(groupData.contains(key))
{
QString existModifyKey = groupData[key].second;
if(existModifyKey != "*" && existModifyKey != modifyKey)
{
return false; //秘钥不匹配,禁止修改
}
}
groupData[key] = qMakePair(value, modifyKey);
if(issave)
{
m_saveMark.insert(fullKey);
saveToFile();
}
notifyDataChanged(group);
return true;
}
void CacheDataManagerImpl::addCacheData(const QString &group, const QMap<QString, QVariant> &value, bool issave, QString modifyKey)
{
QMutexLocker lock(&m_mutex);
if(!checkGroupNameValid(group))
return;
auto &groupData = m_memoryData[group];
for(auto iter = value.cbegin(); iter != value.cend(); ++iter)
{
const QString &k = iter.key();
if(!checkKeyNameValid(k))
continue;
QString fullKey = QString("%1||%2").arg(group, k);
if(groupData.contains(k))
{
QString existMK = groupData[k].second;
if(existMK != "*" && existMK != modifyKey)
continue;
}
groupData[k] = qMakePair(iter.value(), modifyKey);
if(issave)
{
m_saveMark.insert(fullKey);
}
}
if(issave)
saveToFile();
notifyDataChanged(group);
}
bool CacheDataManagerImpl::cacheData(const QString &group, const QString &key, QVariant &value)
{
QMutexLocker lock(&m_mutex);
if(!m_memoryData.contains(group))
return false;
auto &g = m_memoryData[group];
if(!g.contains(key))
return false;
value = g[key].first;
return true;
}
QVariant CacheDataManagerImpl::cacheData(const QString &group, const QString &key)
{
QMutexLocker lock(&m_mutex);
if(!m_memoryData.contains(group))
return QVariant();
auto &g = m_memoryData[group];
if(!g.contains(key))
return QVariant();
return g[key].first;
}
QMap<QString, QVariant> CacheDataManagerImpl::cacheData(const QString &group)
{
QMutexLocker lock(&m_mutex);
QMap<QString, QVariant> ret;
if(!m_memoryData.contains(group))
return ret;
auto &g = m_memoryData[group];
for(auto iter = g.cbegin(); iter != g.cend(); ++iter)
{
ret.insert(iter.key(), iter.value().first);
}
return ret;
}
void CacheDataManagerImpl::remove()
{
QMutexLocker lock(&m_mutex);
QStringList groupList = groups();
for(const auto& g : groupList)
{
remove(g, "*");
}
}
bool CacheDataManagerImpl::remove(const QString &group, const QString modifyKey)
{
QMutexLocker lock(&m_mutex);
if(!m_memoryData.contains(group))
return false;
auto &groupData = m_memoryData[group];
bool anyRemoved = false;
QStringList delKeys;
for(auto iter = groupData.begin(); iter != groupData.end(); ++iter)
{
const QString &existMK = iter.value().second;
if(existMK == "*" || existMK == modifyKey)
{
QString fullKey = QString("%1||%2").arg(group, iter.key());
m_saveMark.remove(fullKey);
delKeys << iter.key();
anyRemoved = true;
}
}
for(const auto& k : delKeys)
{
groupData.remove(k);
}
if(groupData.isEmpty())
{
m_memoryData.remove(group);
}
if(anyRemoved)
{
saveToFile();
notifyDataChanged(group);
}
return anyRemoved;
}
bool CacheDataManagerImpl::remove(const QString &group, const QString &key, const QString modifyKey)
{
QMutexLocker lock(&m_mutex);
if(!m_memoryData.contains(group))
return false;
auto &groupData = m_memoryData[group];
if(!groupData.contains(key))
return false;
QString existMK = groupData[key].second;
if(existMK != "*" && existMK != modifyKey)
return false;
QString fullKey = QString("%1||%2").arg(group, key);
m_saveMark.remove(fullKey);
groupData.remove(key);
if(groupData.isEmpty())
{
m_memoryData.remove(group);
}
saveToFile();
notifyDataChanged(group);
return true;
}
QStringList CacheDataManagerImpl::groups()
{
QMutexLocker lock(&m_mutex);
return m_memoryData.keys();
}
QStringList CacheDataManagerImpl::begingroups(const QString &begin)
{
QMutexLocker lock(&m_mutex);
QStringList ret;
const auto& gs = m_memoryData.keys();
for(const auto& g : gs)
{
if(g.startsWith(begin))
ret << g;
}
return ret;
}
QStringList CacheDataManagerImpl::endgroups(const QString &end)
{
QMutexLocker lock(&m_mutex);
QStringList ret;
const auto& gs = m_memoryData.keys();
for(const auto& g : gs)
{
if(g.endsWith(end))
ret << g;
}
return ret;
}
QStringList CacheDataManagerImpl::keys(const QString &group)
{
QMutexLocker lock(&m_mutex);
if(!m_memoryData.contains(group))
return {};
return m_memoryData[group].keys();
}
QString CacheDataManagerImpl::getSaveFilePath() const
{
// 可修改为你实际缓存文件路径,示例程序运行目录cache.json
return "./cacheData.json";
}
void CacheDataManagerImpl::loadFromFile()
{
QFile f(getSaveFilePath());
if(!f.open(QIODevice::ReadOnly))
return;
QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
f.close();
if(!doc.isObject())
return;
QJsonObject root = doc.object();
for(auto groupIter = root.begin(); groupIter != root.end(); ++groupIter)
{
QString group = groupIter.key();
QJsonObject groupObj = groupIter.value().toObject();
for(auto keyIter = groupObj.begin(); keyIter != groupObj.end(); ++keyIter)
{
QString key = keyIter.key();
QJsonObject itemObj = keyIter.value().toObject();
QVariant val = itemObj["value"].toVariant();
QString mk = itemObj["modifyKey"].toString("*");
bool saveFlag = itemObj["issave"].toBool(false);
m_memoryData[group][key] = qMakePair(val, mk);
if(saveFlag)
{
m_saveMark.insert(QString("%1||%2").arg(group, key));
}
}
}
}
void CacheDataManagerImpl::saveToFile()
{
QJsonObject root;
for(auto gIter = m_memoryData.cbegin(); gIter != m_memoryData.cend(); ++gIter)
{
QString group = gIter.key();
QJsonObject groupObj;
auto &gData = gIter.value();
for(auto kIter = gData.cbegin(); kIter != gData.cend(); ++kIter)
{
QString key = kIter.key();
auto p = kIter.value();
QString fullKey = QString("%1||%2").arg(group, key);
QJsonObject item;
item["value"] = QJsonValue::fromVariant(p.first);
item["modifyKey"] = p.second;
item["issave"] = m_saveMark.contains(fullKey);
groupObj[key] = item;
}
root[group] = groupObj;
}
QJsonDocument doc(root);
QFile f(getSaveFilePath());
if(f.open(QIODevice::WriteOnly))
{
f.write(doc.toJson(QJsonDocument::Indented));
f.close();
}
}
void CacheDataManagerImpl::notifyDataChanged(const QString &group)
{
// ========= 这里替换为你项目内部事件发送代码 =========
// 文档注释:订阅主题为CacheDataChangedEvent,关键字为group的事件
// eventBus->publish("CacheDataChangedEvent", group);
// =================================================
Q_UNUSED(group);
}
bool CacheDataManagerImpl::checkGroupNameValid(const QString &group)
{
//禁止特殊字符 \ / : * ? " < > |
static QRegularExpression reg(R"([\\/:*?"<>|])");
return !group.contains(reg) && !group.isEmpty();
}
bool CacheDataManagerImpl::checkKeyNameValid(const QString &key)
{
static QRegularExpression reg(R"([\\/:*?"<>|])");
return !key.contains(reg) && !key.isEmpty();
}
} // end anonymous namespace
CacheDataManager* CacheDataManager::instance()
{
QMutexLocker lock(&g_instanceMutex);
if(!g_instance)
{
g_instance = new CacheDataManagerImpl();
}
return g_instance;
}
外部调用
c
#include "cachedatamanager.h"
//设置缓存
CacheDataManager* cache = CacheDataManager::instance();
cache->addCacheData("sysConfig","name","testApp",true,"admin");
//读取
QVariant v = cache->cacheData("sysConfig","name");
//删除,必须匹配modifyKey
cache->remove("sysConfig","admin");
最好找个头文件
c
/*! 临时缓存与配置宏定义 */
#define __AddCacheData CacheDataManager::instance()->addCacheData///< 添加配置信息
#define __CacheData CacheDataManager::instance()->cacheData///< 获取配置信息
#define __Remove CacheDataManager::instance()->remove///< 移除配置信息
#define __Groups CacheDataManager::instance()->groups///< 获取所有组
#define __BeginGroups CacheDataManager::instance()->begingroups///< 获取以str开始的所有组
#define __EndGroups CacheDataManager::instance()->endgroups///< 获取以str结尾的所有组
#define __Keys CacheDataManager::instance()->keys///< 获取组下的key