设计模式之过滤器模式

news2025/1/11 18:49:33

目录

1.简介

2.过滤器的实现

2.1.过滤器的角色

2.2.类图

2.3.具体实现

3.过滤器模式的优点

4.过滤器模式的不足

5.适用的场景


1.简介

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种结构型设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。说的通俗些就是把一个集合对象根据过滤条件筛选出自己想要的对象。

2.过滤器的实现

2.1.过滤器的角色

抽象过滤器角色(AbstractFilter):负责定义过滤器的实现接口,具体的实现还要具体过滤器角色去参与,客户端可以调用抽象过滤器角色中定义好的方法,将客户端的所有请求委派到具体的实现类去,从而让实现类去处理;
具体过滤器角色(ConcreteFilter):该角色负责具体筛选规则的逻辑实现,最后再返回一个过滤后的数据集合,标准的过滤器只对数据做过滤,当然也可以对集合中的数据做某项处理,再将处理后的集合返回;
被过滤的主体角色(Subject):一个软件系统中可以有一个或多个目标角色,在具体过滤器角色中会对指定感兴趣的目标进行处理,以确保后面的数据确实是我想要的。

2.2.类图

ICriteria : 抽象过滤器角色,定义了抽象接口doFilter

CCriteriaMale: 具体的过滤器角色,过滤male

CCriteriaFemale: 具体的过滤器角色,过滤female

CCriteriaEducation: 具体的过滤器角色,过滤指定学历的

CCriteriaAboveAge: 具体的过滤器角色,过滤大于某个年龄的

CCriteriaAnd:具体的过滤器角色,实现两个具体的过滤器的逻辑与

CCriteriaOr:具体的过滤器角色,实现两个具体的过滤器的逻辑或

CCriteriaAndEx:具体的过滤器角色,实现多个具体的过滤器的逻辑与

CCriteriaOrEx:具体的过滤器角色,实现多个具体的过滤器的逻辑或

CPerson: 被过滤的主体角色

注:里面用到了std::initializer_list,具体用法可参考深入理解可变参数-CSDN博客的第2章节。

2.3.具体实现

主体角色和过滤器代码如下:FilterMode.h

#ifndef _FILTER_MODE_H_
#define _FILTER_MODE_H_
#include <string>
#include <vector>
#include <algorithm>


//被过滤的实体类
class CPerson
{
public:
	explicit CPerson(const std::string& name, const std::string& sex, int age, const std::string& education)
		: m_name(name), m_sex(sex), m_age(age), m_education(education) {}
	~CPerson() {}

public:
	std::string name() const { return m_name; }
	std::string sex() const { return m_sex; }
	int age() const { return m_age; }
	std::string education() const { return m_education; }
	std::string toString() const {
		return std::string("[name:") + m_name + std::string(";sex:") + m_sex + std::string(";age:") + std::to_string(m_age)
			+ std::string(";education:") + m_education + std::string("]");
	}

private:
	std::string m_name;
	std::string m_sex;
	int         m_age;
	std::string m_education;
};

//抽象过滤器
class ICriteria {
public:
	virtual std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) = 0;
};

//具体过滤器:过滤male
class CCriteriaMale : public ICriteria
{
public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> malePersons;
		for (auto& it : persons) {
			if (0 == it->sex().compare("male")) {
				malePersons.push_back(it);
			}
		}
		return malePersons;
	}
};

//具体过滤器:过滤female
class CCriteriaFemale : public ICriteria
{
public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> femalePersons;
		for (auto& it : persons) {
			if (0 == it->sex().compare("female")) {
				femalePersons.push_back(it);
			}
		}
		return femalePersons;
	}
};

//具体过滤器:过滤学历
class CCriteriaEducation : public ICriteria
{
public:
	explicit CCriteriaEducation(const std::string& education) :m_education(education) {}
public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> eduPersons;
		for (auto& it : persons) {
			if (0 == it->education().compare(m_education)) {
				eduPersons.push_back(it);
			}
		}
		return eduPersons;
	}

private:
	std::string m_education;
};

//具体过滤器:过滤年龄
class CCriteriaAboveAge : public ICriteria
{
public:
	explicit CCriteriaAboveAge(int age) : m_age(age) {}

public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> agePersons;
		for (auto& it : persons) {
			if (it->age() > m_age) {
				agePersons.push_back(it);
			}
		}
		return agePersons;
	}
private:
	int  m_age;
};

//具体过滤器:两个过滤器的逻辑与
class CCriteriaAnd : public ICriteria
{
public:
	explicit CCriteriaAnd(ICriteria* pCriteria1, ICriteria* pCriteria2)
		: m_criteria1(pCriteria1), m_criteria2(pCriteria2) {}

public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> andPersons = m_criteria1->doFilter(persons);
		return m_criteria2->doFilter(andPersons);
	}
private:
	ICriteria* m_criteria1;
	ICriteria* m_criteria2;
};

//具体过滤器:1个或多个过滤器的逻辑与
class CCriteriaAndEx : public ICriteria
{
public:
	explicit CCriteriaAndEx(std::initializer_list<ICriteria*> criteria1s)
		: m_vecCriteria(criteria1s) {}

public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		int index = 0;
		std::vector<CPerson*> andPersons;
		for (auto& it : m_vecCriteria) {
			andPersons = it->doFilter(index == 0 ? persons : andPersons);
			index++;
		}
		return andPersons;
	}
private:
	std::vector<ICriteria*> m_vecCriteria;
};

//具体过滤器:两个过滤器的逻辑或
class CCriteriaOr : public ICriteria
{
public:
	explicit CCriteriaOr(ICriteria* pCriteria1, ICriteria* pCriteria2)
		: m_criteria1(pCriteria1), m_criteria2(pCriteria2) {}

public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		std::vector<CPerson*> orPersons = m_criteria1->doFilter(persons);
		std::vector<CPerson*> orPersons1 = m_criteria2->doFilter(persons);
		for (auto& it : orPersons1) {
			if (std::find_if(orPersons.begin(), orPersons.end(),
				[=](auto& iter) {return it == iter; }) == orPersons.end()) {
				orPersons.push_back(it);
			}
		}
		return orPersons;
	}
private:
	ICriteria* m_criteria1;
	ICriteria* m_criteria2;
};

//CPerson容器包装类
class CPersonContainerWrapper
{
public:
	CPersonContainerWrapper(std::vector<CPerson*>& vecData)
		: m_vecPesons(vecData) {}
public:
	CPersonContainerWrapper& operator|(const std::vector<CPerson*>& others) {
		for (auto& it : others) {
			if (std::find_if(m_vecPesons.begin(), m_vecPesons.end(),
				[=](auto& iter) {return it == iter; }) == m_vecPesons.end()) {
				m_vecPesons.push_back(it);
			}
		}
		return *this;
	}
private:
	std::vector<CPerson*>& m_vecPesons;
};

//具体过滤器:1个或多个过滤器的逻辑或
class CCriteriaOrEx : public ICriteria
{
public:
	explicit CCriteriaOrEx(std::initializer_list<ICriteria*> criteria1s)
		: m_vecCriteria(criteria1s) {}

public:
	std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {
		int index = 0;
		std::vector<CPerson*> orPersons;
		CPersonContainerWrapper wapper(orPersons);

		if (m_vecCriteria.size() <= 0) {
			return persons;
		}

		orPersons = m_vecCriteria[0]->doFilter(persons);
		for (index = 1; index < m_vecCriteria.size(); index++) {
			wapper | m_vecCriteria[index]->doFilter(persons);
		}
		return orPersons;
	}
private:
	std::vector<ICriteria*> m_vecCriteria;
};

#endif

使用不同的标准(Criteria)和它们的结合来过滤CPerson对象的列表,测试代码如下:

#include "FilterMode.h"
static void printPerson(const std::string& tip, std::vector<CPerson*>& persons) {
	qDebug() << tip.data();
	for (auto& it : persons) {
		qDebug() << it->toString().data();
	}
}
void main() {
	std::vector<CPerson*> vecTemp;
	std::vector<CPerson*> vecPersons;
	vecPersons.push_back(new CPerson("liu bin", "male", 39, "benke"));
	vecPersons.push_back(new CPerson("li xiang", "female", 25, "zhuanke"));
	vecPersons.push_back(new CPerson("he nan shan", "male", 44, "boshi"));
	vecPersons.push_back(new CPerson("san ling", "female", 56, "suoshi"));
	vecPersons.push_back(new CPerson("guo dong", "male", 27, "zhuanke"));
	vecPersons.push_back(new CPerson("jing gang shan", "female", 32, "suoshi"));
	vecPersons.push_back(new CPerson("shan shan", "female", 41, "benke"));
	vecPersons.push_back(new CPerson("mei duo", "male", 10, "xiaoxue"));

	ICriteria* pMaleCriteria = new CCriteriaMale();
	ICriteria* pFemaleCriteria = new CCriteriaFemale();
	ICriteria* pAgeCriteria = new CCriteriaAboveAge(26);
	ICriteria* pEduCriteria = new CCriteriaEducation("benke");
	ICriteria* pAndCriteria = new CCriteriaAnd(pMaleCriteria, pEduCriteria);
	ICriteria* pOrCriteria = new CCriteriaOr(pFemaleCriteria, pAgeCriteria);

	ICriteria* pAndCriteriaEx = new CCriteriaAndEx({ pFemaleCriteria, pAgeCriteria, pEduCriteria });
	ICriteria* pOrCriteriaEx = new CCriteriaOrEx({ pMaleCriteria, pFemaleCriteria, pEduCriteria,pAgeCriteria });

	vecTemp = pMaleCriteria->doFilter(vecPersons);
	printPerson("male: ", vecTemp);

	vecTemp = pFemaleCriteria->doFilter(vecPersons);
	printPerson("female: ", vecTemp);

	vecTemp = pAgeCriteria->doFilter(vecPersons);
	printPerson("age>26: ", vecTemp);

	vecTemp = pEduCriteria->doFilter(vecPersons);
	printPerson("benke: ", vecTemp);

	vecTemp = pAndCriteria->doFilter(vecPersons);
	printPerson("benke and male: ", vecTemp);

	vecTemp = pOrCriteria->doFilter(vecPersons);
	printPerson("age>26 or female: ", vecTemp);

	vecTemp = pAndCriteriaEx->doFilter(vecPersons);
	printPerson("age>26 and benke and female: ", vecTemp);

	vecTemp = pOrCriteriaEx->doFilter(vecPersons);
	printPerson("age>26 or benke or male or female: ", vecTemp);

	for (auto& it : vecTemp) {
		delete it;
	}
	delete pMaleCriteria;
	delete pFemaleCriteria;
	delete pAgeCriteria;
	delete pEduCriteria;
	delete pAndCriteria;
	delete pOrCriteria;
	delete pAndCriteriaEx;
	delete pOrCriteriaEx;
}

输出:

male: 
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
[name:mei duo;sex:male;age:10;education:xiaoxue]

female: 
[name:li xiang;sex:female;age:25;education:zhuanke]
[name:san ling;sex:female;age:56;education:suoshi]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]

age>26: 
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:san ling;sex:female;age:56;education:suoshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]

benke: 
[name:liu bin;sex:male;age:39;education:benke]
[name:shan shan;sex:female;age:41;education:benke]

benke and male: 
[name:liu bin;sex:male;age:39;education:benke]

age>26 or female: 
[name:li xiang;sex:female;age:25;education:zhuanke]
[name:san ling;sex:female;age:56;education:suoshi]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:guo dong;sex:male;age:27;education:zhuanke]

age>26 and benke and female: 
[name:shan shan;sex:female;age:41;education:benke]

age>26 or benke or male or female: 
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
[name:mei duo;sex:male;age:10;education:xiaoxue]
[name:li xiang;sex:female;age:25;education:zhuanke]
[name:san ling;sex:female;age:56;education:suoshi]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]

3.过滤器模式的优点

过滤器模式通过提供一种灵活的方式来处理和筛选对象集合,从而提高代码的灵活性和可维护性。

灵活性过滤器模式充许根据不同的过滤条件对请求进行筛选和传递,这意味看你可以轻松地添加、删除或修改过滤器,而无需修改客户端代码,这使得系统更加灵活,能够适应不同的需求和变化。

可扩展性由于过滤器模式是可扩展的,你可以在不影响现有代码的情况下添加新的过滤器,这有助于降低代码的耦合度,提高模块化程度,使代码更易于维护和扩展。

复用性每个过滤器都可以独立地实现其过滤逻辑,这意味着它们是可复用的,你可以在不同的场景下使用相同的过滤器或者将多个过滤器组合在一起以满足更复杂的过滤需求。

解耦通过将过滤逻辑封装在独立的过滤器中,过滤器模式降低了客户端代码与具体过滤逻辑之间的耦合度,这意味看你可以在不改变客户端代码的情况下更改或替换过滤器,提高了  代码的可维护性。

易于测试由于每个过滤器都是独立的,你可以单独测试每个过滤器,确保它们按照预期工作,这有助于提高代码的可测讨性和可维护性。

简化复杂逻辑通过将复杂的筛选逻辑分解为一系列简单的过滤步骤,过滤器模式可以使代码更易于理解和维护,每个过滤器只关注一个特定的筛选条件,从而使代码更加清晰和模块化。

4.过滤器模式的不足

性能问题当数据集合非常大时,大量的迭代运算,过滤器模式可能会降低程序性能。每次过滤都需要遍历整个数据集合,这可能会降低程序的运行效率。

配置复杂性当需要组合多个过滤器时,可能需要编写大量的配置代码,这可能会增加代码的复杂性。

5.适用的场景

1) 数据筛选

在数据处理中,经常需要对大量的数据进行筛选,以满足特定条件。过滤器设计模式可以将这种需求抽象化,通过定义一个过滤器接口,实现不同的筛选逻辑。这种设计模式可以方便地扩展和修改,满足不同的筛选需求。

2) 请求过滤

在Web应用程序中,通常需要对接收到的请求进行筛选和过滤,例如检查用户身份、过滤目的地址请求等。使用过滤器设计模式,可以将请求的筛选逻辑封装在过滤器中,对每个请求进行处理。这种设计模式可以提高代码的可维护性和可扩展性;在这点上由此可以派生出拦截过滤器模式,需要了解的可以点进去看看,在这里就不过多细说了。

3) 事件过滤

在事件驱动的系统中,经常需要对事件进行筛选和过滤。例如,在事件总线中,可能需要对事件进行分类和筛选,以便将事件分发给不同的消费者。过滤器设计模式可以将这种需求抽象化,通过定义一个一致的过滤器接口,实现不司的事件筛选逻辑。

4) 日志过滤

在日志记录中,通常需要对日志消息进行筛选和过滤,以满定不同的需求。例如,可能需要根据志级别、日志内容等信息进行筛选和过滤。过滤器设计模式可以将这种需求抽象化通过定义一个日志过滤器接口,实现不同的日志筛选逻辑。

5) 数据流过滤

在数据处理流中,经常需要对数据进行筛选和过滤。例如,在流处理中,可能需要对数据进行分类、去重、转换等操作。过滤器设计模式可以将这种需求抽象化,通过定义一个数据流过滤器接口,实现不同的数据筛选逻辑。这种设计模式可以提高数据处理流的灵活性和可抗展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1361840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态代理还是动态代理?来聊聊Java中的代理设计模式

代理模式&#xff08;Proxy Design Pattern&#xff09;是一种结构型设计模式&#xff0c;为一个对象提供一个代理对象&#xff0c;然后使用代理对象控制对原对象的引用。即通过代理对象访问目标对象。被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。 一、…

JavaWeb——新闻管理系统(Jsp+Servlet)之jsp新闻查询

java-ee项目结构设计 1.dao:对数据库的访问&#xff0c;实现了增删改查 2.entity:定义了新闻、评论、用户三个实体&#xff0c;并设置对应实体的属性 3.filter&#xff1a;过滤器&#xff0c;设置字符编码都为utf8&#xff0c;防止乱码出现 4.service:业务逻辑处理 5.servlet:处…

Spring AI和Ollama

概述 Spring AI 不仅提供了与 OpenAI 进行API交互&#xff0c;同样支持与 Ollama 进行API交互。Ollama 是一个发布在GitHub上的项目&#xff0c;专为运行、创建和分享大型语言模型而设计&#xff0c;可以轻松地在本地启动和运行大型语言模型。 Docker环境安装Ollama 1.获取D…

第13课 利用openCV检测物体是否运动了

FFmpeg与openCV绝对是绝配。前面我们已经基本熟悉了FFmpeg的工作流程&#xff0c;这一章我们重点来看看openCV。 在前面&#xff0c;我们已经使用openCV打开过摄像头并在MFC中显示图像&#xff0c;但openCV能做的要远超你的想像&#xff0c;比如可以用它来实现人脸检测、车牌识…

个人笔记:分布式大数据技术原理(一)Hadoop 框架

Apache Hadoop 软件库是一个框架&#xff0c;它允许使用简单的编程模型&#xff0c;实现跨计算机集群的大型数据集的分布式处理。它最初的设计目的是为了检测和处理应用程序层的故障&#xff0c;从单个机器扩展到数千台机器&#xff08;这些机器可以是廉价的&#xff09;&#…

算法通关村第二十关-黄金挑战图的常见算法

大家好我是苏麟 , 今天聊聊图的常见算法 . 图里的算法是很多的&#xff0c;这里我们介绍一些常见的图算法。这些算法一般都比较复杂&#xff0c;我们这里介绍这些算法的基本含义&#xff0c;适合面试的时候装*&#xff0c;如果手写&#xff0c;那就不用啦。 图分析算法&#xf…

Qt/QML编程学习之心得:Timer的使用(22)

Qt中timer计时器如何使用? Timer的创建: void InitTimer(){myTimer = new QTimer(q);myTimer->setInterval(100); // 100msmyTimer->setSingleShot(true); //只运行一次的计时器QObject::connect(myTimer,SIGNAL(timeout()),q,SLOT(onTimeOut()));myTimer->start(…

(2023|NIPS,邻域分布预测,Wasserstein 距离)通过上下文预测改进基于扩散的图像合成

Improving Diffusion-Based Image Synthesis with Context Prediction 公和众和号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 3. 基础 4. ConPreDiff 4.1 扩散生成中的邻域上下…

Linux入门攻坚——11、Linux网络属性配置相关知识1

网络基础知识&#xff1a; 局域网&#xff1a;以太网&#xff0c;令牌环网&#xff0c; Ethernet&#xff1a;CSMA/CD 冲突域 广播域 MAC&#xff1a;Media Access Control&#xff0c;共48bit&#xff0c;前24bit需要机构分配&#xff0c;后24bit自己…

安装阿里云CLI之配置阿里云凭证信息

有时候需要再主机上通过 OpenAPI 的调用访问阿里云&#xff0c;并完成控制&#xff0c;此时就需要在服务器上安装阿里云CLI&#xff0c;并完成账号的设置。 1. 登录阿里云创建账号 1.1 点击阿里云头像 ——》 控制访问 ——》创建一个拥有DNS权限的用户 这个用户不用太多权限…

Service Weaver:Google开源基于分布式应用程序开发的框架,重新定义微服务边界

大家好&#xff0c;我是萧楚河&#xff0c;公众号&#xff1a;golang面试经典讲解&#xff0c;感谢关注&#xff0c;一起学习一起成长。一、前言 今年6月&#xff0c;一群谷歌员工&#xff08;由谷歌软件工程师Michael Whittaker领导&#xff09;发表了一篇名为“Towards Mode…

对接第三方接口鉴权(Spring Boot+Aop+注解实现Api接口签名验证)

前言 一个web系统&#xff0c;从接口的使用范围也可以分为对内和对外两种&#xff0c;对内的接口主要限于一些我们内部系统的调用&#xff0c;多是通过内网进行调用&#xff0c;往往不用考虑太复杂的鉴权操作。但是&#xff0c;对于对外的接口&#xff0c;我们就不得不重视这个…

MySQL--基础篇

这里写目录标题 总览MySQl各个阶段基础篇总览 MySQL概述数据库相关概念查看本机MySQL版本号启停mysql打开windows服务管理windows命令行启停 连接mysql客户端mysql运行逻辑数据模型关系型数据库 总结 SQL总览SQL通用语法SQL语句分类DDL数据库操作表操作查询表创建表结构数据类型…

有什么安全处理方案可以有效防护恶意爬虫

常见的爬虫 有百度爬虫、谷歌爬虫、必应爬虫等搜索引擎类爬虫&#xff0c;此类爬虫经常被企业用于提高站点在搜索引擎内的自然排名&#xff0c;使得站点在各大搜索引擎中的排名能够提高&#xff0c;进一步通过搜索引擎来进行引流为企业增加业务流量。 恶意爬虫与合法、合规的搜…

看了致远OA的表单设计后的思考

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

微信小程序的驾校预约管理系统

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1课题背景 在I…

【教学类-43-16】 20240106 推算5-9宫格数独可能出现的不重复题量(N宫格数独模板数量的推算)

作品展示&#xff1a; 通过对各种已有结果的人工推算&#xff0c;目前得到两个结论 一、阶乘基本样式的数量【【123】【321】【231】【132】【312】【312】】6组 结论&#xff1a;阶乘等于出现的基本样式数量 以下N*N格会出现的最大排序数量&#xff08;比如包含333222111这种…

Spring声明式事务业务bug

Spring 针对 Java Transaction API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA) 等事务 API&#xff0c;实现了一致的编程模型&#xff0c;而 Spring 的声明式事务功能更是提供了极其方便的事务配置方式&#xff0c;配合 Spring Boot 的自动配置&#xff0c;大多数 …

C++ 二进制图片的读取和blob插入mysql_stmt_init—新年第一课

关于二进制图片的读取和BLOB插入一共包含五步 第一步&#xff1a;初始化 MYSQL_STMT* stmt mysql_stmt_init(&mysql); 第二步&#xff1a;预处理sql语句 mysql_stmt_prepare(stmt,sql,sqllen); 第三步&#xff1a;绑定字段 mysql_stmt_bind_param(stmt,bind); 第四…

用友U8+CRM 逻辑漏洞登录后台漏洞复现

0x01 产品简介 用友U8 CRM客户关系管理系统是一款专业的企业级CRM软件&#xff0c;旨在帮助企业高效管理客户关系、提升销售业绩和提供优质的客户服务。 0x02 漏洞概述 用友 U8 CRM客户关系管理系统 reservationcomplete.php文件存在逻辑漏洞&#xff0c;未授权的攻击者通过…