`
hetylei
  • 浏览: 142455 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

xmpp with openfire之四 扩展的AuthProvider

阅读更多
上一篇中提到jdbcAuthProvider.passwordType提供了三种方式

如果你的密码加密规则不是这三种方式,可以自己进行扩充

首先,下载openfire的源码
http://www.igniterealtime.org/downloads/source.jsp

打开org.jivesoftware.openfire.auth.JDBCAuthProvider
package org.jivesoftware.openfire.auth;

import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;

import java.sql.*;

/**
 * The JDBC auth provider allows you to authenticate users against any database
 * that you can connect to with JDBC. It can be used along with the
 * {@link HybridAuthProvider hybrid} auth provider, so that you can also have
 * XMPP-only users that won't pollute your external data.<p>
 *
 * To enable this provider, set the following in the system properties:
 * <ul>
 * <li><tt>provider.auth.className = org.jivesoftware.openfire.auth.JDBCAuthProvider</tt></li>
 * </ul>
 *
 * You'll also need to set your JDBC driver, connection string, and SQL statements:
 *
 * <ul>
 * <li><tt>jdbcProvider.driver = com.mysql.jdbc.Driver</tt></li>
 * <li><tt>jdbcProvider.connectionString = jdbc:mysql://localhost/dbname?user=username&amp;password=secret</tt></li>
 * <li><tt>jdbcAuthProvider.passwordSQL = SELECT password FROM user_account WHERE username=?</tt></li>
 * <li><tt>jdbcAuthProvider.passwordType = plain</tt></li>
 * <li><tt>jdbcAuthProvider.allowUpdate = true</tt></li>
 * <li><tt>jdbcAuthProvider.setPasswordSQL = UPDATE user_account SET password=? WHERE username=?</tt></li>
 * </ul>
 *
 * The passwordType setting tells Openfire how the password is stored. Setting the value
 * is optional (when not set, it defaults to "plain"). The valid values are:<ul>
 *      <li>{@link PasswordType#plain plain}
 *      <li>{@link PasswordType#md5 md5}
 *      <li>{@link PasswordType#sha1 sha1}
 *  </ul>
 *
 * @author David Snopek
 */
public class JDBCAuthProvider implements AuthProvider {

    private String connectionString;

    private String passwordSQL;
    private String setPasswordSQL;
    private PasswordType passwordType;
    private boolean allowUpdate;

    /**
     * Constructs a new JDBC authentication provider.
     */
    public JDBCAuthProvider() {
        // Convert XML based provider setup to Database based
        JiveGlobals.migrateProperty("jdbcProvider.driver");
        JiveGlobals.migrateProperty("jdbcProvider.connectionString");
        JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");
        JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");
        JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");
        JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");

        // Load the JDBC driver and connection string.
        String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");
        try {
            Class.forName(jdbcDriver).newInstance();
        }
        catch (Exception e) {
            Log.error("Unable to load JDBC driver: " + jdbcDriver, e);
            return;
        }
        connectionString = JiveGlobals.getProperty("jdbcProvider.connectionString");

        // Load SQL statements.
        passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");
        setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");

        allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);

        passwordType = PasswordType.plain;
        try {
            passwordType = PasswordType.valueOf(
                    JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));
        }
        catch (IllegalArgumentException iae) {
            Log.error(iae);
        }
    }

    public void authenticate(String username, String password) throws UnauthorizedException {
        if (username == null || password == null) {
            throw new UnauthorizedException();
        }
        username = username.trim().toLowerCase();
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain. Return authentication failed.
                throw new UnauthorizedException();
            }
        }
        String userPassword;
        try {
            userPassword = getPasswordValue(username);
        }
        catch (UserNotFoundException unfe) {
            throw new UnauthorizedException();
        }
        // If the user's password doesn't match the password passed in, authentication
        // should fail.
        if (passwordType == PasswordType.md5) {
            password = StringUtils.hash(password, "MD5");
        }
        else if (passwordType == PasswordType.sha1) {
            password = StringUtils.hash(password, "SHA-1");
        }
        if (!password.equals(userPassword)) {
            throw new UnauthorizedException();
        }

        // Got this far, so the user must be authorized.
        createUser(username);
    }

    public void authenticate(String username, String token, String digest)
            throws UnauthorizedException
    {
        if (passwordType != PasswordType.plain) {
            throw new UnsupportedOperationException("Digest authentication not supported for "
                    + "password type " + passwordType);
        }
        if (username == null || token == null || digest == null) {
            throw new UnauthorizedException();
        }
        username = username.trim().toLowerCase();
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain. Return authentication failed.
                throw new UnauthorizedException();
            }
        }
        String password;
        try {
            password = getPasswordValue(username);
        }
        catch (UserNotFoundException unfe) {
            throw new UnauthorizedException();
        }
        String anticipatedDigest = AuthFactory.createDigest(token, password);
        if (!digest.equalsIgnoreCase(anticipatedDigest)) {
            throw new UnauthorizedException();
        }

        // Got this far, so the user must be authorized.
        createUser(username);
    }

    public boolean isPlainSupported() {
        // If the auth SQL is defined, plain text authentication is supported.
        return (passwordSQL != null);
    }

    public boolean isDigestSupported() {
        // The auth SQL must be defined and the password type is supported.
        return (passwordSQL != null && passwordType == PasswordType.plain);
    }

    public String getPassword(String username) throws UserNotFoundException,
            UnsupportedOperationException
    {

        if (!supportsPasswordRetrieval()) {
            throw new UnsupportedOperationException();
        }
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain.
                throw new UserNotFoundException();
            }
        }
        return getPasswordValue(username);
    }

    public void setPassword(String username, String password)
            throws UserNotFoundException, UnsupportedOperationException
    {
        if (allowUpdate && setPasswordSQL != null) {
            setPasswordValue(username, password);
        } else { 
            throw new UnsupportedOperationException();
        }
    }

    public boolean supportsPasswordRetrieval() {
        return (passwordSQL != null && passwordType == PasswordType.plain);
    }

    /**
     * Returns the value of the password field. It will be in plain text or hashed
     * format, depending on the password type.
     *
     * @param username user to retrieve the password field for
     * @return the password value.
     * @throws UserNotFoundException if the given user could not be loaded.
     */
    private String getPasswordValue(String username) throws UserNotFoundException {
        String password = null;
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain.
                throw new UserNotFoundException();
            }
        }
        try {
            con = DriverManager.getConnection(connectionString);
            pstmt = con.prepareStatement(passwordSQL);
            pstmt.setString(1, username);

            rs = pstmt.executeQuery();

            // If the query had no results, the username and password
            // did not match a user record. Therefore, throw an exception.
            if (!rs.next()) {
                throw new UserNotFoundException();
            }
            password = rs.getString(1);
        }
        catch (SQLException e) {
            Log.error("Exception in JDBCAuthProvider", e);
            throw new UserNotFoundException();
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return password;
    }

    private void setPasswordValue(String username, String password) throws UserNotFoundException {
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain.
                throw new UserNotFoundException();
            }
        }
        try {
            con = DriverManager.getConnection(connectionString);
            pstmt = con.prepareStatement(setPasswordSQL);
            pstmt.setString(1, username);
            if (passwordType == PasswordType.md5) {
                password = StringUtils.hash(password, "MD5");
            }
            else if (passwordType == PasswordType.sha1) {
                password = StringUtils.hash(password, "SHA-1");
            }
            pstmt.setString(2, password);

            rs = pstmt.executeQuery();

        }
        catch (SQLException e) {
            Log.error("Exception in JDBCAuthProvider", e);
            throw new UserNotFoundException();
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        
    }

    /**
     * Indicates how the password is stored.
     */
    @SuppressWarnings({"UnnecessarySemicolon"})  // Support for QDox Parser
    public enum PasswordType {

        /**
         * The password is stored as plain text.
         */
        plain,

        /**
         * The password is stored as a hex-encoded MD5 hash.
         */
        md5,

        /**
         * The password is stored as a hex-encoded SHA-1 hash.
         */
        sha1;
    }

    /**
     * Checks to see if the user exists; if not, a new user is created.
     *
     * @param username the username.
     */
    private static void createUser(String username) {
        // See if the user exists in the database. If not, automatically create them.
        UserManager userManager = UserManager.getInstance();
        try {
            userManager.getUser(username);
        }
        catch (UserNotFoundException unfe) {
            try {
                Log.debug("JDBCAuthProvider: Automatically creating new user account for " + username);
                UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),
                        null, null);
            }
            catch (UserAlreadyExistsException uaee) {
                // Ignore.
            }
        }
    }
}



看以看到通过读取PASSWORDTYPE配置
JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");
。。。。。
。。。。。
。。。。。
passwordType = PasswordType.plain;  
        try {  
            passwordType = PasswordType.valueOf(  
                    JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));  
        }  
        catch (IllegalArgumentException iae) {  
            Log.error(iae);  
        }  

进行密码的验证
 if (passwordType == PasswordType.md5) {
            password = StringUtils.hash(password, "MD5");
        }
        else if (passwordType == PasswordType.sha1) {
            password = StringUtils.hash(password, "SHA-1");
        }
        if (!password.equals(userPassword)) {
            throw new UnauthorizedException();
        }



这样完全可以仿照JDBCAuthProvider重新构造

package org.yxsoft.openfire.plugin;


import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.auth.*;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.database.DbConnectionManager;

import java.sql.*;
import java.security.MessageDigest;

/**
 * Created by cl
 * Date: 2008-9-4
 * Time: 9:18:26
 * 仿照JDBCAuthProvider
 * 在数据库连接上 支持user/password
 * 密码验证 使用bfmp的机制
 */
public class BfmpAuthProvider implements AuthProvider {
    private String connectionString;
    private String user;
    private String password;

    private String passwordSQL;
    private String setPasswordSQL;
    private PasswordType passwordType;
    private boolean allowUpdate;

    /**
     * 初始化
     * 比JDBCAuthProvider多支持
     * JiveGlobals.migrateProperty("jdbcProvider.url");
        JiveGlobals.migrateProperty("jdbcProvider.user");
        JiveGlobals.migrateProperty("jdbcProvider.password");
     */
    public BfmpAuthProvider() {
        // Convert XML based provider setup to Database based
        JiveGlobals.migrateProperty("jdbcProvider.driver");
        JiveGlobals.migrateProperty("jdbcProvider.url");
        JiveGlobals.migrateProperty("jdbcProvider.user");
        JiveGlobals.migrateProperty("jdbcProvider.password");

        JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");
        JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");
        JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");
        JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");
        JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");

        // Load the JDBC driver and connection string.
        String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");
        try {
            Class.forName(jdbcDriver).newInstance();
        }
        catch (Exception e) {
            Log.error("Unable to load JDBC driver: " + jdbcDriver, e);
            return;
        }
        connectionString = JiveGlobals.getProperty("jdbcProvider.url");
        user = JiveGlobals.getProperty("jdbcProvider.user");
        password = JiveGlobals.getProperty("jdbcProvider.password");

        // Load SQL statements.
        passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");
        setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");

        allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);

        passwordType = PasswordType.plain;
        try {
            passwordType = PasswordType.valueOf(
                    JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));
            Log.error("PasswordType:"+ passwordType);
        }
        catch (IllegalArgumentException iae) {
            Log.error(iae);
        }
    }

    public boolean isPlainSupported() {
        //default
        return true;
    }

    public boolean isDigestSupported() {
        //default
        return true;
    }

    public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
        if (username == null || password == null) {
            throw new UnauthorizedException();
        }
        Log.error(username+":"+password);
        username = username.trim().toLowerCase();
        if (username.contains("@")) {
            Log.error(username+":"+XMPPServer.getInstance().getServerInfo().getXMPPDomain());
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain. Return authentication failed.
                throw new UnauthorizedException();
            }
        } else {
            Log.error("user name not contains ");
        }
        String userPassword;
        try {
            userPassword = getPasswordValue(username);
        }
        catch (UserNotFoundException unfe) {
            throw new UnauthorizedException();
        }
        // If the user's password doesn't match the password passed in, authentication
        // should fail.
        if (passwordType == PasswordType.bfmp) {
            //这里BfmpMD5 就是自己的密码规则
            password = BfmpMD5(password);
        }

        if (!password.equals(userPassword)) {
            throw new UnauthorizedException();
        }

        // Got this far, so the user must be authorized.
        //createUser(username);
    }

    public void authenticate(String username, String token, String digest) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
        if (passwordType != PasswordType.plain) {
            throw new UnsupportedOperationException("Digest authentication not supported for "
                    + "password type " + passwordType);
        }
        if (username == null || token == null || digest == null) {
            throw new UnauthorizedException();
        }
        username = username.trim().toLowerCase();
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain. Return authentication failed.
                throw new UnauthorizedException();
            }
        }
        String password;
        try {
            password = getPasswordValue(username);
        }
        catch (UserNotFoundException unfe) {
            throw new UnauthorizedException();
        }
        String anticipatedDigest = AuthFactory.createDigest(token, password);
        if (!digest.equalsIgnoreCase(anticipatedDigest)) {
            throw new UnauthorizedException();
        }

        // Got this far, so the user must be authorized.
        //createUser(username);
    }

    public String getPassword(String username) throws UserNotFoundException, UnsupportedOperationException {
        if (!supportsPasswordRetrieval()) {
            throw new UnsupportedOperationException();
        }
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain.
                throw new UserNotFoundException();
            }
        }
        return getPasswordValue(username);
    }

    private String getPasswordValue(String username) throws UserNotFoundException {
        String password = null;
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        if (username.contains("@")) {
            // Check that the specified domain matches the server's domain
            int index = username.indexOf("@");
            String domain = username.substring(index + 1);
            if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                username = username.substring(0, index);
            } else {
                // Unknown domain.
                throw new UserNotFoundException();
            }
        }
        try {
            con = DriverManager.getConnection(connectionString, user, this.password);
            pstmt = con.prepareStatement(passwordSQL);
            pstmt.setString(1, username);

            rs = pstmt.executeQuery();

            // If the query had no results, the username and password
            // did not match a user record. Therefore, throw an exception.
            if (!rs.next()) {
                throw new UserNotFoundException();
            }
            password = rs.getString(1);
        }
        catch (SQLException e) {
            Log.error("Exception in JDBCAuthProvider", e);
            throw new UserNotFoundException();
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return password;
    }

    public void setPassword(String username, String password) throws UserNotFoundException, UnsupportedOperationException {
        // unsupport
    }

    public boolean supportsPasswordRetrieval() {
        return true;
    }


    /**
     * Indicates how the password is stored.
     */
    @SuppressWarnings({"UnnecessarySemicolon"})  // Support for QDox Parser
    public enum PasswordType {

        /**
         * The password is stored as plain text.
         */
        plain,

        /**
         * The password is stored as a bfmp passwrod.
         */
        bfmp;
    }

    private String BfmpMD5 (String source) {
        //在这里实现你的加密机制,返回生成的密码
        return "";

    }


}




编译后将此class加入到lib/openfire.jar中即可

当然不要忘记 将系统属性中
provider.auth.className,改成你自已的Provider
*上述代码例子中是org.yxsoft.openfire.plugin.BFMPAuthProvider
jdbcAuthProvider.passwordType,改成你自己定义的枚举值
*上述代码例子中是bfmp

分享到:
评论
1 楼 moistrot 2010-04-30  
将这个编译好的类,加入我的lib\openfire.jar,之后,登录不进去,无论我输入什么,都是密码错误。

相关推荐

    Xmpp和OpenFire实例

    先说一下为什么要写这篇博客,是因为本人在周末在研究XMPP和OpenFire,从网上下载了个Demo,但跑不起来,花了很长时间,经改造后,跑起来了,写个篇博文也是希望后边学习XMPP和OpenFire的同学下载后直接运行,少走...

    XMPP开发Openfire详细介绍

    Openfire的强大之处在于其高度可扩展的插件系统。通过安装插件,可以极大地增强服务器的功能。 ##### 3.1 KrakenIMGateway插件 - **功能**:支持MSNS、QQ等第三方即时通讯工具的登录。 - **配置**:通过插件配置...

    多人在线聊天系统源码 xmpp+openfire

    XMPP的核心设计原则是分散式和可扩展性,使得开发者可以轻松地添加新功能。在多人聊天系统中,XMPP负责处理用户的登录、注销、消息传递、群组管理等核心功能。用户通过连接到XMPP服务器,发送和接收消息,建立和管理...

    xmpp,openfire搭建ppt

    **XMPP与Openfire搭建详解** XMPP(Extensible Messaging and Presence Protocol)是一种基于XML的实时通讯协议,常用于构建即时通讯系统。它允许用户进行一对一、一对多的消息传输,同时还支持状态呈现、群组聊天...

    Socket TCP通信C# Winform控件封装,集成简单,服务端与客户端全涵盖,源码及应用案例一键下载

    内容概要:本文详细介绍了在C# Winform环境中实现Socket TCP通信的一种高效方式,即通过封装的服务端和客户端控件来简化开发流程。文中不仅讲解了控件的基本使用方法,如服务端监听、客户端连接、数据传输等核心功能,还探讨了控件内部的工作原理,包括异步通信、事件驱动机制以及线程安全管理等方面。此外,文章还提供了一些典型应用场景的具体实现,如聊天程序、文件传输等,帮助开发者更快地上手并解决实际问题。 适合人群:具有一定C#编程基础,希望快速掌握Socket TCP通信开发的程序员。 使用场景及目标:适用于需要在网络编程中快速搭建稳定可靠的通信系统的项目,旨在提升开发效率,降低开发难度,使开发者能够专注于业务逻辑而非底层通信细节。 其他说明:控件源码公开,便于进一步学习和定制化开发;附带多个应用案例源码,涵盖常见网络通信任务,有助于理解和实践。

    欧姆龙PLC CJ2M标准程序:12伺服电机与气缸控制,含轴点动等,模块齐全,流程明晰,含机器人通讯与界面操作指南

    内容概要:本文详细解析了欧姆龙CJ2M PLC控制系统的架构及其对12个伺服电机和气缸的控制方法。主要内容涵盖主控程序、手动模式、复位逻辑、定位控制、通讯与HMI交互以及生产计数模块。文中介绍了状态切换逻辑、伺服使能与时序处理、绝对与相对定位、EtherNet/IP通讯协议的应用、以及各种实用的调试技巧和常见问题解决方案。此外,强调了模块化设计思想和异常处理机制的重要性。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程有一定基础并希望深入了解欧姆龙CJ2M系列产品的读者。 使用场景及目标:帮助读者掌握复杂的多轴伺服控制系统的设计思路与实现方法,提高实际项目的开发效率和稳定性。适用于工业生产线、机器人集成等应用场景。 其他说明:文章提供了丰富的实战经验和代码片段,有助于读者更好地理解和应用相关技术和理念。

    QT步进电机上位机控制程序源代码:跨平台支持串口/TCP/UDP三种通信类型

    内容概要:本文介绍了基于QT框架开发的步进电机上位机控制程序,该程序支持串口、TCP、UDP三种通信方式,适用于不同操作系统(Windows、Linux、macOS)。文章详细讲解了各个通信方式的具体实现方法,包括代码示例和相关技术要点。此外,还讨论了跨平台适配、异常处理、线程安全等问题,并提供了实用的开发经验和优化建议。通过这种方式,开发者可以根据实际需求灵活选择最适合的通信方式,提高步进电机控制的精度和效率。 适合人群:具有一定编程基础,尤其是熟悉C++和QT框架的研发人员,以及从事自动化控制系统开发的技术人员。 使用场景及目标:①适用于各种自动化控制项目,如工业生产线、实验室设备等;②帮助开发者掌握跨平台开发技能,提升程序的兼容性和灵活性;③提供详细的代码实现和技术指导,便于快速搭建稳定的步进电机控制系统。 其他说明:文中不仅涵盖了基本的通信实现,还包括一些高级功能,如运动轨迹预测、电机参数自动识别等。同时强调了程序的稳定性和安全性,建议加入异常处理机制和紧急停止功能。

    少儿编程scratch项目源代码文件案例素材-回拨电话.zip

    少儿编程scratch项目源代码文件案例素材-回拨电话.zip

    少儿编程scratch项目源代码文件案例素材-回声石.zip

    少儿编程scratch项目源代码文件案例素材-回声石.zip

    基于FPGA的图像增强与去雾处理:暗通道先验算法的Matlab仿真及Quartus13.0实现(含浓雾与天空区域处理优化挑战)

    内容概要:本文详细介绍了将暗通道先验算法应用于FPGA平台进行图像去雾处理的技术实现过程。首先,作者在Matlab中展示了暗通道先验算法的基本原理和实现方法,包括计算暗通道、获取大气光值以及估算透射率等步骤。随后,重点讨论了如何在Quartus 13.0环境下利用Verilog语言将这些算法转换为硬件电路的具体实现方式,如构建最小值计算模块、大气光估计模块和透射率优化模块。此外,文中还探讨了在浓雾区域和天空区域处理中存在的问题及解决方案,指出了现有实现的局限性和未来的改进方向。 适合人群:从事图像处理、FPGA开发的研究人员和技术爱好者,尤其是对图像去雾算法感兴趣的开发者。 使用场景及目标:适用于希望深入了解暗通道先验算法在FPGA平台上实现的读者,旨在帮助他们掌握相关技术和解决实际应用中的难点。 其他说明:文章不仅提供了详细的理论解释和技术实现细节,还分享了许多实践经验,有助于读者更好地理解和应对可能出现的各种挑战。

    RK3568与356X开发全套资料:包括Demo原理图、PCB及SDK等全套资源,可直接使用,支持Allegro和PADS设计。

    内容概要:本文详细介绍了RK3568和RK356X系列处理器的开发资料,包括硬件原理图、PCB设计以及SDK开发。硬件部分提供了两种版本的PCB设计文件(Allegro和PADS),并附有详细的GPIO控制示例代码。软件部分则涵盖了Buildroot和Yocto双环境支持,以及多媒体开发示例,如视频播放功能。此外,还提供了丰富的库文件和开发示例,帮助开发者快速上手。文中还提到了一些常见的调试技巧和注意事项,如DDR初始化、电源配置等。 适合人群:嵌入式系统开发工程师、硬件设计师、软件开发者,尤其是那些希望深入理解和应用RK3568/356X平台的人群。 使用场景及目标:①硬件设计:通过原理图和PCB设计文件,帮助工程师快速构建硬件原型;②软件开发:借助SDK和示例代码,加速应用程序的开发和测试;③调试与优化:提供常见问题的解决方案和调试技巧,提高系统的稳定性和性能。 其他说明:资料总量达34GB,内容详尽全面,适用于从初学者到资深工程师的不同层次用户。建议新手先从外设驱动入手,逐步深入硬件设计和高级功能开发。

    基于电压电流双闭环的Vienna整流器SVPWM调制仿真

    内容概要:本文详细介绍了基于MATLAB/Simulink平台搭建Vienna整流器的电压电流双闭环控制系统以及空间矢量脉宽调制(SVPWM)的具体实现方法。首先探讨了电压外环采用带有前馈补偿的PI控制器来稳定直流侧电压,解决了传统PI控制器无法抑制电压波动的问题。接着深入分析了电流内环的设计,通过对比不同坐标系下的控制方式,选择了静止坐标系下的PR控制器以降低总谐波失真率(THD),并加入了谐振项提高基频响应能力。对于SVPWM调制部分,则着重讲解了扇区判断、作用时间和矢量选择等关键技术细节,确保调制波形的质量。此外,文中还分享了许多实用的小技巧,如参数设置、死区补偿及时序安排等方面的经验。 适合人群:从事电力电子研究的技术人员、高校相关专业师生及对Vienna整流器感兴趣的工程爱好者。 使用场景及目标:适用于希望深入了解Vienna整流器内部工作机制的研究者,在进行实验设计或者产品开发过程中可以作为参考资料;同时也为初学者提供了一个完整的项目案例,帮助他们掌握从理论到实践的操作流程。 其他说明:文中提供了大量MATLAB/Simulink代码片段供读者参考学习,强调了实际调试过程中的注意事项,有助于提升读者解决复杂工程问题的能力。

    少儿编程scratch项目源代码文件案例素材-光环:致远星火燎原.zip

    少儿编程scratch项目源代码文件案例素材-光环:致远星火燎原.zip

    基于2019A及以上版本Matlab代码的卷积-长短期记忆网络(CNN-LSTM)数据分类预测

    内容概要:本文详细介绍了如何利用Matlab实现卷积神经网络(CNN)与长短期记忆网络(LSTM)相结合的时间序列分类预测。首先,文章讲解了数据预处理步骤,包括数据生成、标准化以及划分训练集和测试集的方法。然后,重点阐述了CNN-LSTM模型的构建过程,具体涉及卷积层、池化层、LSTM层等关键组件的设计及其参数选择。此外,还讨论了训练选项的设置,如优化器的选择、学习率调度机制等,并提供了训练和评估模型的具体代码示例。最后,针对可能出现的问题提出了多种优化建议,例如调整卷积核大小、增加Dropout层、采用双向LSTM等方法。 适合人群:对时间序列数据分析感兴趣的科研人员、工程师以及希望深入理解深度学习应用于时间序列领域的学生。 使用场景及目标:适用于需要处理带有时空特性的时间序列数据的任务,如金融交易预测、医疗健康监测、工业设备故障诊断等领域。通过构建并优化CNN-LSTM模型,能够提高时间序列分类预测的准确性。 其他说明:文中提供的代码片段可以直接运行于Matlab R2019a及以上版本环境,同时附带了一些实用的小贴士帮助读者更好地理解和应用相关技术。

    LabVIEW Demo:压力位移监控软件与压装过程判断系统

    内容概要:本文介绍了一个使用LabVIEW开发的压力位移监控系统的实现细节。该系统主要用于监控压装过程中压力和位移的变化,通过采集卡或PLC获取数据并在XY图上实时绘制曲线。用户可以通过鼠标在XY图上拖动区域来设定合格范围,系统会自动判断曲线是否超出该区域,并在超出时发出警告。此外,系统还支持数据保存和历史数据回放功能,便于后续分析和调试。文中详细描述了数据采集、鼠标事件处理、曲线判断以及数据存储的具体实现步骤和技术要点。 适合人群:对LabVIEW有一定了解,从事工业自动化、数据采集和监控系统开发的技术人员。 使用场景及目标:适用于需要监控压装过程或其他类似工艺的工厂和实验室,帮助技术人员快速判断产品质量,提高生产效率和质量控制水平。 其他说明:文中提供了详细的代码片段和实现技巧,如坐标转换、事件处理、数据存储等,有助于读者更好地理解和应用LabVIEW进行相关项目的开发。

    Labview非标自动化软件:程序模块化新增,快速设备开发及自动化编程利器

    内容概要:本文介绍了利用LabVIEW进行非标自动化设备开发的一种创新方法——表格驱动开发。这种方法将传统的代码编写转变为通过Excel表格配置参数,从而大幅提高了开发效率和灵活性。文章详细描述了如何通过表格定义硬件配置、逻辑流程、状态机迁移以及变量管理等功能,并展示了具体的代码实现和应用案例。此外,还讨论了该方法的实际效果及其对开发流程的影响。 适合人群:从事非标自动化设备开发的工程师和技术人员,尤其是那些希望提高开发效率、减少重复劳动的人群。 使用场景及目标:适用于需要频繁调整硬件配置和逻辑流程的非标自动化项目。主要目标是通过简化开发流程,缩短开发周期,降低维护成本,使工程师能够专注于更高层次的设计和优化工作。 其他说明:该方法不仅提升了开发效率,还使得硬件兼容性和逻辑迭代变得更加容易。通过将复杂的技术细节封装在表格配置中,即使是新手也能快速上手,而经验丰富的工程师则可以集中精力于系统的性能优化和异常处理。

    二维码批量识别-未来之窗

    二维码批量识别工具,借助先进图像识别技术,能快速准确读取大量二维码信息。适用于物流与供应链管理,如库存盘点和货物追踪;可用于资产管理,像固定资产盘点与设备巡检;还能助力数据收集与市场调研,比如问卷调查与活动签到。它能将识别信息导出为 Excel 等常见表格,表格结构清晰,方便用户对海量二维码数据高效采集、整理与分析,大幅提升工作效率

    MADYMO软件:乘员安全分析与工程应用的专业工具

    内容概要:本文详细介绍了MADYMO软件在汽车安全仿真领域的应用,涵盖气囊折叠模拟、安全带建模、碰撞仿真等方面。MADYMO将多体动力学与显式有限元计算相结合,提供了高效且精准的解决方案。文中展示了如何利用XML定义气囊折叠路径、Fortran代码实现安全带接触力计算、Python脚本进行参数优化以及混合建模策略的应用。此外,还讨论了MADYMO在处理复杂接触问题、优化仿真效率方面的独特优势。 适合人群:从事汽车安全工程、碰撞仿真研究的专业人士和技术爱好者。 使用场景及目标:适用于需要进行汽车安全性能评估、碰撞测试优化、安全设备设计验证等场景。主要目标是提高仿真精度、缩短开发周期、降低实验成本。 其他说明:MADYMO以其强大的多体动力学和显式有限元耦合能力,在汽车安全仿真领域占据重要地位。通过合理的参数设置和混合建模策略,能够显著提升仿真的可靠性和效率。

    用于将zTC1插线板接入HOME ASSISTANT的YAML代码

    本代码用于将zTC1插线板通过自建的mqtt服务器接入homeassistant智慧家居系统。 前提是自己建了mqtt服务器。 安装homeassistant容器之后,在linux操作系统下的/opt/docker/homeassistant/config目录下可以找到configuration.yaml文件,用文本编辑器打开,将本资源的代码加进去。 注意,如果以前曾经添加过mqtt的sensor和switch实体,那么本代码中的sensor或switch就不需要了,将sensor下面的内容合并到以前的sensor下面代码后面,将switch下面的代码合并到以前的switch代码后面。

    Python遥感 - 栅格数据Sen+MK长时间序列趋势分析+显著性检验代码(附示例数据)

    本研究利用Sen+MK方法分析了特定区域内的ET(蒸散发)趋势,重点评估了使用遥感数据的ET空间变化。该方法结合了Sen斜率估算器和Mann-Kendall(MK)检验,为评估长期趋势提供了稳健的框架,同时考虑了时间变化和统计显著性。 主要过程与结果: 1.ET趋势可视化:研究利用ET数据,通过ET-MK和ET趋势图展示了蒸散发在不同区域的空间和时间变化。这些图通过颜色渐变表示不同的ET水平及其趋势。 2.Mann-Kendall检验:应用MK检验来评估ET趋势的统计显著性。检验结果以二元分类图呈现,标明ET变化的显著性,帮助识别出有显著变化的区域。 3.重分类结果:通过重分类处理,将区域根据ET变化的显著性进行分类,从而聚焦于具有显著变化的区域。这一过程确保分析集中在具有实际意义的发现上。 4.最终输出:最终结果以栅格图和png图的形式呈现,支持各种应用,包括政策规划、水资源管理和土地利用变化分析,这些都是基于详细的时空分析。 ------------------------------------------------------------------- 文件夹构造: data文件夹:原始数据,支持分析的基础数据(MOD16A2H ET数据 宁夏部分)。 results文件夹:分析结果与可视化,展示研究成果。 Sen+MK_optimized.py:主分析脚本,适合批量数据处理和自动化分析。 Sen+MK.ipynb:Jupyter Notebook,复现可视化地图。

Global site tag (gtag.js) - Google Analytics