前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[UPDATE语句结合WHERE EXIS...]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...vely, use UPDATE and FLUSH PRIVILEGES: mysql> UPDATE mysql.user SET Password = OLD_PASSWORD('newpwd') -> WHERE Host = 'some_host' AND User = 'some_user';mysql> FLUSH PRIVILEGES; Substitute the password you want to use for newpwd'' in the preceding examples. MySQL cannot tell you what the original password was, so you'll need to pick a new one. Tell the server to use the older password hashing algorithm: Start mysqld with the --old-passwords option. Assign an old-format password to each account that has had its password updated to the longer 4.1 format. You can identify these accounts with the following query: mysql> SELECT Host, User, Password FROM mysql.user -> WHERE LENGTH(Password) > 16; For each account record displayed by the query, use the Host and User values and assign a password using the OLD_PASSWORD() function and either SET PASSWORD or UPDATE, as described earlier. For additional background on password hashing and authentication, see section 5.5.9 Password Hashing in MySQL 4.1. 例子: SET PASSWORD FOR 用户名@localhost = OLD_PASSWORD('密码'); 欢迎大家阅读《MYSQL 新版出现" Client does_mysql》,跪求各位点评,若觉得好的话请收藏本文,by 搞代码 微信 赏一包辣条吧~ 支付宝 赏一听可乐吧~ 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_29363791/article/details/114779150。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-17 19:43:27
105
转载
Struts2
... 2. 问题概述 在使用Struts2框架进行Web开发的过程中,当你试图访问某个Action对应的URL时,若服务器返回了上述错误信息,那么很可能是由于Struts2未能正确地找到并解析到对应的Action资源。用大白话来说,这句话对程序员朋友解释就是:“嘿兄弟,我在你给我的这片代码江湖里,愣是没找到你要我搞定的那个请求路径咧。” 3. 错误原因深度解读 (1)配置问题:这是最常见的原因之一。在Struts2中,我们可以采用XML文件或者注解的方式来给程序做设置。设想一下这个场景哈,如果我们马虎大意,在struts.xml这个配置文件里没有把Action映射正确地写出来,或者是在使用注解配置时搞错了,那么Struts2里面那个核心的“快递员”——DispatcherServlet就没法找到对应能处理请求的Action了。这时候,它可就懵圈了,只能抛出一个异常来表达它的无奈和困惑。 xml /invalid.jsp (2)资源路径问题:当请求被成功路由到Action后,如果你在Action中返回了一个无效的结果路径,也会导致此问题。例如,你可能在结果类型中指定了一个不存在的视图页面。 java // 示例:错误的Action类方法 public String execute() { // ...业务逻辑... return "nonExistentView"; // 这个结果名称在struts.xml中没有对应的有效结果路径 } 4. 解决方案及实战演练 (1)检查Action配置:首先,我们需要核实struts.xml中Action的配置是否正确,包括Action的name属性是否与请求URL匹配,class属性指向的类是否存在且路径正确。 (2)验证结果路径:其次,确认Action执行方法返回的结果字符串所对应的结果路径是否存在。例如: xml /WEB-INF/pages/success.jsp /WEB-INF/pages/exists.jsp (3)排查其他可能性:除此之外,还需注意过滤器链的配置是否合理,避免请求在到达Struts2核心过滤器前就被拦截或处理;同时,也要关注项目部署环境,确认资源文件是否已正确部署至服务器。 5. 结语 面对“Requested resource /resourcePath is not available”的困扰,就像我们在探险过程中遭遇了一道看似无解的谜题。但是,只要我们像侦探破案那样,耐心又细致地把问题揪出来,一步步审查各个环节,早晚能揭开迷雾,让Struts2重新焕发活力,流畅地为我们工作。毕竟,编程的乐趣不仅在于解决问题,更在于那份抽丝剥茧、寻根问底的过程。让我们共同携手,在Struts2的世界里,尽情挥洒智慧与热情吧!
2024-01-24 17:26:04
169
清风徐来
Java
... try { // 使用SHA1算法生成签名 MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(stringToSign.getBytes("UTF-8")); byte[] signatureBytes = crypt.digest(); // 将签名转换为小写的十六进制字符串 Formatter formatter = new Formatter(); for (byte b : signatureBytes) { formatter.format("%02x", b); } String signature = formatter.toString(); formatter.close(); return signature; } catch (Exception e) { throw new RuntimeException("Failed to generate signature: " + e.getMessage()); } } // 设置各个参与签名的字段值的方法省略... } 这段代码中,我们定义了一个WxJsSdkSignatureGenerator类,用于生成微信JS-SDK所需的签名。嘿,重点来了啊,首先你得按照规定的步骤和格式,把待签名的字符串像拼图一样拼接好,然后再用SHA1这个加密算法给它“上个锁”,就明白了吧? 4. 签名问题排查锦囊 --- 当你仍然遭遇“invalid signature”问题时,不妨按以下步骤逐一排查: - 检查时间戳是否同步:确保服务器和客户端的时间差在允许范围内。 - 确认jsapi_ticket的有效性:jsapi_ticket过期或获取有误也会导致签名无效。 - URL编码问题:在计算签名前,务必确保url已正确编码且前后端URL保持一致。 - 签名字段排序问题:严格按照规定顺序拼接签名字符串。 5. 结语 --- 面对“wx.config:invalid signature”的困扰,作为Java开发者,我们需要深入了解微信JS-SDK的签名机制,并通过严谨的编程实现和细致的调试,才能妥善解决这一问题。记住,每一个错误提示都是通往解决问题的线索,而每一步的探索过程,都饱含着我们作为程序员的独特思考和情感投入。只有这样,我们才能在技术的世界里披荆斩棘,不断前行。
2023-09-10 15:26:34
315
人生如戏_
转载文章
...。通过学习如何创建和使用virtualenv或Anaconda的conda环境,您可以在同一系统上为每个项目轻松配置独立的Python版本。 最新资讯:Python官方已推荐使用python -m venv命令创建虚拟环境,取代了原先的virtualenv工具,以更好地整合到标准库中,提供更原生的支持。 2. Python包管理器pip的高级用法:掌握pip的最新功能如缓存加速下载、依赖解析优化以及如何锁定依赖版本等,可以有效提高Python项目的部署效率和稳定性。 实时动态:随着Python 3.7及更高版本的发布,pip也持续迭代更新,引入了诸如pip-tools这样的辅助工具,用于生成精确的requirements文件,确保项目在任何环境下都能获得一致的依赖包版本。 3. 系统服务对Python版本的依赖处理:在Linux系统中,除yum外,还有许多服务和程序可能依赖于特定版本的Python。了解如何查询和适配这些服务的Python版本需求,并结合 alternatives 或 update-alternatives 等系统工具进行版本切换,对于运维工作至关重要。 实例分享:在最新的Fedora CoreOS和Ubuntu Server发行版中,开发者已经开始采用systemd单元文件中的执行路径指向特定Python版本,从而实现了更加灵活的服务管理。 4. Python 2向Python 3迁移的最佳实践:尽管本文介绍了如何在CentOS 7中并存Python 2.7和Python 3.7,但在实际应用中,最终目标往往是全面迁移到Python 3。阅读关于代码迁移、兼容性问题解决、以及利用2to3工具进行自动化转换的教程和案例,将有助于您的项目平滑过渡。 综上所述,随着Python生态的不断演进,理解和掌握Python版本管理、虚拟环境运用以及服务依赖关系,将成为现代开发运维工程师必备技能之一。同时,密切关注Python社区发布的最新资源和指南,能帮助您紧跟技术潮流,确保系统和应用始终保持最佳状态。
2023-03-23 10:44:41
284
转载
Apache Lucene
...entAlreadyExistsException:深入理解与实践 1. 引言 Apache Lucene,作为一款强大的全文搜索引擎库,以其卓越的性能和灵活性赢得了广大开发者们的青睐。然而,在实际开发过程中,我们可能会遇到一个特定的异常——DocumentAlreadyExistsException。当你尝试往索引里塞一个已经存在的文档时,系统就会抛出这个异常。这篇内容会手把手带你“穿越”到这个异常的背后,探寻它产生的真正原因,并且,咱们还会通过一些实际的代码例子,一起研究下到底如何巧妙地应对这种状况。 2. DocumentAlreadyExistsException的理解 在Lucene的世界里,每个文档都有其独一无二的标识符——document id。当我们试图使用相同的document id创建并添加一个新的文档到索引时,DocumentAlreadyExistsException就会闪亮登场。这是因为Lucene这个家伙,为了确保索引数据的整齐划一、滴水不漏,坚决不让两个相同ID的文档同时存在于它的数据库里。就像是图书管理员坚决不让两本同书名、同作者的书籍混进同一个书架一样,它对索引数据的一致性和完整性要求可是相当严格的呢! java // 创建一个新的文档 Document doc = new Document(); doc.add(new StringField("id", "123", Field.Store.YES)); doc.add(new TextField("content", "This is a sample document.", Field.Store.YES)); // 尝试将文档添加到索引(假设索引中已有id为"123"的文档) IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig()); try { writer.addDocument(doc); } catch (DocumentAlreadyExistsException e) { System.out.println("Oops! A document with the same ID already exists."); // 这里是异常处理逻辑... } 3. 遇到DocumentAlreadyExistsException时的思考过程 首先,当此异常出现时,我们应当反思一下业务逻辑。是不是有用户不小心手滑了,或者咱们的系统设计上有个小bug,让一份文档被多次抓取进了索引里?要是真有这样的情况,那我们得在最上面的应用层好好瞅瞅,做点相应的检查和优化工作,确保同样的内容不会被反复提交上去。 其次,如果确实有更新文档的需求,而不是简单地添加新的文档,那么应该采用IndexWriter.updateDocument()方法替换原有的文档,而非addDocument(): java Term term = new Term("id", "123"); writer.updateDocument(term, updatedDoc); // 更新已存在的文档 最后,对于一些需要保证唯一性的场景,例如日志记录、订单编号等,可以考虑在索引建立阶段就设置IndexWriterConfig.setMergePolicy(NoDuplicatesMergePolicy.INSTANCE),从而避免因并发写入导致的重复文档问题。 4. 深入探讨与应对策略 在实践中,处理DocumentAlreadyExistsException不仅关乎对Lucene机制的理解,更需要结合具体应用场景来制定解决方案。比如,我们可以设想这样一种方案:定制一个独特的错误处理机制,这样一来,只要系统一检测到这个异常情况,就会自动启动文档内容合并流程,或者更贴心地告诉你,哎呀,这份文档已经存在了,需要你提供一个新的文档编号。 此外,对于高并发环境下的索引更新,除了利用Lucene提供的API外,还需要引入适当的并发控制策略,如乐观锁、分布式锁等,确保在多线程环境下,也能正确无误地处理文档添加与更新操作。 总结起来,DocumentAlreadyExistsException在Apache Lucene中扮演着守护者角色,提醒我们在构建高效、精准的全文搜索服务的同时,也要注意维护数据的一致性与完整性。如果咱们能全面摸清这个异常状况,并且妥善应对处理,那么咱们的应用程序就会变得更皮实耐造,这样一来,用户体验也绝对会蹭蹭地往上提升,变得超赞!
2023-01-30 18:34:51
458
昨夜星辰昨夜风
ZooKeeper
...:ZooKeeper使用ZAB协议(ZooKeeper Atomic Broadcast)保证了数据的一致性,这意味着所有客户端看到的数据视图都是最新的,并且是全局一致的。 (2)临时节点与监听器:ZooKeeper支持创建临时节点,当创建节点的客户端会话断开时,该节点会自动删除。同时呢,ZooKeeper这个小家伙还支持客户端给任何一个节点挂上Watcher监听器,这样一来,一旦这个节点状态有啥风吹草动,嘿,ZooKeeper可就立马通知所有对这个节点保持关注的客户端们了。 这些特性使得ZooKeeper成为分布式任务调度的理想选择,任务可以以临时节点的形式存在,而任务调度器通过监听节点变化来实时获取并分配任务。 3. 使用ZooKeeper实现分布式任务调度 3.1 创建任务队列 首先,我们可以利用ZooKeeper创建一个持久化或临时的ZNode作为任务队列。例如: java ZooKeeper zk = new ZooKeeper("zk_server:port", sessionTimeout, this); String taskQueuePath = "/task_queue"; zk.create(taskQueuePath, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 3.2 添加任务 当有新的任务需要调度时,将其转化为JSON格式或其他可序列化的形式,然后作为子节点添加到任务队列中,创建为临时有序节点: java String taskId = "task_001"; byte[] taskData = serializeTask(new TaskInfo(...)); // 序列化任务信息 String taskPath = taskQueuePath + "/" + taskId; zk.create(taskPath, taskData, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); 3.3 监听任务节点变化 任务调度器在启动时,会在任务队列节点上设置一个Watcher监听器,当有新任务加入或者已有任务完成(节点被删除)时,都能收到通知: java zk.exists(taskQueuePath, new Watcher() { @Override public void process(WatchedEvent event) { if (event.getType() == EventType.NodeChildrenChanged) { List tasks = zk.getChildren(taskQueuePath, true); // 获取当前待处理的任务列表 // 根据任务优先级、顺序等策略,从tasks中选取一个任务进行调度 } } }); 3.4 分配与执行任务 根据监听到的任务列表,任务调度器会选择合适的任务分配给空闲的工作节点。工作节点接收到任务后,开始执行任务,并在完成后删除对应的ZooKeeper节点。 这样,通过ZooKeeper的协助,我们成功实现了分布式任务调度系统的构建。每个步骤都超级灵活、充满活力,能像变形金刚那样,随着集群的大小变化或者任务需求的起起伏伏,始终保持超高的适应能力和稳定性,妥妥地hold住全场。 4. 总结与探讨 ZooKeeper以其强大的协调能力,让我们得以轻松应对复杂的分布式任务调度场景。不过在实际动手操作的时候,咱们还得多琢磨琢磨怎么对付错误、咋整并发控制这些事儿,这样才能让调度的效率和效果噌噌往上涨,达到更理想的优化状态。另外,面对不同的业务应用场景,我们可能需要量身定制任务分配的策略。这就意味着,首先咱们得把ZooKeeper摸透、吃熟,然后结合实际业务的具体逻辑,进行一番深度的琢磨和探究,这样才能玩转起来!就像冒险家在一片神秘莫测的丛林里找寻出路,我们也是手握ZooKeeper这个强大的指南针,在分布式任务调度这片“丛林”中不断尝试、摸爬滚打,努力让我们的解决方案更加完善、无懈可击。
2023-04-06 14:06:25
53
星辰大海
ZooKeeper
...式锁来确保资源的正确使用。 4.1 分布式锁的实现 java import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; public class DistributedLock { private ZooKeeper zookeeper; private String lockPath; public DistributedLock(ZooKeeper zookeeper, String lockPath) { this.zookeeper = zookeeper; this.lockPath = lockPath; } public void acquireLock() throws Exception { // 创建临时顺序节点 String lockNode = zookeeper.create(lockPath + "/lock-", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("Created lock node: " + lockNode); // 获取所有子节点并排序 List children = zookeeper.getChildren(lockPath, false); Collections.sort(children); // 检查是否为最小节点,如果是则获取锁 if (children.get(0).equals(lockNode.substring(lockPath.length() + 1))) { System.out.println("Acquired lock"); return; } // 否则,等待前一个节点释放锁 String previousNode = children.get(Collections.binarySearch(children, lockNode.substring(lockPath.length() + 1)) - 1); System.out.println("Waiting for lock node: " + previousNode); zookeeper.exists(lockPath + "/" + previousNode, true); } public void releaseLock() throws Exception { // 删除临时节点 zookeeper.delete(lockPath + "/" + lockNode.substring(lockPath.length() + 1), -1); } } 这个简单的实现展示了如何使用ZooKeeper来创建临时顺序节点,并通过监听前一个节点的状态变化来实现分布式锁的功能。在这过程中,我们不仅学会了怎么用ZooKeeper的基本功能,还感受到了它在实际操作中到底有多牛掰。 5. 实践案例二 配置中心 接下来,我们来看看另一个常见的应用场景——配置中心。在大型系统中,配置管理往往是一项繁琐而重要的工作。而ZooKeeper正好为我们提供了一个理想的解决方案。 5.1 配置中心的实现 假设我们有一个配置文件,其中包含了一些关键的配置信息,例如数据库连接字符串、日志级别等。我们可以把配置信息存到ZooKeeper里,然后用监听器让各个节点实时更新,这样就省心多了。 java import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; public class ConfigCenter implements Watcher { private ZooKeeper zookeeper; private String configPath; public ConfigCenter(ZooKeeper zookeeper, String configPath) { this.zookeeper = zookeeper; this.configPath = configPath; } public void start() throws Exception { // 监听配置节点 zookeeper.exists(configPath, this); } @Override public void process(WatchedEvent event) { if (event.getType() == Event.EventType.NodeDataChanged) { try { byte[] data = zookeeper.getData(configPath, this, null); String config = new String(data, "UTF-8"); System.out.println("New configuration: " + config); } catch (Exception e) { e.printStackTrace(); } } } } 这段代码展示了如何创建一个配置中心,通过监听配置节点的变化来实时更新配置信息。这种机制不仅提高了系统的灵活性,也大大简化了配置管理的工作量。 6. 总结与展望 通过上面两个具体的案例,我们看到了ZooKeeper在实际项目中的广泛应用。无论是分布式锁还是配置中心,ZooKeeper都能为我们提供稳定可靠的支持。当然,ZooKeeper还有许多其他强大的功能等待我们去发掘。希望大家在今后的工作中也能多多尝试使用ZooKeeper,相信它一定能给我们的开发带来意想不到的帮助! --- 希望这篇文章能让你对ZooKeeper有更深刻的理解,并激发你进一步探索的兴趣。如果你有任何问题或者想了解更多细节,请随时留言交流!
2025-02-11 15:58:01
39
心灵驿站
转载文章
...套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包 def outer(logo):def inner(msg):print(f"{logo}:{msg}")return innerfun = outer("java")fun("hello world") 闭包修改外部函数的值 需要用 nonlocal 声明这个外部变量 def outer(num1):def inner(num2):nonlocal num1num1 += num2print(num1)return innerfun = outer(10)fun(10) 输出20 优点: 无需定义全局变量即可实现通过函数,持续的访问、修改某个值 闭包使用的变量的所用于在函数内,难以被错误的调用修改 缺点: 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存 装饰器 装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能 def outer(func):def inner():print("我要睡觉了")func()print("我起床了")return inner@outerdef sleep():print("睡眠中")sleep() 单例模式 单例def strTool():passsignle = strTool()==from 单例 import signlet1 = signlet2 = signleprint(id(t1))print(id(t2)) 工厂模式 将对象的创建由使用原生类本身创建转换到由特定的工厂方法来创建 好处: 大批量创建对象的时候有统一的入口,易于代码维护 当发生修改,仅修改工厂类的创建方法即可 class Person:passclass Worker(Person):passclass Student(Person):passclass Teacher(Person):passclass PersonFactory:def get_person(self,p_type):if p_type == 'w':return Worker()elif p_type == 's':return Student()else:return Teacher()pf = PersonFactory()worker = pf.get_person('w')student = pf.get_person('s')teacher = pf.get_person('t') 多线程 threading模块使用 import threadingimport timedef sing(msg):print(msg)time.sleep(1)def dance(msg):print(msg)time.sleep(1)if __name__ == '__main__':sing_thread = threading.Thread(target=sing,args=("唱歌。。。",))dance_thread = threading.Thread(target=dance,kwargs={"msg":"跳舞。。。"})sing_thread.start()dance_thread.start() Socket Socket(套接字)是进程间通信工具 服务端 创建Socket对象import socketsocket_server = socket.socket() 绑定IP地址和端口socket_server.bind(("localhost", 8888)) 监听端口socket_server.listen(1) 等待客户端链接conn, address =socket_server.accept()print(f"接收到客户端的信息{address}")while True:data: str = conn.recv(1024).decode("UTF-8")print(f"客户端消息{data}") 发送回复消息msg = input("输入回复消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8")) 关闭连接conn.close()socket_server.close() 客户端、 import socket 创建socket对象socket_client = socket.socket() 连接到服务器socket_client.connect(("localhost", 8888))while True:msg = input("输入发送消息:")if(msg == 'exit'):break 发送消息socket_client.send(msg.encode("UTF-8"))接收返回消息recv_data = socket_client.recv(1024)print(f"服务端回复消息:{recv_data.decode('UTF-8')}") 关闭链接socket_client.close() 正则表达式使用 import res = "pythonxxxxxxpython"result = re.match("python",s) 从左到右匹配print(result) <re.Match object; span=(0, 6), match='python'>print(result.span()) (0, 6)print(result.group()) pythonresult = re.search("python",s) 匹配到第一个print(result) <re.Match object; span=(0, 6), match='python'>result = re.findall("python",s) 匹配全部print(result) ['python', 'python'] 单字符匹配 数量匹配 边界匹配 分组匹配 pattern = "1[35678]\d{9}"phoneStr = "15288888888"result = re.match(pattern, phoneStr)print(result) <re.Match object; span=(0, 11), match='15288888888'> 递归 递归显示目录中文件 import osdef get_files_recursion_dir(path):file_list = []if os.path.exists(path):for f in os.listdir(path):new_path = path + "/" + fif os.path.isdir(new_path):file_list += get_files_recursion_dir(new_path)else:file_list.append(new_path)else:print(f"指定的目录{path},不存在")return []return file_listif __name__ == '__main__':print(get_files_recursion_dir("D:\test")) 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_29385297/article/details/128085103。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-28 18:35:16
90
转载
Etcd
如何使用Etcd进行分布式事务管理? 1. 初识Etcd 为什么我们需要它? 兄弟们,说到分布式系统,大家是不是都有一种既爱又恨的感觉?爱的是它可以扩展到成千上万台机器,恨的是它的复杂性简直让人头大。尤其是当你需要处理分布式事务的时候,简直就是噩梦! 所以,今天咱们聊聊一个神器——Etcd。它是啥呢?简单说,Etcd就是一个分布式的键值存储系统,可以用来保存各种配置信息、状态数据或者元数据。更重要的是,它支持分布式锁、事件通知、一致性协议(Raft),简直是分布式事务管理的好帮手! 不过在开始之前,我想问问你们:有没有想过为什么分布式事务这么难搞? 思考一下: - 如果两个节点同时修改同一个资源怎么办? - 数据怎么保证一致性? - 怎么避免死锁? 这些问题都是痛点啊!而Etcd通过一些机制,比如分布式锁和事务操作,可以很好地解决这些问题。接下来,咱们就一步步看看怎么用它来搞定分布式事务。 --- 2. Etcd的基本概念 锁、事务、观察者 首先,咱们得了解几个核心概念,不然看代码的时候会懵圈的。 2.1 分布式锁 分布式锁的核心思想就是:多个节点共享同一把锁,谁抢到这把锁,谁就能执行关键逻辑。Etcd提供了lease(租约)功能,用来模拟分布式锁。 举个栗子: python import etcd3 client = etcd3.client(host='localhost', port=2379) 创建一个租约,有效期为5秒 lease = client.lease(5) 给某个key加上这个租约 client.put(key='/my-lock', value='locked', lease=lease) 这段代码的意思是:我给/my-lock这个key绑定了一个5秒的租约。只要这个key存在,别的节点就不能再获取这把锁了。如果租约过期了,锁也就自动释放了。 2.2 事务操作 Etcd支持原子性的事务操作,也就是要么全部成功,要么全部失败。这种特性非常适合用来保证分布式事务的一致性。 比如,我们想做一个转账操作: python 检查账户A是否有足够的余额 如果余额足够,扣掉金额并增加到账户B success, _ = client.transaction( compare=[ client.transactions.version('/account/A') > 0, client.transactions.value('/account/A') >= '100' ], success=[ client.transactions.put('/account/A', '50'), client.transactions.put('/account/B', '100') ], failure=[] ) if success: print("Transaction succeeded!") else: print("Transaction failed.") 这里咱们用transaction()方法定义了一个事务,先检查账户A的余额是否大于等于100,如果是的话,就把钱从A转到B。整个过程啊,要么全都搞定,要么就啥也不干,这不就是分布式事务最理想的状态嘛! 2.3 观察者模式 Etcd还有一个很酷的功能叫观察者模式,你可以监听某个key的变化,并实时做出反应。这对于监控系统状态或者触发某些事件非常有用。 比如: python for event in client.watch('/my-key'): print(event) 这段代码会一直监听/my-key的变化,一旦有更新就会打印出来。 --- 3. 实战演练 用Etcd实现分布式事务 现在咱们来实战一下,看看怎么用Etcd搞定分布式事务。假设我们要实现一个简单的库存管理系统。 3.1 场景描述 假设我们有两个服务A和服务B,服务A负责扣减库存,服务B负责记录日志。要让这两个步骤像一个整体似的,中间不能出岔子,那我们就得靠Etcd来管着分布式锁和事务了。 3.2 代码实现 Step 1: 初始化Etcd客户端 python import etcd3 client = etcd3.client(host='localhost', port=2379) Step 2: 获取分布式锁 python 创建一个租约,有效期为10秒 lease = client.lease(10) 尝试获取锁 lock_key = '/inventory-lock' try: lock_result = client.put(lock_key, 'locked', lease=lease) print("Lock acquired!") except Exception as e: print(f"Failed to acquire lock: {e}") Step 3: 执行事务操作 python 假设当前库存是100件 stock_key = '/inventory' current_stock = int(client.get(stock_key)[0].decode('utf-8')) if current_stock >= 10: 开始事务 success, _ = client.transaction( compare=[ client.transactions.version(stock_key) == current_stock ], success=[ client.transactions.put(stock_key, str(current_stock - 10)) ], failure=[] ) if success: print("Inventory updated successfully!") else: print("Failed to update inventory due to race condition.") else: print("Not enough stock available.") Step 4: 释放锁 python 租约到期后自动释放锁 lease.revoke() print("Lock released.") --- 4. 总结与展望 写到这里,我觉得咱们已经掌握了如何用Etcd来进行分布式事务管理。其实啊,事情没那么吓人!别看整个流程听着挺绕的,但只要你把分布式锁、事务操作还有观察者模式这些“法宝”都搞明白了,不管啥情况都能游刃有余地搞定,妥妥的! 不过,我也想提醒大家,分布式事务并不是万能药。有时候,过度依赖分布式事务反而会让系统变得更加复杂。所以,在实际开发中,我们需要根据业务需求权衡利弊。 最后,希望大家都能用好Etcd这个利器,让自己的分布式系统更加健壮和高效!如果你还有其他问题,欢迎随时来找我讨论,咱们一起进步!
2025-03-21 15:52:27
54
凌波微步
Beego
...在你的控制器中引入并使用jwt-go库: go package main import ( "github.com/dgrijalva/jwt-go" "github.com/beego/beego/v2/client/orm" "net/http" ) // 创建JWT密钥 var jwtKey = []byte("your-secret-key") type User struct { Id int64 orm:"column(id);pk" Name string orm:"column(name)" } func main() { // 初始化ORM orm.RegisterModel(new(User)) // 示例:创建用户并生成JWT令牌 user := &User{Name: "John Doe"} err := orm.Insert(user) if err != nil { panic(err) } token, err := createToken(user.Id) if err != nil { panic(err) } http.HandleFunc("/login", func(w http.ResponseWriter, r http.Request) { w.Write([]byte(token)) }) http.ListenAndServe(":8080", nil) } func createToken(userId int64) (string, error) { claims := jwt.StandardClaims{ Issuer: "YourApp", ExpiresAt: time.Now().Add(time.Hour 24).Unix(), Subject: userId, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtKey) } 2. JWT验证与解码 在用户请求资源时,我们需要验证JWT的有效性。Beego框架允许我们通过中间件轻松地实现这一功能: go func authMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r http.Request) { tokenHeader := r.Header.Get("Authorization") if tokenHeader == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } tokenStr := strings.Replace(tokenHeader, "Bearer ", "", 1) token, err := jwt.Parse(tokenStr, func(token jwt.Token) (interface{}, error) { if _, ok := token.Method.(jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return jwtKey, nil }) if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } if !token.Valid { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } next.ServeHTTP(w, r) } } http.HandleFunc("/protected", authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r http.Request) { claims := token.Claims.(jwt.MapClaims) userID := int(claims["subject"].(float64)) // 根据UserID获取用户信息或其他操作... }))) 3. 刷新令牌与过期处理 为了提高用户体验并减少用户在频繁登录的情况下的不便,可以实现一个令牌刷新机制。当JWT过期时,用户可以发送请求以获取新的令牌。这通常涉及到更新JWT的ExpiresAt字段,并相应地更新数据库中的记录。 go func refreshToken(w http.ResponseWriter, r http.Request) { claims := token.Claims.(jwt.MapClaims) userID := int(claims["subject"].(float64)) // 更新数据库中的用户信息以延长有效期 err := orm.Update(&User{Id: userID}, "expires_at = ?", time.Now().Add(time.Hour24)) if err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } newToken, err := createToken(userID) if err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Write([]byte(newToken)) } 4. 总结与展望 通过上述步骤,我们不仅实现了JWT在Beego框架下的集成与管理,还探讨了其在实际应用中的实用性和灵活性。JWT令牌的生命周期管理对于增强Web应用的安全性和用户体验至关重要。哎呀,你懂的,就是说啊,咱们程序员小伙伴们要是能不断深入研究密码学这门学问,然后老老实实地跟着那些最佳做法走,那在面对各种安全问题的时候就轻松多了,咱开发出来的系统自然就又稳当又高效啦!就像是有了金刚钻,再硬的活儿都能干得溜溜的! 在未来的开发中,持续关注安全漏洞和最佳实践,不断优化和升级JWT的实现策略,将有助于进一步提升应用的安全性和性能。哎呀,随着科技这玩意儿越来越发达,咱们得留意一些新的认证方式啦。比如说 OAuth 2.0 啊,这种东西挺适合用在各种不同的场合和面对各种变化的需求时。你想想,就像咱们出门逛街,有时候用钱包,有时候用手机支付,对吧?认证机制也一样,得根据不同的情况选择最合适的方法,这样才能更灵活地应对各种挑战。所以,探索并尝试使用 OAuth 2.0 这类工具,让咱们的技术应用更加多样化和适应性强,听起来挺不错的嘛!
2024-10-15 16:05:11
70
风中飘零
Consul
... go // 使用Consul的Go客户端存储键值对 package main import ( "fmt" "github.com/hashicorp/consul/api" ) func main() { config := api.DefaultConfig() config.Address = "localhost:8500" client, err := api.NewClient(config) if err != nil { panic(err) } // 存储键值对 _, _, err = client.KV().Put(&api.KVPair{ Key: "myapp/config/db_url", Value: []byte("postgresql://localhost:5432/mydb"), }, nil) if err != nil { fmt.Printf("Error storing key: %v\n", err) } else { fmt.Println("Key-value stored successfully") } } 3. 版本控制与事务 Consul KV Store支持版本控制,这意味着每次更新键值对时,都会记录一个新的版本。这对于确保数据一致性至关重要。例如,你可以使用KV() API的CheckAndSet方法原子性地更新值,只有当键的当前值与预期一致时才进行更新。 go // 更新键值对并确保值匹配 _, _, err = client.KV().CheckAndSet(&api.KVPair{ Key: "myapp/config/db_url", Value: []byte("postgresql://localhost:5432/mydb-updated"), Version: 1, // 假设我们已经知道当前版本是1 }, nil) 4. 过期时间与自动清理 Consul允许为键设置过期时间,一旦超过这个时间,Consul会自动删除该键值对,无需人工干预。这对于临时存储或缓存数据特别有用。 go // 设置过期时间为1小时的键值对 _, _, err = client.KV().Put(&api.KVPair{ Key: "myapp/temp_data", Value: []byte("temp data"), TTL: time.Hour, }, nil) 5. 集群同步与一致性 Consul的KV Store采用复制和一致性算法,确保所有节点上的数据保持同步。当有新数据需要写入时,Consul会发动一次全体节点参与的协同作战,确保这些新鲜出炉的数据会被所有节点稳稳接收到,这样一来,就不用担心数据会神秘消失或者出现啥不一致的情况啦。 6. 动态配置与服务发现 Consul的KV Store常用于动态配置,如应用的环境变量。同时呢,它还跟服务发现玩得可亲密了。具体来说就是,服务实例会主动把自己的信息挂到KV Store这个公告板上,其他服务一看,嘿,只要找到像service/myapp这样的关键词,就能轻松查到这些服务的配置情况和健康状况啦。 go // 注册服务 service := &api.AgentServiceRegistration{ ID: "myapp", Name: "My App Service", Tags: []string{"web"}, Address: "192.168.1.100:8080", } _, _, err = client.Agent().ServiceRegister(service, nil) 7. 总结与展望 Consul的Key-Value存储是其强大功能的核心,它使得数据管理变得简单且可靠。嘿,你知道吗?KV Store就像个超能小管家,在分布式系统里大显身手。它通过灵活的版本控制机制,像记录家族大事记一样,确保每一次数据变动都有迹可循;再搭配上过期时间管理这一神技能,让数据能在合适的时间自动更新换代,永葆青春;最关键的是,它还提供了一致性保证这个法宝,让所有节点的数据都能保持同步协调,稳如磐石。所以说啊,KV Store实实在在地为分布式系统搭建了一个无比坚实的基础支撑。无论是服务发现还是配置管理,Consul都展现了其灵活和实用的一面。随着企业越来越离不开微服务和云原生架构,Consul这个家伙将在现代DevOps的日常运作中持续扮演它的“大主角”,而且这戏份只会越来越重。 --- 在撰写这篇文章的过程中,我尽力将复杂的概念以易于理解的方式呈现,同时也融入了一些代码示例,以便读者能更直观地感受Consul的工作原理。甭管你是刚刚开始摸Consul的开发者小哥,还是正在绞尽脑汁提升自家系统稳定性的工程师大佬,都能从Consul这儿捞到实实在在的好处。希望本文能帮助你在使用Consul时更好地理解和利用其数据存储能力。
2024-03-04 11:46:36
433
人生如戏-t
ElasticSearch
...通过以下命令检查磁盘使用情况: bash df -h 看到磁盘空间变大了,心里顿时舒坦了不少。 --- 4. 解决方案二 调整ElasticSearch配置 当然啦,仅仅扩容还不够,还需要优化ElasticSearch的配置文件。特别是那些容易导致内存不足或磁盘占用过高的参数,比如indices.memory.index_buffer_size和indices.store.throttle.max_bytes_per_sec。修改后的配置文件大概长这样: yaml cluster.routing.allocation.disk.threshold_enabled: true cluster.routing.allocation.disk.watermark.low: 85% cluster.routing.allocation.disk.watermark.high: 90% cluster.routing.allocation.disk.watermark.flood_stage: 95% cluster.info.update.interval: 30s 这些设置的意思是告诉ElasticSearch,当磁盘使用率达到85%时开始警告,达到90%时限制写入,超过95%时完全停止操作。这样可以有效避免再次出现类似的问题。 --- 5. 实战演练 代码中的应对策略 除了调整配置,我们还可以通过编写脚本来监控和处理NodeNotActiveException。比如,下面这段Java代码展示了如何捕获异常并记录日志: java import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; public class ElasticSearchExample { public static void main(String[] args) { RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http"))); try { CreateIndexRequest request = new CreateIndexRequest("test_index"); CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); System.out.println("Index created: " + response.isAcknowledged()); } catch (Exception e) { if (e instanceof ClusterBlockException) { System.err.println("Cluster block detected: " + e.getMessage()); } else { System.err.println("Unexpected error: " + e.getMessage()); } } finally { try { client.close(); } catch (IOException ex) { System.err.println("Failed to close client: " + ex.getMessage()); } } } } 这段代码的作用是在创建索引时捕获可能发生的异常,并根据异常类型采取不同的处理方式。如果遇到ClusterBlockException,我们可以选择延迟重试或者其他补偿措施。 --- 6. 总结与反思 成长路上的一课 通过这次经历,我深刻体会到,作为一名开发者,不仅要掌握技术细节,还要学会从实际问题出发,找到最优解。NodeNotActiveException这个错误看着不起眼,但其实背后有不少门道呢!比如说,你的服务器硬件是不是有点吃不消了?集群那边有没有啥小毛病没及时发现?还有啊,咱们平时运维的时候是不是也有点松懈了?这些都是得好好琢磨的地方! 最后,我想说的是,技术学习的过程就像爬山一样,有时候会遇到陡峭的山坡,但只要坚持下去,总能看到美丽的风景。希望这篇文章能给大家带来一些启发和帮助!如果还有其他疑问,欢迎随时交流哦~
2025-03-14 15:40:13
64
林中小径
转载文章
...if (!file.exists()){file.mkdirs();} } 最后在mainapp包内创建PullPic类,并添加主方法。 package com.asahi.mainapp;import com.asahi.common.Kind;import com.asahi.common.PrintLog;import com.asahi.utils.JsoupPic;import java.util.Scanner;public class PullPic {public static void main(String[] args) throws Exception {new PullPic().downloadPic();}public void downloadPic() throws Exception {System.out.println("启动程序>>\n请输入所爬取的分类:");Scanner scanner = new Scanner(System.in);String kind = scanner.next();while(!Kind.contains(kind)){System.out.println("分类不存在,请重新输入:");kind = scanner.next();}System.out.println("分类输入正确!");System.out.println("开始下载>>");JsoupPic.getPic(kind);} } 三、成果展示 最终的运行结果如下: 最终的代码已上传到我的github中,点击“我的github”进行查看。 在学习Java爬虫的过程中,我收获了很多,一开始做的时候确实遇到了很多困难,这次写的获取图片也是最基础的,还可以继续深入。本来我想写一个通过多线程来获取图片来着,也尝试着去写了一下,越写越跑偏,暂时先放着不处理吧,等以后有时间再来弄,我想问题应该不大,只是考虑的东西有很多。希望大家多多指点不足,有哪些需要改进的地方,我也好多学习学习๑乛◡乛๑。 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_39693281/article/details/108463868。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-12 10:26:04
130
转载
转载文章
....repo,只是为了使用阿里云的yum源中的mariadb rm -rf /etc/yum.repos.d/Mariadb.repo然后清空yum 缓存yum clean all 3.通过yum安装mariadb软件,安装mariadb服务端和客户端 官方 yum install MariaDB-server MariaDB-client -y阿里云 yum install mariadb mariadb-server -y 4.安装完成后,启动mariadb服务端 systemctl start/stop/restart/status mariadbsystemctl enable mariadb 开机启动mariadb 5. mariadb初始化 这条命令可以初始化mysql,删除匿名用户,设置root密码等等....mysql_secure_installation1.输入当前密码,初次安装后是没有密码的,直接回车2.询问是否使用 'unix_socket' 进行身份验证: n3.为 root 设置密码:y4.输入 root 的新密码: root5.确认输入 root 的新密码: root6.是否移除匿名用户,这个随意,建议删除: y7.拒绝用户远程登录,这个建议开启:n8.删除 test 库,可以保留:n9.重新加载权限表:y 6. 设置mysql的中文编码支持,修改/etc/my.cnf 1.vi /etc/my.cnf在[mysqld]中添加参数,使得mariadb服务端支持中文[mysqld]character-set-server=utf8collation-server=utf8_general_ci2.重启mariadb服务,读取my.cnf新配置systemctl restart mariadb 3.登录数据库,查看字符编码mysql -uroot -p输入 \s 查看编码 7. mysql常用命 desc 查看表结构create database 数据库名create table 表名查看如何创建db的show create database 库名 查看如何创建table结构的show create table 表名; 修改mysql的密码set password = PASSWORD('redhat'); 创建mysql的普通用户,默认权限非常低create user zhang@'%' identified by '123456'; 查询mysql数据库中的用户信息use mysql;select host,user,password from user; 7. 给用户添加权限命令 对所有库和所有表授权所有权限grant all privileges on . to 账户@主机名 给zhang用户授予所有权限grant all privileges on . to zhang@'%'; 刷新授权表flush privileges; 8. 给用户添加权限命令 给zhangsan用户授予所有权限grant all privileges on . to zhangsan@'%'; 给与root权限授予远程登录的命令 'centos这是密码随意设置grant all privileges on . to root@'%' identified by '123456'; 此时可以在windows登录linux的数据库 连接服务器的mysqlmysql -uyining -p -h 服务器的地址 9. 数据备份与恢复 导出当前数据库的所有db,到一个文件中1.mysqldump -u root -p --all-databases > /data/AllMysql.dump2.登录mysql 导入数据mysql -u root -p> source /data/AllMysql.dump3.通过命令导入数据 在登录时候,导入数据文件,一样可以写入数据mysql -uroot -p < /data/AllMysql.dump 10. 修改Mariadb存储路径 10.1 首先确定MariaDB数据库能正常运行,确定正常后关闭服务 systemctl stop mariadb 10.2 建立要更改数据存放的目录,如:我这单独分了一个区/data存放MariaDB的数据 mkdir /data/mysql_data chown -R mysql:mysql /data/mysql_data 10.3 复制默认数据存放文件夹到/data/mysql_data cp -a /var/lib/mysql /data/mysql_data 10.4 修改/etc/my.cnf.d/server.cnf vim /etc/my.cnf.d/server.cnf 在[mysqld]标签下添加如下内容 datadir=/data/mysql_data/mysqlsocket=/var/lib/mysql/mysql.sockdefault-character-set=utf8character_set_server=utf8slow_query_log=onslow_query_log_file=/data/mysql_data/slow_query_log.loglong_query_time=2 10.5 配置MariaDB慢查询 touch /data/mysql_data/slow_query_log.logchown mysql:mysql /data/mysql_data/slow_query_log.log 10.6 重启数据库 systemctl start mariadb 10.7 注意: 1、配置文件my.cnf存在,但是修改的并不是my.cnf,而是/etc/my.cnf.d/server.cnf; 2、并没有更改mysql.sock的路径配置; 3、没有修改/etc/init.d/mysql中的内容; 4、没有修改mysql_safe中的内容; 5、增加了数据库的慢查询配置。 11. Mariadb主从复制 11.1 主从库初始化 这条命令可以初始化mysql,删除匿名用户,设置root密码等等....mysql_secure_installation1.输入当前密码,初次安装后是没有密码的,直接回车2.询问是否使用 'unix_socket' 进行身份验证: n3.为 root 设置密码:y4.输入 root 的新密码: root5.确认输入 root 的新密码: root6.是否移除匿名用户,这个随意,建议删除: y7.拒绝用户远程登录,这个建议开启:n8.删除 test 库,可以保留:n9.重新加载权限表:y 11.2 修改主库配置 [root@mster mysql] grep -Ev "^$|^" /etc/my.cnf.d/server.cnf[server][mysqld]character-set-server=utf8collation-server=utf8_general_ciserver_id = 13 一组主从组里的每个id必须是唯一值。推荐用ip位数log-bin= mysql-bin 二进制日志,后面指定存放位置。如果只是指定名字,默认存放在/var/lib/mysql下lower_case_table_names=1 不区分大小写binlog-format=ROW 二进制日志文件格式log-slave-updates=True slave更新是否记入日志sync-master-info=1 值为1确保信息不会丢失slave-parallel-threads=3 同时启动多少个复制线程,最多与要复制的数据库数量相等即可binlog-checksum=CRC32 效验码master-verify-checksum=1 启动主服务器效验slave-sql-verify-checksum=1 启动从服务器效验[galera][embedded][mariadb][mariadb-10.6][root@mster-k8s mysql] 11.2 修改从库配置 [mysqld]character-set-server=utf8collation-server=utf8_general_ciserver_id=14log-bin= mysql-bin log-bin是二进制文件relay_log = relay-bin 中继日志, 后面指定存放位置。如果只是指定名字,默认存放在/var/lib/mysql下lower_case_table_names=1 11.3 重启主库和从库服务 systemctl restart mariad 11.4 master节点配置 MariaDB [huawei]> grant replication slave, replication client on . to 'liu'@'%' identified by '123456';Query OK, 0 rows affected (0.001 sec)MariaDB [huawei]> show master status;+------------------+----------+--------------+------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |+------------------+----------+--------------+------------------+| mysql-bin.000001 | 4990 | | |+------------------+----------+--------------+------------------+1 row in set (0.000 sec)MariaDB [huawei]> select binlog_gtid_pos('mysql-bin.000001', 4990 );+-------------------------------------------+| binlog_gtid_pos('mysql-bin.000001', 4990) |+-------------------------------------------+| 0-13-80 |+-------------------------------------------+1 row in set (0.000 sec)MariaDB [huawei]> flush privileges; 11.5 slave节点配置 MariaDB [(none)]> set global gtid_slave_pos='0-13-80';Query OK, 0 rows affected (0.004 sec)MariaDB [(none)]> change master to master_host='101.34.141.216',master_user='liu',master_password='123456',master_use_gtid=slave_pos;Query OK, 0 rows affected (0.008 sec)MariaDB [(none)]> start slave;Query OK, 0 rows affected (0.005 sec)MariaDB [(none)]> 11.6 验证salve状态 MariaDB [(none)]> show slave status\G 1. row Slave_IO_State: Waiting for master to send eventMaster_Host: 101.34.141.216Master_User: liuMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000001Read_Master_Log_Pos: 13260Relay_Log_File: relay-bin.000002Relay_Log_Pos: 10246Relay_Master_Log_File: mysql-bin.000001Slave_IO_Running: YesSlave_SQL_Running: YesReplicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0Last_Error: Skip_Counter: 0Exec_Master_Log_Pos: 13260Relay_Log_Space: 10549Until_Condition: NoneUntil_Log_File: Until_Log_Pos: 0Master_SSL_Allowed: NoMaster_SSL_CA_File: 本篇文章为转载内容。原文链接:https://blog.csdn.net/l363130002/article/details/126121255。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-07-12 10:11:01
310
转载
转载文章
...t技术,如果支持,就使用检测到的技术。 那么这个库到哪里下载,怎么搭建呢,比较懒的童鞋还是用Install-Package Plupload搞定吧,一个命令搞定所有事 Plupload支持的功能这里就不细说了,什么批量上传,这里我没有用到,主要是感觉它支持的事件非常丰富,文件选取后的事件,文件上传中的事件(可获得文件的上传进度),文件上传成功的事件,文件上传失败的事件,等等 我的例子主要是上传一个单个文件,并显示上传的进度条(使用jQuery的一个进度条插件) 下面的例子主要是为文件上传交给 UploadCoursePackage.ashx 来处理 /ProgressBar/ var progressBar = $("loading").progressbar({ width: '500px', color: 'B3240E', border: '1px solid 000000' }); /Plupload/ //实例化一个plupload上传对象 var uploader = new plupload.Uploader({ browse_button: 'browse', //触发文件选择对话框的按钮,为那个元素id runtimes: 'html5,flash,silverlight,html4',//兼容的上传方式 url: "Handlers/UploadCoursePackage.ashx", //后端交互处理地址 max_retries: 3, //允许重试次数 chunk_size: '10mb', //分块大小 rename: true, //重命名 dragdrop: false, //允许拖拽文件进行上传 unique_names: true, //文件名称唯一性 filters: { //过滤器 max_file_size: '999999999mb', //文件最大尺寸 mime_types: [ //允许上传的文件类型 { title: "Zip", extensions: "zip" }, { title: "PE", extensions: "pe" } ] }, //自定义参数 (键值对形式) 此处可以定义参数 multipart_params: { type: "misoft" }, // FLASH的配置 flash_swf_url: "../Scripts/plupload/Moxie.swf", // Silverligh的配置 silverlight_xap_url: "../Scripts/plupload/Moxie.xap", multi_selection: false //true:ctrl多文件上传, false 单文件上传 }); //在实例对象上调用init()方法进行初始化 uploader.init(); uploader.bind('FilesAdded', function (uploader, files) { $("<%=fileSource.ClientID %>").val(files[0].name); $.ajax( { type: 'post', url: 'HardDiskSpace.aspx/GetHardDiskFreeSpace', data: {}, dataType: 'json', contentType: 'application/json;charset=utf-8', success: function (result) { //选择文件以后检测服务器剩余磁盘空间是否够用 if (files.length > 0) { if (parseInt(files[0].size) > parseInt(result.d)) { $('error-msg').text("文件容量大于剩余磁盘空间,请联系管理员!"); } else { $('error-msg').text(""); } } }, error: function (xhr, err, obj) { $('error-msg').text("检测服务器剩余磁盘空间失败"); } }); }); uploader.bind('UploadProgress', function (uploader, file) { var percent = file.percent; progressBar.progress(percent); }); uploader.bind('FileUploaded', function (up, file, callBack) { var data = $.parseJSON(callBack.response); if (data.statusCode === "1") { $("<%=hfPackagePath.ClientID %>").val(data.filePath); var id = $("<%=hfCourseID.ClientID %>").val(); __doPostBack("save", id); } else { hideLoading(); $('error-msg').text(data.message); } }); uploader.bind('Error', function (up, err) { alert("文件上传失败,错误信息: " + err.message); }); /Plupload/ 后台 UploadCoursePackage.ashx 的代码也重要,主要是文件分片跟不分片的处理方式不一样 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; namespace WebUI.Handlers { /// <summary> /// UploadCoursePackage 的摘要说明 /// </summary> public class UploadCoursePackage : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; int statuscode = 1; string message = string.Empty; string filepath = string.Empty; if (context.Request.Files.Count > 0) { try { string resourceDirectoryName = System.Configuration.ConfigurationManager.AppSettings["resourceDirectory"]; string path = context.Server.MapPath("~/" + resourceDirectoryName); if (!Directory.Exists(path)) Directory.CreateDirectory(path); int chunk = context.Request.Params["chunk"] != null ? int.Parse(context.Request.Params["chunk"]) : 0; //获取当前的块ID,如果不是分块上传的。chunk则为0 string fileName = context.Request.Params["name"]; //这里写的比较潦草。判断文件名是否为空。 string type = context.Request.Params["type"]; //在前面JS中不是定义了自定义参数multipart_params的值么。其中有个值是type:"misoft",此处就可以获取到这个值了。获取到的type="misoft"; string ext = Path.GetExtension(fileName); //fileName = string.Format("{0}{1}", Guid.NewGuid().ToString(), ext); filepath = resourceDirectoryName + "/" + fileName; fileName = Path.Combine(path, fileName); //对文件流进行存储 需要注意的是 files目录必须存在(此处可以做个判断) 根据上面的chunk来判断是块上传还是普通上传 上传方式不一样 ,导致的保存方式也会不一样 FileStream fs = new FileStream(fileName, chunk == 0 ? FileMode.OpenOrCreate : FileMode.Append); //write our input stream to a buffer Byte[] buffer = null; if (context.Request.ContentType == "application/octet-stream" && context.Request.ContentLength > 0) { buffer = new Byte[context.Request.InputStream.Length]; context.Request.InputStream.Read(buffer, 0, buffer.Length); } else if (context.Request.ContentType.Contains("multipart/form-data") && context.Request.Files.Count > 0 && context.Request.Files[0].ContentLength > 0) { buffer = new Byte[context.Request.Files[0].InputStream.Length]; context.Request.Files[0].InputStream.Read(buffer, 0, buffer.Length); } //write the buffer to a file. if (buffer != null) fs.Write(buffer, 0, buffer.Length); fs.Close(); statuscode = 1; message = "上传成功"; } catch (Exception ex) { statuscode = -1001; message = "保存时发生错误,请确保文件有效且格式正确"; Util.LogHelper logger = new Util.LogHelper(); string path = context.Server.MapPath("~/Logs"); logger.WriteLog(ex.Message, path); } } else { statuscode = -404; message = "上传失败,未接收到资源文件"; } string msg = "{\"statusCode\":\"" + statuscode + "\",\"message\":\"" + message + "\",\"filePath\":\"" + filepath + "\"}"; context.Response.Write(msg); } public bool IsReusable { get { return false; } } } } 再附送一个检测服务器端硬盘剩余空间的功能吧 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Script.Services; using System.Web.Services; using System.Web.UI; using System.Web.UI.WebControls; namespace WebUI { public partial class CheckHardDiskFreeSpace : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } /// <summary> /// 获取磁盘剩余容量 /// </summary> /// <returns></returns> [WebMethod] public static string GetHardDiskFreeSpace() { const string strHardDiskName = @"F:\"; var freeSpace = string.Empty; var drives = DriveInfo.GetDrives(); var myDrive = (from drive in drives where drive.Name == strHardDiskName select drive).FirstOrDefault(); if (myDrive != null) { freeSpace = myDrive.TotalFreeSpace+""; } return freeSpace; } } } 效果展示: 详细配置信息可以参考这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/plupload%e4%b8%8a%e4%bc%a0%e6%95%b4%e4%b8%aa%e6%96%87%e4%bb%b6%e5%a4%b9-2/ 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_45525177/article/details/100654639。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-19 09:43:46
127
转载
转载文章
...;!-- 做断点下载使用--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.8.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency> controller package com.kang.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.;import java.net.URLEncoder;import java.util.Optional;/ @Description 文件切片下载 @ClassName DownLoadController @Author 康世行 @Date 20:58 2023/2/22 @Version 1.0/@Controller@Slf4jpublic class DownLoadController {private final static String utf8 = "utf-8";@RequestMapping("/down")public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {// 设置编码格式response.setCharacterEncoding(utf8);//获取文件路径String fileName=request.getParameter("fileName");String drive=request.getParameter("drive");//参数校验log.info(fileName,drive);//完整路径(路径拼接待优化-前端传输优化-后端从新格式化 )String pathAll=drive+":\\"+fileName;log.info("pathAll{}",pathAll);Optional<String> pathFlag = Optional.ofNullable(pathAll);File file=null;if (pathFlag.isPresent()){//根据文件名,读取file流file = new File(pathAll);log.info("文件路径是{}",pathAll);if (!file.exists()){log.warn("文件不存在");return;} }else {//请输入文件名log.warn("请输入文件名!");return;}InputStream is = null;OutputStream os = null;try {//分片下载long fSize = file.length();//获取长度response.setContentType("application/x-download");String file_Name = URLEncoder.encode(file.getName(),"UTF-8");response.addHeader("Content-Disposition","attachment;filename="+fileName);//根据前端传来的Range 判断支不支持分片下载response.setHeader("Accept-Range","bytes");//获取文件大小//response.setHeader("fSize",String.valueOf(fSize));response.setHeader("fName",file_Name);//定义断点long pos = 0,last = fSize-1,sum = 0;//判断前端需不需要分片下载if (null != request.getHeader("Range")){response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);String numRange = request.getHeader("Range").replaceAll("bytes=","");String[] strRange = numRange.split("-");if (strRange.length == 2){pos = Long.parseLong(strRange[0].trim());last = Long.parseLong(strRange[1].trim());//若结束字节超出文件大小 取文件大小if (last>fSize-1){last = fSize-1;} }else {//若只给一个长度 开始位置一直到结束pos = Long.parseLong(numRange.replaceAll("-","").trim());} }long rangeLenght = last-pos+1;String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();response.setHeader("Content-Range",contentRange);// response.setHeader("Content-Lenght",String.valueOf(rangeLenght));os = new BufferedOutputStream(response.getOutputStream());is = new BufferedInputStream(new FileInputStream(file));is.skip(pos);//跳过已读的文件(重点,跳过之前已经读过的文件)byte[] buffer = new byte[1024];int lenght = 0;//相等证明读完while (sum < rangeLenght){lenght = is.read(buffer,0, (rangeLenght-sum)<=buffer.length? (int) (rangeLenght - sum) :buffer.length);sum = sum+lenght;os.write(buffer,0,lenght);}log.info("下载完成");}finally {if (is!= null){is.close();}if (os!=null){os.close();} }} } 启动成功 Vue <html xmlns:th="http://www.thymeleaf.org"><head><meta charset="utf-8"/><title>狂神说Java-ES仿京东实战</title><link rel="stylesheet" th:href="@{/css/style.css}"/></head><body class="pg"><div class="page" id="app"><div id="mallPage" class=" mallist tmall- page-not-market "><!-- 头部搜索 --><div id="header" class=" header-list-app"><div class="headerLayout"><div class="headerCon "><!-- Logo--><h1 id="mallLogo"><img th:src="@{/images/jdlogo.png}" alt=""></h1><div class="header-extra"><!--搜索--><div id="mallSearch" class="mall-search"><form name="searchTop" class="mallSearch-form clearfix"><fieldset><legend>天猫搜索</legend><div class="mallSearch-input clearfix"><div class="s-combobox" id="s-combobox-685"><div class="s-combobox-input-wrap"><input v-model="keyword" type="text" autocomplete="off" value="java" id="mq"class="s-combobox-input" aria-haspopup="true"></div></div><button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button></div></fieldset></form><ul class="relKeyTop"><li><a>狂神说Java</a></li><li><a>狂神说前端</a></li><li><a>狂神说Linux</a></li><li><a>狂神说大数据</a></li><li><a>狂神聊理财</a></li></ul></div></div></div></div></div><el-button @click="download" id="download">下载</el-button><!-- <el-button @click="concurrenceDownload" >并发下载测试</el-button>--><el-button @click="stop">停止</el-button><el-button @click="start">开始</el-button>{ {fileFinalOffset} }{ {contentList} }<el-progress type="circle" :percentage="percentage"></el-progress></div><!--前端使用Vue,实现前后端分离--><script th:src="@{/js/axios.min.js}"></script><script th:src="@{/js/vue.min.js}"></script><!-- 引入样式 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script>new Vue({ el: 'app',data: {keyword: '', //搜索关键字results: [] ,//搜索结果percentage: 0, // 下载进度filesCurrentPage:0,//文件开始偏移量fileFinalOffset:0, //文件最后偏移量stopRecursiveTags:true, //停止递归标签,默认是true 继续进行递归contentList: [], // 文件流数组breakpointResumeTags:false, //断点续传标签,默认是false 不进行断点续传temp:[],fileMap:new Map(),timer:null, //定时器名称},methods: {//根据关键字搜索商品信息searchKey(){var keyword=this.keyword;axios.get('/search/JD/search/'+keyword+"/1/10").then(res=>{this.results=res.data;//绑定数据console.log(this.results)console.table(this.results)})},//停止下载stop(){//改变递归标签为falsethis.stopRecursiveTags=false;},//开始下载start(){//重置递归标签为true 最后进行合并this.stopRecursiveTags=true;//重置断点续传标签this.breakpointResumeTags=true;//重新调用下载方法this.download();},// 分段下载需要后端配合download() {// 下载地址const url = "/down?fileName="+this.keyword.trim()+"&drive=E";console.log(url)const chunkSize = 1024 1024 50; // 单个分段大小,这里测试用100Mlet filesTotalSize = chunkSize; // 安装包总大小,默认100Mlet filesPages = 1; // 总共分几段下载//计算百分比之前先清空上次的if(this.percentage==100){this.percentage=0;}let sentAxios = (num) => {let rande = chunkSize;//判断是否开启了断点续传(断点续传没法并行-需要上次请求的结果作为参数)if (this.breakpointResumeTags){rande = ${Number(this.fileFinalOffset)+1}-${num chunkSize + 1};}else {if (num) {rande = ${(num - 1) chunkSize + 2}-${num chunkSize + 1};} else {// 第一次0-1方便获取总数,计算下载进度,每段下载字节范围区间rande = "0-1";} }let headers = {range: rande,};axios({method: "get",url: url.trim(),async: true,data: {},headers: headers,responseType: "blob"}).then((response) => {if (response.status == 200 || response.status == 206) {//检查了下才发现,后端对文件流做了一层封装,所以将content指向response.data即可const content = response.data;//截取文件总长度和最后偏移量let result= response.headers["content-range"].split("/");// 获取文件总大小,方便计算下载百分比filesTotalSize =result[1];//获取最后一片文件位置,用于断点续传this.fileFinalOffset=result[0].split("-")[1]// 计算总共页数,向上取整filesPages = Math.ceil(filesTotalSize / chunkSize);// 文件流数组this.contentList.push(content);// 递归获取文件数据(判断是否要继续递归)if (this.filesCurrentPage < filesPages&&this.stopRecursiveTags==true) {this.filesCurrentPage++;//计算下载百分比 当前下载的片数/总片数this.percentage=Number((this.contentList.length/filesPages)100).toFixed(2);sentAxios(this.filesCurrentPage);//结束递归return;}//递归标签为true 才进行下载if (this.stopRecursiveTags){// 文件名称const fileName =decodeURIComponent(response.headers["fname"]);//构造一个blob对象来处理数据const blob = new Blob(this.contentList);//对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性//IE10以上支持blob但是依然不支持downloadif ("download" in document.createElement("a")) {//支持a标签download的浏览器const link = document.createElement("a"); //创建a标签link.download = fileName; //a标签添加属性link.style.display = "none";link.href = URL.createObjectURL(blob);document.body.appendChild(link);link.click(); //执行下载URL.revokeObjectURL(link.href); //释放urldocument.body.removeChild(link); //释放标签} else {//其他浏览器navigator.msSaveBlob(blob, fileName);} }} else {//调用暂停方法,记录当前下载位置console.log("下载失败")} }).catch(function (error) {console.log(error);});};// 第一次获取数据方便获取总数sentAxios(this.filesCurrentPage);this.$message({message: '文件开始下载!',type: 'success'});} }})</script></body></html> 本篇文章为转载内容。原文链接:https://blog.csdn.net/kangshihang1998/article/details/129407214。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-01-19 08:12:45
546
转载
转载文章
...t os.path.exists(save_train):os.makedirs(save_train)if not os.path.exists(save_test):os.makedirs(save_test)trans(test_images, test_labels, save_test)trans(train_images, train_labels, save_train) 2.2 将图片按照标签分类到具体文件夹 文章参考链接:python实现根据文件名自动分类转移至不同的文件夹 注意:为了适合这个数据集和我的win11系统对代码进行了一点调整,由于数据很多如果只需要部分数据一定要将那些数据单独放在一个文件夹。 导入库import osimport shutil 当前文件夹所在的路径,使用时需要进行修改current_path = 'C:/Users/ASUS/Desktop/MNIST/test'print('当前文件夹为:' + current_path) 读取该路径下的文件filename_list = os.listdir(current_path) 建立文件夹并且进行转移 假设原图片名称 test_001_2.jpgfor filename in filename_list:name1, name2, name3 = filename.split('_') name1 = test name2 = 001 name3 = 2.jpgname4, name5 = name3.split('.') name4 = 2 name5 = jpgif name5 == 'jpg' or name5 == 'png':try:os.mkdir(current_path+'/'+name4)print('成功建立文件夹:'+name4)except:passtry:shutil.move(current_path+'/'+filename, current_path+'/'+name4[:])print(filename+'转移成功!')except Exception as e:print('文件 %s 转移失败' % filename)print('转移错误原因:' + e)print('整理完毕!') 2.3 数据存在的缺陷 数据集内的图片数量很多,由于后面介绍的云端训练的限制,只能采用部分数据(本人采用的是1000张,大家可以自行增减数目)。 数据集为国外的数据集,很多数字写的跟我们不一样。如果想要更好的适用于我们国内的场景,可以对数据集进行手动的筛选。下面是他们写的数字2: 可以看出跟我们的不一样,不过数据集中仍然存在跟常规书写的一样的,我们需要进行人为的筛选。 2.4 优化建议(核心) 分析发现,部分数字精度不高的原因主要是国外手写很随意,我们可以通过调整网络参数(如下)、人为筛选数据(如上)、增大数据集等方式进行优化。 二、模型训练 主要参考文章:通过云端自动生成openmv的神经网络模型,进行目标检测 !!!唯一不同的点是我图像参数设置的是灰度而不是上述文章的RGB。 下面是我模型训练时的参数设置(仅供参考): 通过混淆矩阵可以看出,主要的错误在于数字2、6、8。我们可以通过查看识别错误的数字来分析可能的原因。 三、项目实现 !!!我们需要先将上述步骤中导出文件中的所有内容复制粘贴带OpenMV中自带的U盘中。然后将其中的.py文件名称改为main 1. 代码实现 本人修改后的完整代码展示如下,使用的是OpenMV IDE(官网下载): 数字识别后控制直流电机转速from pyb import Pin, Timerimport sensor, image, time, os, tf, math, random, lcd, uos, gc 根据识别的数字输出不同占比的PWM波def run(number):if inverse == True:ain1.low()ain2.high()else:ain1.high()ain2.low()ch1.pulse_width_percent(abs(number10)) 具体参数调整自行搜索sensor.reset() 初始化感光元件sensor.set_pixformat(sensor.GRAYSCALE) set_pixformat : 设置像素模式(GRAYSCALSE : 灰色; RGB565 : 彩色)sensor.set_framesize(sensor.QQVGA2) set_framesize : 设置处理图像的大小sensor.set_windowing((128, 160)) set_windowing : 设置提取区域大小sensor.skip_frames(time = 2000) skip_frames :跳过2000ms再读取图像lcd.init() 初始化lcd屏幕。inverse = False True : 电机反转 False : 电机正转ain1 = Pin('P1', Pin.OUT_PP) 引脚P1作为输出ain2 = Pin('P4', Pin.OUT_PP) 引脚P4作为输出ain1.low() P1初始化低电平ain2.low() P4初始化低电平tim = Timer(2, freq = 1000) 采用定时器2,频率为1000Hzch1 = tim.channel(4, Timer.PWM, pin = Pin('P5'), pulse_width_percent = 100) 输出通道1 配置PWM模式下的定时器(高电平有效) 端口为P5 初始占空比为100%clock = time.clock() 设置一个时钟用于追踪FPS 加载模型try:net = tf.load("trained.tflite", load_to_fb=uos.stat('trained.tflite')[6] > (gc.mem_free() - (641024)))except Exception as e:print(e)raise Exception('Failed to load "trained.tflite", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') 加载标签try:labels = [line.rstrip('\n') for line in open("labels.txt")]except Exception as e:raise Exception('Failed to load "labels.txt", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') 不断的进行运行while(True):clock.tick() 更新时钟img = sensor.snapshot().binary([(0,64)]) 抓取一张图像以灰度图显示lcd.display(img) 拍照并显示图像for obj in net.classify(img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5): 初始化最大值和标签max_num = -1max_index = -1print("\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())img.draw_rectangle(obj.rect()) 预测值和标签写成一个列表predictions_list = list(zip(labels, obj.output())) 输出各个标签的预测值,找到最大值进行输出for i in range(len(predictions_list)):print('%s 的概率为: %f' % (predictions_list[i][0], predictions_list[i][1]))if predictions_list[i][1] > max_num:max_num = predictions_list[i][1]max_index = int(predictions_list[i][0])run(max_index)print('该数字预测为:%d' % max_index)print('FPS为:', clock.fps())print('PWM波占空比为: %d%%' % (max_index10)) 2. 采用器件 使用的器件为OpenMV4 H7 Plus和L298N以及常用的直流电机。关键是找到器件的引脚图,再进行简单的连线即可。 参考文章:【L298N驱动模块学习笔记】–openmv驱动 参考文章:【openmv】原理图 引脚图 2. 注意事项 上述代码中我用到了lcd屏幕,主要是为了方便离机操作。使用过程中,OpenMV的lcd初始化时会重置端口,所有我们在输出PWM波的时候一定不要发生引脚冲突。我们可以在OpenMV官网查看lcd用到的端口: 可以看到上述用到的是P0、P2、P3、P6、P7和P8。所有我们输出PWM波时要避开这些端口。下面是OpenMV的PWM资源: 总结 本人第一次自己做东西也是第一次使用python,所以代码和项目写的都很粗糙,只是简单的识别数字控制直流电机。我也是四处借鉴修改后写下的大小,这篇文章主要是为了给那些像我一样的小白们提供一点帮助,减少大家查找资料的时间。模型的缺陷以及改进方法上述中已经说明,如果我有写错或者大家有更好的方法欢迎大家告诉我,大家一起进步! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_57100435/article/details/130740351。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-10 08:44:41
282
转载
JQuery插件下载
...可以根据需要设置触发条件、动画时长以及动画结束后的状态。这意味着你可以精准地控制元素何时开始动画,以及动画在滚动过程中如何变化。ScrollMagic不仅支持基本的动画效果,还能实现更为复杂的效果如视觉差动画和瀑布流布局,极大地丰富了网页的表现力。使用ScrollMagic,开发者可以轻松地将吸引人的动画效果融入到网站设计中,提升用户体验,使网站更具吸引力。无论是个人项目还是企业级应用,ScrollMagic都是实现高级滚动动画效果的理想选择。通过结合CSS3动画和JavaScript的强大功能,ScrollMagic能够为用户提供流畅、高效的动画体验,让网站内容在用户浏览时更加生动有趣。 点我下载 文件大小:1.36 MB 您将下载一个JQuery插件资源包,该资源包内部文件的目录结构如下: 本网站提供JQuery插件下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2025-02-09 21:21:20
21
本站
JQuery插件下载
...来定制翻转速度、触发条件等参数,确保动画既符合品牌形象,又能流畅自然。得益于CSS3和jQuery的强大结合,TURNBOX兼容现代主流浏览器,包括Safari、Chrome和Firefox,为用户提供一致且惊艳的视觉效果。总的来说,TURNBOX是一款实用而富有创意的工具,帮助设计师和开发者在扁平化设计潮流中添加生动的动态元素,提升网站的用户体验和整体设计水平。 点我下载 文件大小:105.79 KB 您将下载一个JQuery插件资源包,该资源包内部文件的目录结构如下: 本网站提供JQuery插件下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2024-06-11 20:47:11
377
本站
JQuery插件下载
...与功能增强。通过巧妙结合jQuery强大的交互能力和CSS3的动态视觉效果,该插件能够将普通的下拉菜单转变为一种富有创意的用户体验设计。每一个列表项都被精心设计为卡片样式,赋予了界面更多的空间感与层次性。当用户触发下拉动作时,这些卡片会以类似打开或关闭百叶窗的动画效果呈现,营造出令人眼前一亮的视觉冲击力和流畅的过渡效果。这一特性不仅提升了整体页面的设计美学,同时也增强了用户的操作体验,使其在选择列表项时享受到更为生动有趣的互动过程。此插件适用于追求现代、时尚网页设计风格的开发者,尤其适合那些希望在保持功能实用性的同时,又能凸显网站品质与个性化的应用场景。通过简单的集成与配置,开发者可以轻松地将这一炫酷的折叠卡片式下拉列表框特效应用于导航菜单、筛选条件或其他需要使用下拉列表功能的地方。 点我下载 文件大小:38.96 KB 您将下载一个JQuery插件资源包,该资源包内部文件的目录结构如下: 本网站提供JQuery插件下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2023-01-10 16:07:53
268
本站
JQuery插件下载
...元素的动态视觉效果相结合,为网站添加了生动且流畅的交互体验。通过精确检测页面滚动位置,ScrollTrigger能够自动触发指定元素上的动画效果,如淡入、缩放、移动等,使页面内容在用户浏览时呈现出更加吸引人的动态变化。该插件采用现代浏览器支持的requestAnimationFrame技术,确保在滚动过程中保持页面的流畅性和响应速度,避免因动画处理而造成的性能瓶颈或卡顿现象。这不仅提升了用户体验,也使得开发者可以更专注于设计创意动画效果,而不必担心影响网站的整体性能。ScrollTrigger具有高度灵活性和可定制性,允许开发者根据需要自定义动画效果、触发条件及持续时间等参数。无论是简单的渐变动画还是复杂的组合动画,ScrollTrigger都能轻松实现,满足各种场景下的动画需求。此外,由于其基于纯JavaScript开发,无需依赖任何第三方库或框架,因此兼容性强,可在各类现代浏览器上稳定运行。总之,ScrollTrigger凭借其高性能、易用性和强大的功能,成为创建引人入胜网页动画效果的理想选择。无论是用于构建产品展示页面、故事叙述型网站还是动态信息图表,ScrollTrigger都能帮助你快速实现令人印象深刻的滚动动画效果。 点我下载 文件大小:17.52 KB 您将下载一个JQuery插件资源包,该资源包内部文件的目录结构如下: 本网站提供JQuery插件下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2024-11-27 21:18:29
53
本站
JQuery插件下载
...Query与CSS3结合的插件,名为“页面过渡、页面切换、ajax”,提供了一种令人眼前一亮的网站交互体验。通过利用现代浏览器的强大功能,此插件能够实现网页内容的无缝切换,同时加入华丽的CSS3动画效果,使整个页面过渡过程流畅自然,视觉效果震撼。在用户点击链接时,插件会运用AJAX技术异步请求服务器数据,避免了传统页面刷新导致的等待时间,从而大大提升了用户体验。与此同时,借助CSS3强大的动画能力,每一个页面切换动作都如同精心设计的电影场景般流畅,从淡入淡出到旋转翻页,各种动画效果可供选择,让每一次页面转换都成为一次视觉盛宴。不仅如此,这款插件还支持自定义动画效果,开发者可以根据实际需求调整动画速度、持续时间和触发条件等参数,使得页面过渡更加符合网站的整体风格和品牌调性。无论是用于展示作品集、博客文章还是企业官网,这款插件都能帮助你打造出既有深度又具吸引力的互动式网站。总之,这款“页面过渡、页面切换、ajax”插件不仅简化了网站开发过程中的复杂操作,更以其独特的动画效果和出色的用户体验,成为了网页设计师和前端开发者不可或缺的工具之一。 点我下载 文件大小:51.66 KB 您将下载一个JQuery插件资源包,该资源包内部文件的目录结构如下: 本网站提供JQuery插件下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2024-10-26 20:53:05
58
本站
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
tac file.txt
- 类似于cat但反向输出文件内容。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"