`
hetylei
  • 浏览: 141247 次
  • 性别: 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的实时通讯协议,常用于构建即时通讯系统。它允许用户进行一对一、一对多的消息传输,同时还支持状态呈现、群组聊天...

    基于spring boot框架药品购买系统-a7imn57w.zip

    基于spring boot框架药品购买系统_a7imn57w.zip

    "基于滑模磁链的改进无位置控制技术:减小转矩脉动与抖振,降低电流THD并优化参数依赖",结合滑模和磁链的改进滑模磁链无位置控制,相比于传统的滑模观测器,能有效减小转矩脉动和抖振现象,降低电流THD

    "基于滑模磁链的改进无位置控制技术:减小转矩脉动与抖振,降低电流THD并优化参数依赖",结合滑模和磁链的改进滑模磁链无位置控制,相比于传统的滑模观测器,能有效减小转矩脉动和抖振现象,降低电流THD。 传统的磁链观测器对电气参数非常敏感,改进的磁链观测器将滑模控制率和磁链观测器结合,有效降低了对参数的依赖。 该模型针对特定的小电感电阻电机进行了验证。 ,核心关键词:滑模磁链无位置控制;改进滑模;磁链观测器;传统滑模观测器;电气参数依赖;电流THD;小电感电阻电机验证,好的,根据您提供的关键信息,提炼的标题如下: "结合滑模与磁链技术的改进型无位置控制策略,有效减小抖振与电流THD" 此标题直接体现了该策略结合了滑模和磁链技术,并有效减小了转矩脉动、抖振现象以及电流THD。希望符合您的要求。

    红外轮廓提取python代码

    红外轮廓提取python代码

    (源码)基于Raspberry Pi 3b的STM原子力显微镜控制系统.zip

    # 基于Raspberry Pi 3b的STM原子力显微镜控制系统 ## 项目简介 本项目是一个基于Raspberry Pi 3b的STM(扫描隧道显微镜)控制系统,旨在实现对原子力显微镜的高精度控制和图像采集。通过结合Arduino Uno和ADS1115、AD5764等硬件设备,项目实现了对显微镜的多种操作模式和图像处理功能。 ## 项目的主要特性和功能 1. 信号采集与控制 使用ADS1115进行z轴信号的采集。 通过Arduino Uno控制AD5764,实现对压电驱动器的精确控制。 2. 图像处理 实现3D图像的采集和处理。 3. 操作模式 支持两种操作模式 1. 恒高模式在扫描过程中保持高度恒定。 2. 恒流模式在扫描过程中保持电流恒定。 4. 粗略定位 使用步进电机进行粗略的初始定位。 ## 安装使用步骤 1. 硬件连接

    毕业设计&课程设计&毕设&课设-java-超市管理系统

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    在线课程管理系统 2024免费JAVA毕设

    2024免费毕业设计成品,包括源码+数据库+往届论文资料 录屏:https://www.bilibili.com/video/BV15S421o7Do 启动教程:https://www.bilibili.com/video/BV11ktveuE2d 讲解视频:https://www.bilibili.com/video/BV1YfkHYwEME 二次开发教程:https://www.bilibili.com/video/BV1Cw2rY1ErC

    【GO】关于一个分布式事务的中间件,目前通信是走的http协议.zip

    【GO】关于一个分布式事务的中间件,目前通信是走的http协议

    【爬虫】(天猫,淘宝,京东)爬虫,根据query词爬取数据(Python+Scrapy+MongoDB)_pgj.zip

    【爬虫】(天猫,淘宝,京东)爬虫,根据query词爬取数据(Python+Scrapy+MongoDB)_pgj

    基于三菱PLC与组态王技术的鸡舍温湿度智能控制系统在养鸡场的应用与优化-No.909解决方案,No.909 基于三菱PLC和组态王鸡舍温湿度控制养鸡场 ,三菱PLC; 温湿度控制; 鸡舍

    基于三菱PLC与组态王技术的鸡舍温湿度智能控制系统在养鸡场的应用与优化——No.909解决方案,No.909 基于三菱PLC和组态王鸡舍温湿度控制养鸡场 ,三菱PLC; 温湿度控制; 鸡舍养鸡场; 组态王控制系统; No.909,基于三菱PLC与组态王技术的鸡舍温湿度控制方案

    "三菱PLC与触摸屏联合开发气压传动焊条包装线技术详解",No.945 三菱PLC和触摸屏基于气压传动的焊条包装线的研发 ,核心关键词:三菱PLC; 触摸屏; 气压传动; 焊条包装线; 研

    "三菱PLC与触摸屏联合开发气压传动焊条包装线技术详解",No.945 三菱PLC和触摸屏基于气压传动的焊条包装线的研发 ,核心关键词:三菱PLC; 触摸屏; 气压传动; 焊条包装线; 研发; No.945,"三菱PLC与触摸屏在气压传动焊条包装线研发项目No.945中的应用"

    (源码)基于Spring Boot和Spring Integration的微服务购物系统.zip

    # 基于Spring Boot和Spring Integration的微服务购物系统 ## 项目简介 本项目是一个基于Spring Boot和Spring Integration的微服务购物系统,旨在提供一个高效、可扩展的在线购物平台。系统通过微服务架构实现各个功能模块的解耦,包括商品管理、购物车、订单处理、配送服务等。Spring Integration用于实现服务间的消息传递和集成。 ## 项目的主要特性和功能 1. 商品管理 商品的添加、删除和查询。 从京东网站抓取商品信息。 2. 购物车功能 添加商品到购物车。 从购物车中删除商品。 购物车结账生成订单。 3. 订单处理 订单的创建和状态管理。 订单的供应和结账流程。 4. 配送服务 根据订单生成配送信息。 配送状态的管理和查询。 5. 服务注册与发现

    基于Omron PLC与MCGS组态的自动化售货机控制系统研究与应用:No.848 实践探索与效果分析,No.848 基于Omron PLC和MCGS组态机控制 ,基于Omron PLC

    基于Omron PLC与MCGS组态的自动化售货机控制系统研究与应用:No.848 实践探索与效果分析,No.848 基于Omron PLC和MCGS组态机控制 ,基于Omron PLC; MCGS组态; 售货机控制; 848号项目,基于Omron PLC与MCGS组态的售货机控制系统研究No.848

    基于springboot+vue的人事工资管理系统设计与实现【源码+数据库】

    参考链接:https://www.bilibili.com/video/BV1ZYNHetEaY/?vd_source=bf2d43514ea61b1121399ab65421e37c 前端:Vue 后端:SpringBoot 数据库:MySQL 有数据库文件,项目完整 1、登录模块 可以登录成功和退出登录。 2、用户管理模块 可以添加、删除、修改、查询用户信息。 3、部门管理模块 可以添加、删除、修改、查询部门信息。 4、出勤管理模块 可以查询和编辑出勤信息。 5、工资管理模块 可以查询和编辑工资信息。 6、奖惩管理模块 可以添加、删除、修改、查询奖惩信息。 7、员工管理模块 可以添加、删除、修改、查询员工信息。

    昇腾硬件上面向算子开发场景的编程语言Ascend C的高阶类库ascendc-api-adv-master.zip

    昇腾硬件上面向算子开发场景的编程语言Ascend C的高阶类库ascendc-api-adv-master.zip

    "中央空调时间控制启停的优化:西门子1200PLC与TP900触摸屏模拟仿真程序在博途V16环境下的应用与探讨",中央空调改时间控制启停西门子1200PLC和TP900触摸屏模拟仿真程序博途V16

    "中央空调时间控制启停的优化:西门子1200PLC与TP900触摸屏模拟仿真程序在博途V16环境下的应用与探讨",中央空调改时间控制启停西门子1200PLC和TP900触摸屏模拟仿真程序博途V16 ,中央空调; 时间控制启停; 西门子1200PLC; TP900触摸屏; 模拟仿真程序; 博途V16,"中央空调的定时启停:Siemens 1200PLC与TP900触摸屏模拟仿真程序V16"

    Java多线程核心技术解析及常见面试题详解

    内容概要:这份PDF文档系统梳理了Java多线程的核心概念和技术,涵盖了基础知识、锁机制、线程池以及典型应用场景等关键主题。主要内容包括:多线程的基础知识点(并行与并发区分、线程和进程差异及其创建方式)、创建和使用线程的多种方式及其实现;详细讨论了几种常用的并发锁机制(synchronized、AQS、ReentrantLock等);深入介绍了不同类型的线程池及其配置参数的选择依据;探讨了常见的线程控制工具(如Semaphore和CountDownLatch);并讲解了一些高级话题(例如死锁检测与预防、ThreadLocal的作用)及相关的真实面试情景还原。 适用人群:对于具有一定Java编程经验、希望进一步掌握或复习多线程编程技巧的人士而言是非常有用的资料。特别适用于准备求职面试的技术人员。 使用场景及目标:该资料可以帮助开发者理解并发编程的基本原理,熟练运用各类同步原语和容器以构建高效的并发应用程序;此外,文中提供的面试指南有助于应聘者针对可能出现的技术难题做好充分准备。 其他说明:尽管本资料详尽地阐述了许多理论知识,但在实践中还需结合实际情况做出合理的优化决策。 适合人群:具有一定Java基础并且对多线程感兴趣的开发人员,尤其是那些想要深入了解多线程机制并对自己的职业发展有所规划的人。 使用场景及目标:帮助程序员加深对Java多线程编程技术的认知,提升应对复杂任务的能力;同时也是备战工作中可能遇到的各种多线程面试考题的有效参考资料。 阅读建议:此资源适合循序渐进地学习,先从简单的概念入手逐步过渡到较为复杂的主题,对于关键技术和实用的例子可以适当做一些练习加深理解和记忆。

Global site tag (gtag.js) - Google Analytics