React权限管理系统实现

目录

一、需求

二、逻辑

三、实现

(一)代码

(二)解释

1. 获取权限对照数组 (queryReferencePermissionsInfo)

2. 获取处理对照数组 (queryDisposePermissionsInfo)

3. 获取权限映射表信息并处理 (queryPermissionsInfo)

4. 处理权限信息并获取指定模块和目标字典信息 (handlePermissionsInfo)

5. 获取相应app的权限信息 (queryAppPermissionsInfo)

6. 递归获取权限数组 (renderTreeNodes)

7. 处理权限信息并获取指定模块及目标权限的具体信息 (queryPermissionsChildren)

四、使用

五、总结


一、需求

        今年的4月份,我们的产品被甲方采购,并根据甲方需求更改了一下权限系统,由于原来的老旧权限系统过于臃肿且不够灵活,最重要的是没有注释看着很头大,于是我决定将权限系统重构。

二、逻辑

        其实逻辑很简单,就是将获取的权限数据进行处理然后通过传入不同的参数返回不同的处理后的数据。再用这些返回的数据进行页面上的权限控制。

三、实现

(一)代码

import globalUtil from '../utils/global';
import { formatMessage, FormattedMessage } from 'umi-plugin-locale';
import Exception from '../components/Exception'

const actionMaps = {
    admin: '管理员',
    developer: '开发者',
    viewer: '观察者',
    access: '访问者',
    owner: '拥有者'
};
const En_actionMaps = {
    admin: 'Administrators',
    developer: 'Developer',
    viewer: 'Observer',
    access: 'Visitor',
    owner: 'Owner'
};
const roleMaps = {
    admin: formatMessage({ id: 'utils.role.roleMaps_admin' }),
    app_store: formatMessage({ id: 'utils.role.roleMaps_app_store' })
};
const AccessText = {
    team_overview: '应用管理',
    team_app_create: '新建应用',
    team_app_manage: '应用控制',
    team_gateway_manage: '网关管理',
    team_plugin_manage: '插件管理',
    team_manage: '团队管理',
    app_overview: '应用总览',
    app_release: '应用发布',
    app_gateway_manage: '应用网关',
    app_upgrade: '应用升级',
    app_resources: '应用资源',
    app_config_group: '应用配置',
    route_manage: '路由管理',
    target_services: '目标服务',
    certificate: '证书管理',
    team_member: '成员管理',
    team_region: '集群管理',
    team_role: '角色管理',
    team_registry_auth: '镜像仓库授权管理',
    app_gateway_monitor: '网关监控',
    app_route_manage: '路由管理',
    app_target_services: '目标服务',
    app_certificate: '证书管理',
    team_gateway_monitor: '网关监控',
    team_route_manage: '路由管理',
    team_target_services: '目标服务',
    team_certificate: '证书管理',
    team_dynamic: '动态',
    team_overview_perms: '团队信息',
    app_backup: '应用备份',
    listed_manage: '上架管理',
    application_records: '申请记录',
    team_library_manage: '组件库',
};
const En_AccessText = {
    team_overview: 'Team overview',
    team_app_create: 'Create application',
    team_app_manage: 'Application management',
    team_gateway_manage: 'Gateway management',
    team_plugin_manage: 'Plug-in management',
    team_manage: 'Team management',
    app_overview: 'Application overview',
    app_release: 'Application publishing',
    app_gateway_manage: 'Application gateway',
    app_upgrade: 'Application upgrade',
    app_resources: 'Application resource',
    app_config_group: 'Application management',
    route_manage: 'Route management',
    target_services: 'Target service',
    certificate: 'Certificate management',
    team_member: 'Member management',
    team_region: 'Cluster management',
    team_role: 'Role management',
    team_registry_auth: 'Image warehouse authorization management',
    app_gateway_monitor: 'Gateway monitoring',
    app_route_manage: 'Route management',
    app_target_services: 'Target service',
    app_certificate: 'Certificate management',
    team_gateway_monitor: 'Gateway monitoring',
    team_route_manage: 'Route management',
    team_target_services: 'Target service',
    team_certificate: 'Certificate management',
    team_dynamic: 'Dynamic',
    team_overview_perms: 'Team information',
    app_backup: 'Application backup',
    listed_manage: 'Listed management',
    application_records: 'Application records',
    team_library_manage: 'Component library',
};

// 定义菜单与权限属性的映射结构
const teamMenuPermissionsMap = {
    team_overview_perms: 'isTeamOverview',//团队总览
    app_create: 'isTeamAppCreate',//新建应用
    team_gateway_monitor: 'isTeamGatewayMonitor',//网关监控
    team_route_manage: 'isTeamRouteManage',//路由管理
    team_target_services: 'isTeamTargetServices',//目标服务
    team_certificate: 'isTeamCertificate',//证书管理
    team_dynamic: 'isTeamDynamic',//动态
    team_region: 'isTeamRegion',//集群管理
    team_role: 'isTeamRole',//角色管理
    team_registry_auth: 'isTeamRegistryAuth',//镜像仓库授权管理
    team_plugin_manage: 'isTeamPluginManage',//插件管理
    application_records: 'isAudit',//申请记录
    listed_manage: 'isTeamPutaway',//上架管理
    team_library_manage: 'isTeamLibraryManage',//组件库
};

const appMenuPermissionsMap = {
    app_overview: 'isAppOverview', //应用总览
    app_release: 'isAppRelease',//应用发布
    app_upgrade: 'isAppUpgrade',//应用升级
    app_gateway_monitor: 'isAppGatewayMonitor',//网关监控
    app_route_manage: 'isAppRouteManage',//路由管理
    app_target_services: 'isAppTargetServices',//目标服务
    app_certificate: 'isAppCertificate',//证书管理
    app_resources: 'isAppResources',//应用资源
    app_config_group: 'isAppConfigGroup',//应用管理
    app_backup: 'isAppBackup',//应用备份
};
export default {
    // 身份
    actionMap(name, bool) {
        var keys = ''
        Object.keys(actionMaps).map(item => {
            if (actionMaps[item] == name) {
                return keys = item
            }
        })
        if (bool) {
            return actionMaps[keys] || name;
        } else {
            return En_actionMaps[keys] || name;
        }
    },
    // 角色
    roleMap(name) {
        return roleMaps[name] || name;
    },
    // 权限翻译
    fetchAccessText(text, bool) {
        if (bool) {
            return AccessText[text] || text;
        } else {
            return En_AccessText[text] || text;
        }
    },
    // 获取权限对照数组
    queryReferencePermissionsInfo(type) {
        const defaultTargetArr = [
            'describe',
            'create',
            'edit',
            'delete',
            'install',
            'uninstall'
        ];
        const defaultTargetOperationArr = ['start', 'stop', 'update', 'construct', 'copy', 'restart'];
        switch (type) {
            // 团队级别权限特殊处理
            case 'team_overview_perms':
                return ['describe', 'resource_limit', 'app_list']
                break;
            case 'team_app_create':
            case 'team_gateway_monitor':
            case 'app_gateway_monitor':
            case 'team_dynamic':
                return ['describe']
                break;
            // 应用级别特殊权限
            case 'app_release':
                return ['share', 'export', 'delete', 'describe']
                break;
            case 'app_upgrade':
                return ['app_model_list', 'upgrade_record', 'upgrade', 'rollback']
                break;
            // 组件与应用级别特殊权限
            case 'app_overview':
                return [
                    ...defaultTargetArr,
                    ...defaultTargetOperationArr,
                    ...[
                        'visit_web_terminal',
                        'service_monitor',
                        'telescopic',
                        'env',
                        'rely',
                        'storage',
                        'port',
                        'plugin',
                        'source',
                        'safety',
                        'other_setting'
                    ]
                ];
                break;
            case 'app_backup':
                return [
                    'describe',
                    'add',
                    'import',
                    'recover',
                    'move',
                    'expor',
                    'delete'
                ]
                break;
            default:
                return defaultTargetArr;
                break;
        }
    },
    // 获取处理对照数组
    queryDisposePermissionsInfo(type) {
        const defaultArr = [
            'isAccess',
            'isCreate',
            'isEdit',
            'isDelete',
            'isInstall',
            'isUninstall'
        ];
        const defaultOperationArr = ['isStart', 'isStop', 'isUpdate', 'isConstruct', 'isCopy', 'isRestart' ];
        switch (type) {
            // 团队级别权限特殊处理
            case 'team_overview_perms':
                return ['isAccess', 'isResourceLimit', 'isAppList']
                break;
            case 'team_app_create':
            case 'team_gateway_monitor':
            case 'app_gateway_monitor':
            case 'team_dynamic':
                return ['isAccess']
                break;
            // 应用级别特殊权限
            case 'app_release':
                return ['isShare', 'isExport', 'isDelete', 'isAccess']
                break;
            case 'app_upgrade':
                return ['isAppModelList', 'isUpgradeRecord', 'isUpgrade', 'isRollback']
                break;
            // 组件与应用级别特殊权限
            case 'app_overview':
                return [
                    ...defaultArr,
                    ...defaultOperationArr,
                    ...[
                        'isVisitWebTerminal',
                        'isServiceMonitor',
                        'isTelescopic',
                        'isEnv',
                        'isRely',
                        'isStorage',
                        'isPort',
                        'isPlugin',
                        'isSource',
                        'isSafety',
                        'isOtherSetting',
                    ]
                ];
                break;
            case 'app_backup':
                return [
                    'isAccess',
                    'isAddBackup',
                    'isImportBackup',
                    'isRecoverBackup',
                    'isMoveBackup',
                    'isExportBackup',
                    'isDeleteBackup'
                ]
                break;
            default:
                return defaultArr;
                break;
        }
    },
    /**
     * 获取权限映射表信息并进行处理
     *
     * @param {Object} data - 权限数据对象,包含团队或应用级别的权限信息
     * @param {string} module - 需要处理的目标模块名称
     * @param {string=} appid - (可选)应用ID,若提供,则查找对应应用的权限信息,否则查找团队级别的权限信息
     *
     * @returns {Object} - 返回一个对象,键为处理后的权限标识,值为对应的权限字典信息
    
     * 此函数首先调用queryDisposePermissionsInfo方法获取处理权限的动作列表(disposeActions),
     * 然后调用queryReferencePermissionsInfo方法获取权限对照数组(referencePermissions)。
     * 接着,遍历处理权限的动作列表,对每个动作调用handlePermissionsInfo方法,
       根据提供的module和appid获取对应权限字典信息,并将结果存入一个新的对象(permissionsObj)中,
       其中对象的键为处理权限的动作,值为该动作在目标模块下的权限字典详情。
     */
    queryPermissionsInfo(data, module, appid = '') {
        const disposeActions = this.queryDisposePermissionsInfo(module);
        const referencePermissions = this.queryReferencePermissionsInfo(module);
        const permissionsObj = {};

        disposeActions.forEach((item, index) => {
            permissionsObj[item] = this.handlePermissionsInfo(data, referencePermissions[index], module, appid);
        });

        return permissionsObj;
    },
    /**
     * 处理权限信息并获取指定模块和目标字典信息
     *
     * @param {Object} data - 权限数据对象,包含团队或应用级别的权限信息
     * @param {string} target - 需要查找的目标权限字典名称
     * @param {string} module - 需要查找的目标模块名称
     * @param {string=} appid - (可选)应用ID,若提供,则查找对应应用的权限信息,否则查找团队级别的权限信息
     *
     * @returns {Object|boolean} - 返回查找到的第一个匹配的权限字典信息,若未找到则返回false
     *
     * 此函数根据提供的appid参数决定查找团队还是应用级别的权限信息。
     * 如果appid存在,则先通过queryAppPermissionsInfo函数获取应用权限信息,再利用renderTreeNodes递归获取目标模块的权限信息,
     * 最后通过queryPermissionsChildren获取指定模块和目标字典的具体信息,并存入results数组。
     * 若appid不存在,则直接对团队权限数据进行类似操作。
     * 结束处理后,返回results数组中第一个(或唯一)找到的权限字典信息,若未找到任何匹配项,则返回false。
     */
    handlePermissionsInfo(data, target, module, appid = '') {
        const results = [];
        if (appid) {
            if (data && target && module) {
                const appInfo = this.queryAppPermissionsInfo(data, appid)
                const newAppInfo = this.renderTreeNodes(appInfo, module)
                this.queryPermissionsChildren(newAppInfo, module, target, results);
            }
        } else {
            if (data && target && module) {
                const teamInfo = this.renderTreeNodes(data, module)
                this.queryPermissionsChildren(teamInfo, module, target, results);
            }
        }
        return results.length > 0 ? results[0] : false;
    },

    /**
     * 获取相应app的权限信息
     *
     * @param {Object} data - 整体权限数据对象,通常包含一系列子模型
     * @param {string} appid - 需要查找的目标应用ID
     *
     * @returns {Object} - 返回与目标应用ID相对应的应用权限信息对象,若未找到则返回一个空对象 {}
     *
     * 此函数首先在整体权限数据对象的子模型中查找名为'team_app_manage'的部分,
     * 找到后,在'team_app_manage'的子模型中搜索与给定appid相匹配的应用权限信息,
     * 若找到匹配项,则返回该应用的权限信息对象;否则返回一个空对象。
     */
    queryAppPermissionsInfo(data, appid) {
        const appManagement = this.renderTreeNodes(data, 'team_app_manage');

        if (appManagement) {
            const appSubModels = appManagement.find((item) => Object.keys(item)[0] === 'team_app_manage').team_app_manage.sub_models || [];
            const targetApp = appSubModels.find((app) => Object.keys(app)[0] === appid);

            return targetApp ? targetApp[appid] : {};
        } else {
            return {};
        }
    },

    /**
     * 递归获取权限数组
     *
     * @param {Object[]} data - 权限数据结构,通常为一棵包含子模型(sub_models)的树形结构
     * @param {string} moduleName - 需要查找的目标权限模块名称
     *
     * @returns {Object[]|null} 返回与指定模块名称相符的权限数组,如果未找到,则返回null
     *
     * 此函数遍历给定的数据结构,逐层深入子模型直至找到与 moduleName 匹配的权限模块。
     * 当找到匹配项时,返回该模块所在层级的权限数组。若递归遍历完整棵树仍未找到匹配项,则返回null。
     */
    renderTreeNodes(data, moduleName) {
        const permissionsArr = data.sub_models || [];

        // 遍历当前层级的所有子模型
        for (let i = 0; i < permissionsArr.length; i++) {
            const item = permissionsArr[i];
            const keys = Object.keys(item)[0];

            // 如果当前节点的主键名称与目标模块名称相匹配,则直接返回当前层级的权限数组
            if (keys === moduleName) {
                return permissionsArr;
            }

            // 如果当前节点还包含子模型,并且子模型数量大于0,则递归查找
            if (item[keys] && item[keys].sub_models && item[keys].sub_models.length > 0) {
                const foundNode = this.renderTreeNodes(item[keys], moduleName);

                // 如果递归过程中找到了匹配的权限模块,则返回该模块的权限数组
                if (foundNode) {
                    return foundNode;
                }
            }
        }

        // 如果遍历完成仍没找到匹配的权限模块,则返回null
        return null;
    },

    /**
     * 处理权限信息并获取指定模块及目标权限的具体信息
     *
     * @param {Array<Object>} data - 权限数据列表,每个元素为一个包含模块名称及权限详细信息的对象
     * @param {string} moduleName - 需要检索的目标模块名称
     * @param {string} targets - 需要在目标模块中检索的具体权限名称
     * @param {Array<*>} results - 用于存储匹配到的权限详细信息的数组,函数执行结束后会填充相关数据
     *
     * @returns {void} 无返回值,而是通过修改传入的results参数来存储查找到的权限信息
     *
     * 此函数遍历给定的权限数据列表,查找与moduleName相匹配的模块,并在其中寻找与targets相匹配的权限详细信息。
     * 找到匹配项时,将该权限的详细信息推入results数组中。
     */
    queryPermissionsChildren(data, moduleName, targets, results) {
        return (data || []).map((item) => {
            const keys = Object.keys(item)[0];
            if (keys === moduleName) {
                item[keys].perms.map((item2) => {
                    const name = Object.keys(item2)[0];
                    if (targets === name) {
                        results.push(item2[targets]);
                    }
                });
            }
        });
    },
    /**
     * 通用权限获取方法
     *
     * @param {Object} menuMap - 菜单与权限属性的映射结构,键为菜单类型,值为权限对象上对应的属性名
     * @param {Object} data - 权限数据对象,包含各种菜单类型的权限信息
     * @param {string} appid - (可选)应用ID,默认为空字符串。在某些情况下可能需要根据应用ID获取特定应用的权限信息
     * @param {Function} permissionCheckStrategy - (可选)权限检查策略函数,默认为检查`.isAccess`属性是否存在。
     *                                         该函数接收一个菜单权限对象作为参数,并返回一个布尔值表示用户是否有该菜单的权限。
     *                                         对于特殊情况(如'app_upgrade'),可以通过传入自定义策略函数进行处理。
     *
     * @returns {Object} 返回一个对象,键为菜单类型对应的属性名,值为用户是否拥有该菜单的权限(布尔值)
     */
    queryMenuPermissionsInfo(menuMap, data, appid = '') {
        const obj = {};
        for (const [menuKey, propertyKey] of Object.entries(menuMap)) {
            const menuPermissions = this.queryPermissionsInfo(data, menuKey, appid);
            if (menuKey == 'app_upgrade') {
                obj[propertyKey] = menuPermissions?.isAppModelList || menuPermissions?.isUpgradeRecord || false;
            } else {
                obj[propertyKey] = menuPermissions?.isAccess || false;
            }
        }
        return obj;
    },
    /**
     * 根据团队或应用类型调用通用方法获取菜单权限
     *
     * @param {Object} data - 权限数据对象,包含各种菜单类型的权限信息
     * @param {'team'|'app'} type - 指定获取团队或应用的权限,取值只能为'team'或'app'
     * @param {string} appid - (可选)应用ID,默认为空字符串。当type为'app'时,可能需要根据应用ID获取特定应用的权限信息
     *
     * @returns {Object} 返回一个对象,键为菜单类型对应的属性名,值为用户是否拥有该菜单的权限(布尔值)
     *
     * 此方法根据传入的'type'参数自动选择合适的菜单权限映射表(teamMenuPermissionsMap或appMenuPermissionsMap),
     * 然后调用通用权限获取方法queryMenuPermissionsInfo,从而获取团队或应用的菜单权限信息。
     */
    queryTeamOrAppPermissionsInfo(data, type, appid = '') {
        return this.queryMenuPermissionsInfo(type == 'team' ? teamMenuPermissionsMap : appMenuPermissionsMap, data, appid);
    },
    // 没有权限
    noPermission() {
        return <Exception type={403} style={{ minHeight: 600, height: '80%' }} actions />
    }
};



(二)解释

1. 获取权限对照数组 (queryReferencePermissionsInfo)

此函数根据输入的type参数,返回不同场景下的一组基础权限列表。这些列表定义了不同模块或操作下所涉及的基本权限集,如“描述”、“创建”、“编辑”等。对于特定类型的权限(如团队级别、应用级别等),有专门的处理逻辑,返回特定的权限集合。这个函数是权限对照的基础,定义了系统支持的各种权限类型。

2. 获取处理对照数组 (queryDisposePermissionsInfo)

类似于queryReferencePermissionsInfo,但这里的数组是针对权限操作的处理逻辑,如“是否允许访问”、“是否允许创建”等。每个操作对应一个布尔型的检查方法,用于实际权限控制逻辑中的判断依据。这个函数进一步细化了权限的实际运用方式。

3. 获取权限映射表信息并处理 (queryPermissionsInfo)

这是整个权限处理流程的核心函数。它首先调用上述两个函数获取基础权限列表和处理逻辑列表,然后遍历处理逻辑列表,对每个逻辑调用handlePermissionsInfo函数。handlePermissionsInfo负责根据当前模块、目标权限字典以及是否针对特定应用来获取具体的权限字典信息。最终,queryPermissionsInfo会返回一个对象,其键为处理逻辑名称,值为对应的权限字典信息,实现了权限到操作的映射。

4. 处理权限信息并获取指定模块和目标字典信息 (handlePermissionsInfo)

该函数根据appid是否存在来区分处理团队或应用级别的权限。它首先调用queryAppPermissionsInfo或直接从团队权限数据开始处理,然后通过递归函数renderTreeNodes定位到目标模块,并通过queryPermissionsChildren在该模块下查找特定的权限信息。最后,它返回查找到的第一个匹配的权限字典信息,或在找不到时返回false

5. 获取相应app的权限信息 (queryAppPermissionsInfo)

此函数从整体权限数据中提取指定appid的应用权限信息。它首先找到“team_app_manage”部分,然后在其中查找与appid匹配的应用权限数据。

6. 递归获取权限数组 (renderTreeNodes)

这个递归函数用于在树形结构的权限数据中查找指定模块的权限数组。它遍历每一层的子模型,直到找到匹配的模块名或遍历完整棵树。

7. 处理权限信息并获取指定模块及目标权限的具体信息 (queryPermissionsChildren)

该函数遍历权限数据列表,定位到指定模块,并从中找出特定权限名称的详细信息,将其加入到结果数组中。

四、使用

import roleUtil from '../../utils/newRole';

roleUtil.queryPermissionsInfo(this.props.currentTeamPermissionsInfo && this.props.currentTeamPermissionsInfo.team, 'team_app_create'),

这是我的权限树结构,传进去的参数一个是树结构,一个是节点名称,这样返回出来的就是该节点下的所有权限。因为我们这里做了动态权限,所以也有可能传入第三个参数,用于辨认是否是查询某个app的权限列表,这里我就不再赘述,具体可以看上面的代码实现逻辑。

 

五、总结

        整个代码段构建了一套复杂的权限管理系统,能够根据不同的业务场景(如团队、应用级别等)动态地获取并处理权限信息。它通过分层次的函数调用,实现了权限数据的解析、筛选和具体化,以支持系统在运行时进行细粒度的权限控制。这套逻辑不仅灵活地适应了多种权限配置需求,而且保持了代码的模块化和可维护性。

        以上只是个人的实现思路,针对业务的不同不能生搬硬套,具体详细的使用请参照开源项目

https://github.com/goodrain/rainbond-ui/tree/V6.0icon-default.png?t=N7T8https://github.com/goodrain/rainbond-ui/tree/V6.0

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【分享】两种方法设置PDF“打开密码”

想要保护PDF文件的私密性&#xff0c;只允许特定人查看&#xff0c;我们可以给PDF设置“打开密码”&#xff0c;这样只有知道密码的人才可以打开文件。如果小伙伴们不知道如何设置&#xff0c;就一起看看以下两种方法吧&#xff01; 方法1&#xff1a;使用PDF编辑器 大部分PD…

【异常检测】MVTec LOCO AD 数据集

every blog every motto: There’s only one corner of the universe you can be sure of improving, and that’s your own self. https://blog.csdn.net/weixin_39190382?spm1010.2135.3001.5343 0. 前言 MVTec LOCO AD 数据集介绍 相比MVTec AD 增加了逻辑异常 1. 正文…

【grafana】创建多变量table

这个普罗米修斯的指标啊&#xff0c;大多数都是键值对&#xff0c;而且笔者如果没记错&#xff0c;他这个值还必须是浮点。少数可以设成离散值&#xff08;Enum&#xff09;&#xff0c;但本质还是一个带翻译功能的键值对 这样的好处是&#xff0c;做起来非常简单&#xff0c;…

Java环境配置(超详细)

Java环境配置&#xff08;超详细&#xff09; 引言1、安装 JDK1.1、下载安装JDK1.2、配置环境变量&#xff1a;JAVA_HOME1.3、将JAVA_HOME添加到Path中 2、安装 Maven2.1、下载安装Maven2.2、配置maven的环境变量: M2_HOME2.3、将Maven变量添加到Path中 引言 Java开发环境的配…

智能水位监测识别报警摄像机:保障水域安全的重要利器

随着城市化进程的加速和气候变化的影响&#xff0c;对水域安全的关注日益增加。为了及时监测水位变化并采取相应措施&#xff0c;智能水位监测识别报警摄像机应运而生。本文将介绍这一创新技术的应用和优势。 传统的水位监测方法通常依赖于传感器&#xff0c;但其存在着安装位置…

如何编辑pdf文件内容?3种PDF编辑方法分享

如何编辑pdf文件内容&#xff1f;在当今数字化时代&#xff0c;PDF文件因其跨平台兼容性和保持原样不变的特点&#xff0c;在办公、学习、生活等多个领域得到了广泛应用。然而&#xff0c;PDF文件的不可编辑性也让许多用户感到困扰。你是否曾经遇到过需要修改PDF文件内容&#…

java8升级到JDK21

一、版本升级 spring-boot升级到3.0以上 如果依赖了springcloud&#xff0c;则需要升级到对应spring-boot3.0的版本&#xff0c;最新依赖都是可行的。 依赖了springcloudAlibaba&#xff0c;则参考文档选择合适的依赖&#xff1a; 版本依赖关系&#xff1a; 文档地址&#x…

【谣传】不能完全取代HR

https://arxiv.org/pdf/2405.18113 这份研究论文提出了 MockLLM&#xff0c;一个利用大型语言模型&#xff08;LLM&#xff09;角色扮演能力来促进招聘场景中人和职位匹配的框架。它通过模拟面试过程来生成额外的匹配证据&#xff0c;从而提高匹配的准确性。 主要问题和挑战&am…

579页 | 工业数字孪生建模与应用(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 工业数字孪生建模与应用 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT/WORD解决方…

【Java】---- SpringBoot 统一数据返回格式

目录 1. 统一数据返回格式介绍2. 实际应用2.1 添加前后的返回结果区别2.2 存在问题 3. 统一数据返回格式的优点 1. 统一数据返回格式介绍 通过使用ControllerAdvice和引用ResponseBodyAdvice接口来进行实现。 ResponseBodyAdvice这个接口里面有两个方法&#xff0c;分别是: s…

实现教育数字化转型,选择智慧校园软件

在当今数字时代&#xff0c;教育数字化转型已经成为不可忽视的趋势。随着技术的不断发展&#xff0c;智慧校园软件正日益受到教育机构的关注。那么&#xff0c;为什么选择智慧校园软件能够成为实现教育数字化转型的最佳解决方案呢&#xff1f; 首先&#xff0c;智慧校园软件为教…

居民社区团购小程序源码系统 拼团管理+团长管理功能 带完整的安装代拿代码包以及搭建教程

系统概述 居民社区团购小程序源码系统是一款专为社区团购打造的一站式解决方案。它整合了拼团管理和团长管理等核心功能&#xff0c;能够帮助企业和创业者快速搭建自己的社区团购平台&#xff0c;实现高效运营和便捷管理。 代码示例 系统特色功能 1.拼团管理&#xff1a;支持…

用友NC downCourseWare 任意文件读取漏洞复现

0x01 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具,用友NC提供了一系列业务管理模块,包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等,帮助企业实现数字化转型和高效管理。 0x02 漏洞概述 用友NC 系统 /portal/pt/downCourseWare…

20240606在RK3588的Android12下使用adb pull出现权限问题Permission denied

adb root adb remount 20240606在RK3588的Android12下使用adb pull出现权限问题Permission denied 2024/6/6 11:48 缘起&#xff1a;想从Toybrick的TB-RK3588的Android12开发板上通过adb pull获取刚刚生成的edid.bin&#xff0c;老是报告权限问题。 百度&#xff1a;adb: error…

Mac 苹果电脑下载安装《植物大战僵尸杂交版2.0.88》详细指南教程(含已损坏打不开等问题解决)

最近植物大战僵尸杂交版可是非常的火爆&#xff0c;各大主播都在玩&#xff0c;可是该游戏作者只发布了win版本&#xff0c;我只有一台 Macbook 一直都很想玩&#xff0c;经过一番折腾终于在Mac上成功安装运行了该游戏&#xff0c;并整理好了&#xff0c;大家想要在 Mac 上安装…

【Altium】AD-原理图中使用多通道问题

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决在原理图主图中&#xff0c;对子图使用多通道命令后&#xff0c;子图未形成多个通道的问题。 2、 问题场景 客户手中的工程文件&#xff0c;主图中对子图使用了多通道命令&#xff0c;子图图纸并未形成多通道…

语音深度鉴伪识别项目实战:基于深度学习的语音深度鉴伪识别算法模型(三)音频去噪算法大全+Python源码应用

前言 深度学习技术在当今技术市场上面尚有余力和开发空间的&#xff0c;主流落地领域主要有&#xff1a;视觉&#xff0c;听觉&#xff0c;AIGC这三大板块。 目前视觉板块的框架和主流技术在我上一篇基于Yolov7-LPRNet的动态车牌目标识别算法模型已有较为详细的解说。与AIGC相…

C# Web控件与数据感应之 填充 HtmlTable

目录 关于 HtmlTable HtmlTable与BaseDataList的区别 准备数据源 ​范例运行环境 FillTable 方法 设计与实现 模板样例输出 Automatic 模式填充 ​ DynamicRows 模式填充 StaticRows 模式填充 ​ 小结 关于 HtmlTable 数据感应也即数据捆绑&#xff0c;是…

前端canvas绘图,利用canvas在图片上面绘制标记以及给canvas添加点击事件。

前端canvas绘图&#xff0c;利用canvas在图片上面绘制标记以及给canvas添加点击事件。 需要实现的效果如下图: 首先需要一个承载的核心画布 <canvas id"canvas" width"800" height"600"></canvas>全部代码&#xff1a; <!DOCT…

Web3的应用场景分析

Web3&#xff0c;即基于区块链技术的去中心化互联网&#xff0c;正逐渐改变我们与数字世界的互动方式。以下是Web3的一些主要应用场景。Web3技术正在各个领域推动创新&#xff0c;创造更多透明、开放和去中心化的解决方案&#xff0c;为用户带来更高的自主权和安全性。北京木奇…