前后端配合实现按钮级操作权限控制

背景

公司项目需要做到按钮级权限限制,至此有了该文,如有错误,请联系博主指出,多多感谢。

角色配置前后端操作

首先最基本的角色配置,配置该类角色有哪些菜单以及那些菜单的哪些按钮权限

菜单及菜单按钮由前端维护(或者也可以后端数据库维护)

前端维护一个JSON文件,直接读取渲染页面即可

JSON文件类似这样,定义菜单及菜单下按钮,声明唯一key和name(角色配置时需要存储对应菜单及按钮的key)

[
  {
    key: 'Home',
    menu: '首页',
  },
  {
    key: 'OrgManagement',
    menu: '组织管理',
    children: [
      {
        key: 'RoleConfig',
        menu: '角色信息配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'PersonnelConfig',
        menu: '人员信息配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'TeamsConfig',
        menu: '班组信息配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
    ],
  },
  {
    key: 'FacilityManagement',
    menu: '设施管理',
    children: [
      {
        key: 'LineManagement',
        menu: '线体管理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'DeviceManagement',
        menu: '设备管理',
        children: [
          {
            key: 'DeviceManagement_DeviceType',
            menu: '设备类型',
            disableSelect: true,
            checkPermissions: [],
            permissionOptions: [
              {
                key: 'add',
                name: '新增',
              },
              {
                key: 'edit',
                name: '编辑',
              },
              {
                key: 'delete',
                name: '删除',
              },
            ],
          },
          {
            key: 'DeviceManagement_Device',
            menu: '设备',
            disableSelect: true,
            checkPermissions: [],
            permissionOptions: [
              {
                key: 'add',
                name: '新增',
              },
              {
                key: 'edit',
                name: '编辑',
              },
              {
                key: 'delete',
                name: '删除',
              },
            ],
          },
        ],
      },
      {
        key: 'ComponentManagement',
        menu: '部件管理',
        children: [
          {
            key: 'ComponentManagement_ComponentType',
            menu: '部件类型',
            disableSelect: true,
            checkPermissions: [],
            permissionOptions: [
              {
                key: 'add',
                name: '新增',
              },
              {
                key: 'edit',
                name: '编辑',
              },
              {
                key: 'delete',
                name: '删除',
              },
            ],
          },
          {
            key: 'ComponentManagement_Component',
            menu: '部件',
            disableSelect: true,
            checkPermissions: [],
            permissionOptions: [
              {
                key: 'add',
                name: '新增',
              },
              {
                key: 'edit',
                name: '编辑',
              },
              {
                key: 'delete',
                name: '删除',
              },
            ],
          },
        ],
      },
    ],
  },
  {
    key: 'OamAlarm',
    menu: '运维报警',
    children: [
      {
        key: 'AlarmTemplate',
        menu: '报警模版',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'AlarmRecords',
        menu: '报警明细',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'ignore',
            name: '忽略',
          },
          {
            key: 'createOrder',
            name: '生成工单',
          },
          {
            key: 'oneKeyHandle',
            name: '一键处理',
          },
        ],
      },
      {
        key: 'AlarmWorkOrderRecords',
        menu: '工单明细',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'receive',
            name: '接单',
          },
        ],
      },
      {
        key: 'AlarmLevel',
        menu: '报警等级配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
    ],
  },
  {
    key: 'OamPatrol',
    menu: '运维巡检',
    children: [
      {
        key: 'PatrolTaskConfig',
        menu: '巡检任务配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'FrequencyRulesConfig',
        menu: '频率规则配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'DistributeRulesConfig',
        menu: '下发规则配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'PatrolTaskManagement',
        menu: '巡检任务处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'distribute',
            name: '下发',
          },
          {
            key: 'handle',
            name: '处理',
          },
        ],
      },
    ],
  },
  {
    key: 'Maintenance',
    menu: '维修保养',
    children: [
      {
        key: 'MaintenanceDeviceConfig',
        menu: '维保设备配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },

      {
        key: 'MaintenancePlanConfig',
        menu: '维保计划配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },

      {
        key: 'MaintenanceRemindConfig',
        menu: '维保提醒配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },

      {
        key: 'MaintenanceTaskManagement',
        menu: '维保任务处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'distribute',
            name: '下发',
          },
        ],
      },
    ],
  },
  {
    key: 'SpareParts',
    menu: '备品备件',
    children: [
      {
        key: 'WarehouseConfig',
        menu: '库房库位配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'SpareTypeConfig',
        menu: '备件类型配置',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },
      {
        key: 'SpareAccountManagement',
        menu: '备件台帐管理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
        ],
      },

      {
        key: 'PurchaseApply',
        menu: '采购申请',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'examine',
            name: '审核',
          },
          {
            key: 'createPurchaseOrder',
            name: '生成采购单',
          },
        ],
      },

      {
        key: 'ArrivalManagement',
        menu: '到货处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'confirm',
            name: '到货确认',
          },
          {
            key: 'entry',
            name: '生成入库',
          },
        ],
      },

      {
        key: 'EntryStorageManagement',
        menu: '入库处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'entry',
            name: '入库',
          },
        ],
      },

      {
        key: 'ExitStorageApply',
        menu: '出库申请',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'examine',
            name: '审核',
          },
        ],
      },

      {
        key: 'ExitStorageManagement',
        menu: '出库处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'exit',
            name: '出库',
          },
        ],
      },

      {
        key: 'ExitEntryStorageRecords',
        menu: '出入库记录',
      },

      {
        key: 'StocktakingManagement',
        menu: '盘库处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'stocktaking',
            name: '盘库',
          },
        ],
      },

      {
        key: 'TransferManagement',
        menu: '调库处理',
        checkPermissions: [],
        permissionOptions: [
          {
            key: 'add',
            name: '新增',
          },
          {
            key: 'edit',
            name: '编辑',
          },
          {
            key: 'delete',
            name: '删除',
          },
          {
            key: 'handle',
            name: '处理',
          },
        ],
      },
    ],
  },
  {
    key: 'Dict',
    menu: '数据字典',
  },
  {
    key: 'Knowledge',
    menu: '知识库',
    checkPermissions: [],
    permissionOptions: [
      {
        key: 'add',
        name: '新增',
      },
      {
        key: 'edit',
        name: '编辑',
      },
      {
        key: 'delete',
        name: '删除',
      },
    ],
  },
]

根据上述JSON文件,渲染出的角色权限编辑页面如下:

image-20231031125412416

该页面可以配置角色菜单及按钮权限,前端请求参数如下:

{
  "roleName": "库管员",
  "roleSort": 1,
  "remark": "库管员",
  "menuIds": [
    "SpareParts",
    "WarehouseConfig",
    "SpareTypeConfig",
    "SpareAccountManagement",
    "PurchaseApply",
    "ArrivalManagement",
    "EntryStorageManagement",
    "ExitStorageApply",
    "ExitStorageManagement",
    "ExitEntryStorageRecords",
    "StocktakingManagement",
    "TransferManagement"
  ],
  "permissions": [
    "WarehouseConfig/add",
    "WarehouseConfig/edit",
    "WarehouseConfig/delete",
    "SpareTypeConfig/add",
    "SpareTypeConfig/edit",
    "SpareTypeConfig/delete",
    "SpareAccountManagement/add",
    "SpareAccountManagement/edit",
    "SpareAccountManagement/delete",
    "PurchaseApply/add",
    "PurchaseApply/edit",
    "PurchaseApply/delete",
    "PurchaseApply/examine",
    "PurchaseApply/createPurchaseOrder",
    "ArrivalManagement/confirm",
    "ArrivalManagement/entry",
    "EntryStorageManagement/add",
    "EntryStorageManagement/edit",
    "EntryStorageManagement/delete",
    "EntryStorageManagement/entry",
    "ExitStorageApply/add",
    "ExitStorageApply/edit",
    "ExitStorageApply/delete",
    "ExitStorageApply/examine",
    "ExitStorageManagement/add",
    "ExitStorageManagement/delete",
    "ExitStorageManagement/exit",
    "StocktakingManagement/add",
    "StocktakingManagement/edit",
    "StocktakingManagement/delete",
    "StocktakingManagement/stocktaking",
    "TransferManagement/add",
    "TransferManagement/edit",
    "TransferManagement/delete",
    "TransferManagement/handle"
  ]
}

后端需要将该角色有的菜单权限及按钮权限存起来,存在sys_role表中,表结构如下:

image-20231031130430532

主要关注划红线的两个字段,将上述请求参数,分别用逗号隔开存与这两个字段(菜单以及按钮权限)中,此时角色菜单级及按钮级权限以维护好!(此时可以创建有不同操作权限的角色了)

新增用户时,就可以直接选择对应角色,维护好用户和角色的对应关系,用户就有了对应角色的权限了(用户登录后,查询用户对应菜单权限以及按钮权限,前端可以直接根据返回权限展示菜单及按钮权限【此时连菜单权限也一并做了】)。

其实到这里基本就不会有什么问题了,不同角色用户,只能操作自己有的权限操作。

但是以防万一,后端对应接口加个校验会更加安全。

后端权限校验

注解校验

因为后端用的Java的springBoot框架,可以很方便的进行aop操作。使用注解来实现鉴权操作。

注解如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface RequiresPermissions
{
    /**
     * 需要校验的权限码
     */
    String[] value() default {};

    /**
     * 验证模式:AND | OR,默认AND
     *(这个属性对应场景如下:
     * 前端有多个按钮操作可能是调用一个接口/
     * 后端新增或者编辑定义的是一个接口)
     * 前者属性用 OR,后者用 AND 【权限会存在 and/or 的关系】
     */
    Logical logical() default Logical.AND;
}

aop切面类

@Aspect
@Component
public class PreAuthorizeAspect
{
    /**
     * 构建
     */
    public PreAuthorizeAspect()
    {}

    /**
     * 定义AOP签名 (切入所有使用鉴权注解的方法)【切点】
     */
    public static final String POINTCUT_SIGN = " @annotation(com.smart.common.security.annotation.RequiresLogin) || "
            + "@annotation(com.smart.common.security.annotation.RequiresPermissions) || "
            + "@annotation(com.smart.common.security.annotation.RequiresRoles)";

    /**
     * 声明AOP签名
     */
    @Pointcut(POINTCUT_SIGN)
    public void pointcut()
    {}

    /**
     * 环绕切入
     * 
     * @param joinPoint 切面对象
     * @return 底层方法执行后的返回值
     * @throws Throwable 底层方法抛出的异常
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable
    {
        // 注解鉴权
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        checkMethodAnnotation(signature.getMethod());
        try
        {
            // 执行原有逻辑
            Object obj = joinPoint.proceed();
            return obj;
        }
        catch (Throwable e)
        {
            throw e;
        }
    }

    /**
     * 对一个Method对象进行注解检查
     */
    public void checkMethodAnnotation(Method method) {
        // 校验 @RequiresLogin 注解
        RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class);
        if (requiresLogin != null) {
            AuthUtil.checkLogin();
        }

        // 校验 @RequiresRoles 注解
        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
        if (requiresRoles != null) {
            AuthUtil.checkRole(requiresRoles);
        }

        // 校验 @RequiresPermissions 注解 【主要看这个校验逻辑】
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
        if (requiresPermissions != null) {
            AuthUtil.checkPermi(requiresPermissions);
        }
    }
}

核心处理逻辑在这AuthUtil.checkPermi

    public void checkPermi(RequiresPermissions requiresPermissions) {
	SecurityContextHolder.setPermission(StringUtils.join(requiresPermissions.value(), ","));
		// 判断是否有所有权限或者是单个权限就可以
        if (requiresPermissions.logical() == Logical.AND) {
            checkPermiAnd(requiresPermissions.value());
        }
        else {
            checkPermiOr(requiresPermissions.value());
        }
    }

checkPermiAnd 权限与逻辑,所有权限满足才能调用该方法

    public void checkPermiAnd(String... permissions) {
        Set<String> permissionList = getPermiList();
        for (String permission : permissions) {
            if (!hasPermi(permissionList, permission)) {
                throw new NotPermissionException(permission);
            }
        }
    }

hasPermi逐个判断是否有对应操作权限,只要一个不满足直接抛异常。

checkPermiOr 权限或逻辑,只要有权限满足就能直接调用该方法

    public void checkPermiOr(String... permissions) {
        // 登录后将用户信息存在ThreadLocal中,直接获取登录用户操作权限列表
        Set<String> permissionList = getPermiList();
        for (String permission : permissions) {
            if (hasPermi(permissionList, permission)) {
                return;
            }
        }
        if (permissions.length > 0) {
            throw new NotPermissionException(permissions);
        }
    }
    // 所有权限标识
	private static final String ALL_PERMISSION = "*:*:*";

	// 【or 逻辑】走到这里,只要一个满足条件直接结束,鉴权结束,不会抛异常
	public boolean hasPermi(Collection<String> authorities, String permission) {
        // 前半段校验是否有所有权限,后半段匹配当前权限是否在当前用户权限中
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission));
    }

接口使用的话就比较简单了,直接加个注解添加最开始前端传给后端保存的操作标识即可,如下:

image-20231031154546860

这下前后端双保险,按钮级操作权限到此已经实现。撒花✿✿ヽ(°▽°)ノ✿

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

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

相关文章

kali搭建docker

kali搭建docker 更新kali源 sudo apt update出错 更新一下密钥 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ED444FF07D8D0BF6安装docker sudo apt install docker.io -y #安装docker docker -v #docker版本 sudo systemctl status docker #查看docker…

C语言数据结构之数据结构入门

目录 数据结构介绍 数据结构发展史 何为算法 数据结构基础 基本概念和术语 四大逻辑结构&#xff08;Logic Structure&#xff09; 数据类型 理解复杂度概念 时间空间复杂度定义 度量时间复杂度的方法 程序运行时的内存与地址 编程预备 数据结构介绍 数据结构发展…

CSS+Javascript+Html日历控件

最近&#xff0c;因需要用HTMLJAVASCRIPTCSS实现了一个日历控件&#xff0c;效果如下&#xff1a; 单击上月、下月进行日历切换。当前日期在日历中变颜色标注显示。还是老老套路、老方法&#xff0c;分HMLCSSJAVASCRIPT三部分代码。 一、html代码 <h1>学习计划</h1…

1.6 基本安全设计准则

思维导图&#xff1a; 1.6 基本安全设计准则笔记 目标&#xff1a;理解和遵循一套广泛认可的安全设计准则&#xff0c;以指导保护机制的开发。 主要准则&#xff1a; 机制的经济性&#xff1a;安全机制应设计得简单、短小&#xff0c;便于测试和验证&#xff0c;减少漏洞和降…

ES 8.x新特性一览(完整版)

一、看点 在 2022 年 2 月 11 日&#xff0c;Elasticsearch&#xff08;ES&#xff09;正式发布了 8.0 版本&#xff0c;而截止到 2023 年 10 月&#xff0c;历经一年半时间&#xff0c;ES官方已经连续发布了多个版本&#xff0c;最新版本为 8.10.4。这一系列的更新引入了众多引…

【算法|动态规划No.32 | 完全背包问题】完全背包模板题

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

如何知道服务器的某个端口是否打开

1、telnet 命令&#xff1a;telnet ip port&#xff0c;port即端口&#xff0c;我们一般最常见的命令就是telnet&#xff0c;但是telnet使用的是tcp协议&#xff0c;换句话说telnet只能检测tcp的这个端口打开了没 若是端口打开&#xff0c;会出现下列信息 失败的是这个 如…

Linux 块设备驱动实验

前面我们都是在学习字符设备驱动&#xff0c;本章我们来学习一下块设备驱动框架&#xff0c;块设备驱动是Linux 三大驱动类型之一。块设备驱动要远比字符设备驱动复杂得多&#xff0c;不同类型的存储设备又对应不同的驱动子系统&#xff0c;本章我们重点学习一下块设备相关驱动…

Elasticsearch:使用 Elasticsearch 进行词汇和语义搜索

作者&#xff1a;PRISCILLA PARODI 在这篇博文中&#xff0c;你将探索使用 Elasticsearch 检索信息的各种方法&#xff0c;特别关注文本&#xff1a;词汇 (lexical) 和语义搜索 (semantic search)。 使用 Elasticsearch 进行词汇和语义搜索 搜索是根据你的搜索查询或组合查询…

【Java 进阶篇】Java BeanUtils 使用详解

Java中的BeanUtils是一组用于操作JavaBean的工具&#xff0c;它允许你在不了解JavaBean的具体内部结构的情况下&#xff0c;访问和修改其属性。本文将详细介绍Java BeanUtils的使用&#xff0c;包括如何获取和设置JavaBean的属性&#xff0c;复制属性&#xff0c;以及如何处理嵌…

Prometheus接入AlterManager配置钉钉告警(基于K8S环境部署)

文章目录 一、钉钉群创建报警机器人二、安装Webhook-dingtalk插件三、配置Webhook-dingtalk插件对接钉钉群四、配置AlterManager告警发送至Webhook-dingtalk五、Prometheus接入AlterManager配置六、部署PrometheusAlterManager(放到一个Pod中)七、测试告警 注意&#xff1a;请基…

使用Nokogiri和OpenURI库进行HTTP爬虫

目录 一、Nokogiri库 二、OpenURI库 三、结合Nokogiri和OpenURI进行爬虫编程 四、高级爬虫编程 1、并发爬取 2、错误处理和异常处理 3、深度爬取 总结 在当今的数字化时代&#xff0c;网络爬虫已经成为收集和处理大量信息的重要工具。其中&#xff0c;Nokogiri和OpenUR…

深入理解数据结构(2)——用数组实现队列

数组是一种数据结构&#xff0c;队列也是一种数据结构。它们都是由基础的语法实现的。 如果一个数据结构可以用另外的数据结构来实现&#xff0c;那么可以有力的证明——“数据结构是一种思想”&#xff0c;是一种讲语法组合起来实现某种功能的手段 “整体大于局部” 一、队列的…

SpringSecurity6 | HelloWorld入门案例

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

腾讯云优惠券如何领取?详细教程来了!

腾讯云优惠券是腾讯云为广大用户提供的优惠福利&#xff0c;包括代金券和折扣券&#xff0c;大家可以通过领取优惠券&#xff0c;在购买腾讯云产品时享受优惠。本文将为大家介绍如何领取腾讯云优惠券&#xff0c;以及领取后的使用规则。 一、腾讯云优惠券领取方法 腾讯云优惠券…

视频讲解|考虑源荷两侧不确定性的含风电电力系统低碳调度

目录 1 主要内容 2 讲解视频 1 主要内容 本次程序讲解对应程序链接考虑源荷两侧不确定性的含风电电力系统低碳调度&#xff0c;主要实现了基于模糊机会约束的源荷两侧不确定性对含风电电力系统低碳调度的影响&#xff0c;将源荷不确定性采用清晰等价类进行处理。部分讲解重点…

11.与JavaScript深入交流-[js一篇通]

文章目录 1.变量的使用1.1基本用法1.2理解 动态类型 2.基本数据类型2.1number 数字类型2.1.1数字进制表示2.1.2特殊的数字值 2.2string 字符串类型2.2.1基本规则2.2.2转义字符2.2.3求长度2.2.4字符串拼接 2.3boolean 布尔类型2.4undefined 未定义数据类型2.5null 空值类型 3.运…

原生JS 表格列拖拽 适用JqGrid

js $(function () {var d1 new dragTable();d1.init({tabel: .drag-table}); })function dragTable() {this.disX 0; // 相对按下的位置移动的距离this.outX 0; // 鼠标按下的点到大盒子边上的距离this.lanX 0; // 拖动到的位置this.$createDiv null;this.$createDivBg …

缓存和数据库一致性解决方案

引入缓存提高性能 如果你的业务处于起步阶段&#xff0c;流量非常小&#xff0c;那无论是读请求还是写请求&#xff0c;直接操作数据库即可&#xff0c;这时你的架构模型是这样的&#xff1a; 但随着业务量的增长&#xff0c;你的项目请求量越来越大&#xff0c;这时如果每次都…