首页 文章 精选 留言 我的

精选列表

搜索[便捷],共6722篇文章
优秀的个人博客,低调大师

🔥🔥🔥version-manager 版本更新,更便捷好用

项目地址: https://github.com/gvcgo/version-manager 文档地址: https://github.com/gvcgo/version-manager/blob/main/docs/readmeCN.md B 站视频演示教程地址: https://www.bilibili.com/video/BV1bZ421v7sD/?spm_id_from=333.1007.0.0&vd_source=1835c845bf533ce47c2b4d33db3419b5 Version-Manager(简称 vmr)是一款用 go 编写的超实用的跨平台 SDK 版本管理器。 它支持 40 多种编程语言和工具。 稳定流畅,无需插件,一键安装,开箱即用。 支持全局切换版本、在终端会话中临时切换版本、以及锁定项目版本等。 当锁定项目版本时,使用 vmr 注册的cdr命令切换到项目目录下的任何位置,就会自动开启新的终端会话并切换到锁定版本。退出该终端会话之后,锁定版本会失效,不影响全局版本。 即使你不需要 SDK 版本管理,你也可以把它当成一个方便的安装器。当你想要尝试其他语言或者工具时,就能一键安装,无需去麻烦地寻找各种资源。可以说是提高效率的利器。 目前很多来自腾讯、阿里、字节等大厂的,甚至是工作十几二十年的大佬都在使用 vmr ,并为 vmr 提供了很好的建议和意见。 欢迎大家去项目参观,star ,分享和使用。有兴趣的,可以贡献代码和想法。

优秀的个人博客,低调大师

9种常用便捷的Java异常处理方法,帮你脱身繁琐

前言 Java中的异常处理是个不简单的话题。初学者很难理解,即使是经验丰富的开发人员也可以花费数小时来讨论如何以及应该抛出或处理哪些异常。 这就是为什么大多数开发团队都有一套关于如何使用它们的规则的原因。而且,如果您是团队新手,那么您可能会感到惊讶,这些规则与您以前使用的规则有何不同。 尽管如此,大多数团队还是采用了几种最佳实践。以下是9个最重要的信息,它们可以帮助您入门或改善异常处理。 一、在finally块中清理资源或使用Try-With-resource语句 经常发生的是,您在try块中使用了一个资源,例如InputStream,之后需要关闭它。在这些情况下,常见的错误是在try块的末尾关闭资源。 publicvoiddoNotCloseResourceInTry(){ FileInputStreaminputStream=null; try{ Filefile=newFile("./tmp.txt"); inputStream=newFileInputStream(file); //usetheinputStreamtoreadafile //doNOTdothis inputStream.close(); }catch(FileNotFoundExceptione){ log.error(e); }catch(IOExceptione){ log.error(e); } }复制代码 问题在于,只要不引发异常,此方法似乎就可以很好地工作。try块中的所有语句将被执行,并且资源将被关闭。 但是您添加try块是有原因的。您调用一个或多个可能引发异常的方法,或者您可能自己引发异常。这意味着您可能未到达try块的末尾。因此,您将不会关闭资源。 因此,您应该将所有清理代码放入finally块中,或使用try-with-resource语句。 使用finally模块 与try块的最后几行相反,finally块始终执行。在成功执行try块之后或在catch块中处理了异常之后,就会发生这种情况。因此,可以确保清除所有打开的资源。 publicvoidcloseResourceInFinally(){ FileInputStreaminputStream=null; try{ Filefile=newFile("./tmp.txt"); inputStream=newFileInputStream(file); //usetheinputStreamtoreadafile }catch(FileNotFoundExceptione){ log.error(e); }finally{ if(inputStream!=null){ try{ inputStream.close(); }catch(IOExceptione){ log.error(e); } } } }复制代码 Java 7的Try-With-Resource语句另一个选择是try-with-resource语句,我在Java异常处理简介中对其进行了详细说明。 如果您的资源实现了AutoCloseable接口,则可以使用它。那就是大多数Java标准资源所做的。当您在try子句中打开资源时,将在try块执行或处理异常后自动关闭资源。 publicvoidautomaticallyCloseResource(){ Filefile=newFile("./tmp.txt"); try(FileInputStreaminputStream=newFileInputStream(file);){ //usetheinputStreamtoreadafile }catch(FileNotFoundExceptione){ log.error(e); }catch(IOExceptione){ log.error(e); } }复制代码 二、指定具体的异常 抛出的异常越具体越好。始终牢记,不知道您的代码,或者可能几个月后不知道您的代码的同事,需要调用您的方法并处理该异常。 因此,请确保为他们提供尽可能多的信息。这使您的API更易于理解。结果,您的方法的调用者将能够更好地处理该异常,或者通过额外的check避免该异常。 因此,请始终尝试查找最适合您的异常事件的类,例如,抛出NumberFormatException而不是. IllegalArgumentException。并避免引发不确定的Exception。 publicvoiddoNotDoThis()throwsException{ ... } publicvoiddoThis()throwsNumberFormatException{ ... }复制代码 整理了一下2021年的Java工程师经典面试真题,共485页大概850道含答案的面试题PDF,包含了Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等几乎所有技术栈,每个技术栈都有不少于50道经典面试真题,不敢说刷完包你进大厂,但有针对性的刷让你面对面试官的时候多几分底气还是没问题的。 三、对特定异常进行归档 每当在方法签名中指定异常时,也应在Javadoc中对其进行记录。这与以前的最佳实践具有相同的目标:为呼叫者提供尽可能多的信息,以便他可以避免或处理异常。 因此,请确保在Javadoc中添加一个@throws声明,并描述可能导致异常的情况。 /** *Thismethoddoessomethingextremelyuseful... * *@paraminput *@throwsMyBusinessExceptionif...happens */ publicvoiddoSomething(Stringinput)throwsMyBusinessException{ ... }复制代码 四、抛出异常的时候包含描述信息 最佳实践背后的想法与前两个类似。但是这一次,您没有将信息提供给您的方法的调用者。每个必须了解该日志文件或您的监视工具中报告该异常时发生的情况的人都可以阅读该异常的消息。 因此,它应尽可能准确地描述问题,并提供最相关的信息以了解异常事件。 不要误会我的意思;您不应该写一段文字。但是您应该用1-2个简短的句子来说明出现异常的原因。这可以帮助您的运营团队了解问题的严重性,还可以使您更轻松地分析任何服务事件。 如果抛出特定的异常,则其类名很可能已经描述了错误的种类。因此,您无需提供很多其他信息。一个很好的例子是NumberFormatException。当您以错误的格式提供String时,它将由类java.lang.Long的构造函数引发。 try{ newLong("xyz"); }catch(NumberFormatExceptione){ log.error(e); }复制代码 NumberFormatException类的名称已经告诉您问题的类型。它的消息仅需要提供引起问题的输入字符串。如果异常类的名称不那么具有表现力,则需要在消息中提供所需的信息。 17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz" 五、首先捕获最具体的异常 大多数IDE都可以帮助您获得最佳实践。当您尝试首先捕获不太具体的异常时,它们报告无法访问的代码块。 问题在于仅执行与异常匹配的第一个catch块。因此,如果您首先捕获IllegalArgumentException,那么您将永远不会到达应该处理更具体的NumberFormatException的catch块,因为它是IllegalArgumentException的子类。 始终首先捕获最具体的异常类,并将不那么具体的捕获块添加到列表的末尾。 您可以在以下代码片段中看到这样的try-catch语句的示例。第一个catch块处理所有NumberFormatException,第二个所有IllegalArgumentException,它们不是NumberFormatException。 publicvoidcatchMostSpecificExceptionFirst(){ try{ doSomething("Amessage"); }catch(NumberFormatExceptione){ log.error(e); }catch(IllegalArgumentExceptione){ log.error(e) } }复制代码 六、不要捕获Throwable异常 Throwable是所有异常和错误的超类。您可以在catch子句中使用它,但绝对不要这样做! 如果在catch子句中使用Throwable,它将不仅捕获所有异常,而且还捕获所有Exception。它还会捕获所有Error。JVM抛出严重的错误问题,这些问题不会由应用程序处理。 比如说:OutOfMemoryError或StackOverflowError。 两者都是由应用程序无法控制的情况引起的,无法处理。 因此,最好不要捕获Throwable,除非您完全确定自己处于特殊情况下,在这种情况下您能够或被要求处理错误。 publicvoiddoNotCatchThrowable(){ try{ //dosomething }catch(Throwablet){ //don'tdothis! } }复制代码 七、不要忽略异常 您是否曾经分析过仅在用例的第一部分得到执行的错误报告? 这通常是由忽略的异常引起的。开发人员可能非常确定不会将其抛出,并添加了一个不会处理或记录它的catch块。并且,当您找到该块时,您很可能甚至找到了著名的“这将永远不会发生”注释之一。 publicvoiddoNotIgnoreExceptions(){ try{ //dosomething }catch(NumberFormatExceptione){ //thiswillneverhappen } }复制代码 好吧,您可能正在分析一个不可能发生的问题。 因此,请不要忽略异常。您不知道将来的代码将如何更改。有人可能会删除阻止异常事件的验证,而没有意识到这会造成问题。或者,引发异常的代码被更改,现在引发同一个类的多个异常,并且调用代码并不能阻止所有这些异常。 您至少应该写一条日志消息,告诉所有人不可想象的事情刚刚发生,有人需要检查它。 publicvoidlogAnException(){ try{ //dosomething }catch(NumberFormatExceptione){ log.error("Thisshouldneverhappen:"+e); } }复制代码 八、不要记录和抛出 这可能是此列表中最常被忽略的最佳实践。您可以找到许多代码段,甚至可以找到捕获,记录和重新抛出异常的库。 try{ newLong("xyz"); }catch(NumberFormatExceptione){ log.error(e); throwe; }复制代码 记录发生的异常,然后将其重新抛出,以便调用者可以适当地处理它,这可能会很直观。但是它将为同一异常写入多个错误消息。 17:44:28,945ERRORTestExceptionHandling:65-java.lang.NumberFormatException:Forinputstring:"xyz" Exceptioninthread"main"java.lang.NumberFormatException:Forinputstring:"xyz" atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:65) atjava.lang.Long.parseLong(Long.java:589) atjava.lang.Long.(Long.java:965) atcom.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63) atcom.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58) 在com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)复制代码 其他消息也不会添加任何信息。如最佳做法4中所述,异常消息应描述异常事件。堆栈跟踪会告诉您在哪个类,方法和行中引发了异常。 如果需要添加其他信息,则应捕获异常并将其包装在自定义异常中。但是请确保遵循最佳实践9。 publicvoidwrapException(Stringinput)throwsMyBusinessException{ try{ //dosomething }catch(NumberFormatExceptione){ thrownewMyBusinessException("Amessagethatdescribestheerror.",e); } }复制代码 因此,仅在要处理它时才捕获异常。否则,请在方法签名中指定它,然后让调用者来处理它。 九、在不消耗异常的情况下包装异常 有时最好捕获一个标准异常并将其包装到自定义异常中。这种例外的典型示例是特定于应用程序或框架的业务例外。这使您可以添加其他信息,还可以对异常类实施特殊处理。 执行此操作时,请确保将原始异常设置为原因。该异常类提供了接受一个特定的构造方法的Throwable作为参数。否则,您将丢失堆栈跟踪和原始异常的消息,这将使分析导致您的异常的异常事件变得困难。 publicvoidwrapException(Stringinput)throwsMyBusinessException{ try{ //dosomething }catch(NumberFormatExceptione){ thrownewMyBusinessException("Amessagethatdescribestheerror.",e); } }复制代码 总结 综上所述,抛出或捕获异常时,您应该考虑很多不同的事情。他们中大多数人的目标是提高代码的可读性或API的可用性。 异常通常是同时存在的错误处理机制和通信介质。因此,您应该确保与同事讨论要应用的最佳实践和规则,以便每个人都能理解一般概念并以相同的方式使用它们。

优秀的个人博客,低调大师

每日一博 | 搭建 RocketMQ 服务器最便捷的方法

最近学习使用 rocketmq,需要搭建 rocketmq 服务端,本文主要记录 rocketmq 搭建过程以及这个过程踩到的一些坑。至于有多简单呢,在本机已有Docker环境的情况下只需要三步即可。 从github上面拉取项目 修改broker.conf中的brokerIP1 参数,修改为本机IP 进入docker-compose.yml文件所在路径,执行docker-compose up命令即可 前言 首先我们是使用Docker进行搭建环境的,所以我们先要在自己机器上的安装Docker,具体的安装过程以及对于Docker的介绍官方文档里面说的很清楚了https://docs.docker.com/get-started/。 我们要搭建RocketMQ服务器,那么我们就要知道大概搭建RocketMQ服务器需要部署哪些东西。对于RocketMQ有一个架构图,如下所示。而图中所示的Producer(生产者)和Consumer(消费者)无需我们搭建,因为那是作为一个服务器进行启动的。nameserver就是一个注册中心一样组件,我们可以将其简单理解成springcloud中的Eureka,那么nameserver是需要我们搭建的。broker就是真正处理消息的地方,也是需要我们搭建的。 正常情况我们搭建上面所提到的两个组件其实就能已经能够满足我们的发送接收消息的需求了。但是通常情况下我们还需要搭建一个Web可视化的平台用来查看MQ的服务状态、消息的消费情况、主题的队列配置等等。这里使用rocketmq-console。同样也是通过Docker来进行安装。 部署 上面我们提到了需要安装三个组件,那么这三个组件又是需要能够互相通信连接的,考虑到分开部署进行配置连接信息比较麻烦,于是这里我们采用docker-compose进行配置部署。 首先我们需要创建docker-compose.yml配置文件。文件内容如下 version: '3.5' services: rmqnamesrv: image: foxiswho/rocketmq:server container_name: rmqnamesrv ports: - 9876:9876 volumes: - ./logs:/opt/logs - ./store:/opt/store networks: rmq: aliases: - rmqnamesrv rmqbroker: image: foxiswho/rocketmq:broker container_name: rmqbroker ports: - 10909:10909 - 10911:10911 volumes: - ./logs:/opt/logs - ./store:/opt/store - ./conf/broker.conf:/etc/rocketmq/broker.conf environment: NAMESRV_ADDR: "rmqnamesrv:9876" JAVA_OPTS: " -Duser.home=/opt" JAVA_OPT_EXT: "-server -Xms128m -Xmx128m -Xmn128m" command: mqbroker -c /etc/rocketmq/broker.conf depends_on: - rmqnamesrv networks: rmq: aliases: - rmqbroker rmqconsole: image: styletang/rocketmq-console-ng container_name: rmqconsole ports: - 8080:8080 environment: JAVA_OPTS: "-Drocketmq.namesrv.addr=rmqnamesrv:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" depends_on: - rmqnamesrv networks: rmq: aliases: - rmqconsole networks: rmq: name: rmq driver: bridge 然后在与docker-compose.yml同级下面相应的建立三个文件夹conf、logs、store。然后在conf文件夹下面建立broker.conf配置文件,所有文件的目录位置如下所示。 docker-compose.yml conf - broker.conf logs store 然后在编写broker.conf配置文件里面的内容 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # 所属集群名字 brokerClusterName=DefaultCluster # broker 名字,注意此处不同的配置文件填写的不一样,如果在 broker-a.properties 使用: broker-a, # 在 broker-b.properties 使用: broker-b brokerName=broker-a # 0 表示 Master,&gt; 0 表示 Slave brokerId=0 # nameServer地址,分号分割 # namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876 # 启动IP,如果 docker 报 com.alibaba.rocketmq.remoting.exception.RemotingConnectException: connect to &lt;192.168.0.120:10909&gt; failed # 解决方式1 加上一句 producer.setVipChannelEnabled(false);,解决方式2 brokerIP1 设置宿主机IP,不要使用docker 内部IP brokerIP1=192.168.1.16 # 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数 defaultTopicQueueNums=4 # 是否允许 Broker 自动创建 Topic,建议线下开启,线上关闭 !!!这里仔细看是 false,false,false autoCreateTopicEnable=true # 是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭 autoCreateSubscriptionGroup=true # Broker 对外服务的监听端口 listenPort=10911 # 删除文件时间点,默认凌晨4点 deleteWhen=04 # 文件保留时间,默认48小时 fileReservedTime=120 # commitLog 每个文件的大小默认1G mapedFileSizeCommitLog=1073741824 # ConsumeQueue 每个文件默认存 30W 条,根据业务情况调整 mapedFileSizeConsumeQueue=300000 # destroyMapedFileIntervalForcibly=120000 # redeleteHangedFileInterval=120000 # 检测物理文件磁盘空间 diskMaxUsedSpaceRatio=88 # 存储路径 # storePathRootDir=/home/ztztdata/rocketmq-all-4.1.0-incubating/store # commitLog 存储路径 # storePathCommitLog=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/commitlog # 消费队列存储 # storePathConsumeQueue=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/consumequeue # 消息索引存储路径 # storePathIndex=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/index # checkpoint 文件存储路径 # storeCheckpoint=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/checkpoint # abort 文件存储路径 # abortFile=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/abort # 限制的消息大小 maxMessageSize=65536 # flushCommitLogLeastPages=4 # flushConsumeQueueLeastPages=2 # flushCommitLogThoroughInterval=10000 # flushConsumeQueueThoroughInterval=60000 # Broker 的角色 # - ASYNC_MASTER 异步复制Master # - SYNC_MASTER 同步双写Master # - SLAVE brokerRole=ASYNC_MASTER # 刷盘方式 # - ASYNC_FLUSH 异步刷盘 # - SYNC_FLUSH 同步刷盘 flushDiskType=ASYNC_FLUSH # 发消息线程池数量 # sendMessageThreadPoolNums=128 # 拉消息线程池数量 # pullMessageThreadPoolNums=128 配置文件中的内容我们只需要改动一点即可,即brokerIP1 这个属性,我们将其更改为我们本机的ip,可以利用ipconfig进行查看。 修改完以后我们直接在docker-compose.yml文件所在的位置输入命令docker-compose up即可启动。启动成功以后在浏览器中输入http://localhost:8080/即可看到管理页面,就表示我们搭建成功了。 使用Springboot快速上手 这里将会使用 springboot 快速上手使用 mq,将会使用rocketmq-spring-boot-starter模块。 pom 配置如下 <!--在pom.xml中添加依赖--> <dependency> <groupid>org.apache.rocketmq</groupid> <artifactid>rocketmq-spring-boot-starter</artifactid> <version>2.0.3</version> </dependency> gradle配置如下 implementation 'org.apache.rocketmq:rocketmq-spring-boot-starter:2.0.3' 消费服务发送方配置如下: ## application.properties rocketmq.name-server=ip:9876 rocketmq.producer.group=my-group 消费服务发送方程序如下: @SpringBootApplication public class ProducerApplication implements CommandLineRunner { @Resource private RocketMQTemplate rocketMQTemplate; public static void main(String[] args){ SpringApplication.run(ProducerApplication.class, args); } public void run(String... args) throws Exception { rocketMQTemplate.convertAndSend("test-topic-1", "Hello, World!"); rocketMQTemplate.send("test-topic-1", MessageBuilder.withPayload("Hello, World! I'm from spring message").build()); } } 这里图省事的话可以将消费者和生产者写道同一个项目中。 消息消费方配置如下: ## application.properties rocketmq.name-server=ip:9876 消息消费方运行程序如下: @SpringBootApplication public class ConsumerApplication{ public static void main(String[] args){ SpringApplication.run(ConsumerApplication.class, args); } @Slf4j @Service @RocketMQMessageListener(topic = "test-topic-1", consumerGroup = "my-consumer_test-topic-1") public static class MyConsumer1 implements RocketMQListener<string> { public void onMessage(String message) { log.info("received message: {}", message); } } } 到现在为止我们就可以在本机上快乐的试验各种关于RocketMQ的相关东西了。 RocketMQ的Docker配置文件存放处 RocketMQ的Docker配置文件存放处 RocketMQ的Docker配置文件存放处 大家可以直接从上面拉取项目,启动RocketMQ只需要两步。 修改broker.conf中的brokerIP1 参数,修改为本机IP 进入docker-compose.yml文件所在路径,执行docker-compose up命令即可 如果大家不想自己搭建Springboot项目的话,可以从https://github.com/modouxiansheng/Doraemon上面直接拉取下来就行了。</string>

优秀的个人博客,低调大师

Canonical 正在改进 CLA 流程,让开发者更便捷参与 Ubuntu 贡献

Canonical宣布,他们正在努力提升其贡献者许可协议流程,该流程多年来一直主要依靠人工操作。基于他们的新流程,贡献者许可协议处理变得更加简便,开发者参与贡献也更加迅速。 请注意,Canonical为其开发的围绕Ubuntu Linux的各种项目所使用的贡献者许可协议(CLA)本身并未改变,但签署CLA的流程正在得到改进。 新的Canonical CLA流程将允许通过GitHub的OAuth身份验证,或通过带有Ubuntu SSO单点登录的Launchpad更轻松地签署协议。对于签署CLA的组织,还有一个改进的协议流程。 如需了解更多关于新Canonical CLA流程的信息,请访问Ubuntu Discourse。

优秀的个人博客,低调大师

bg.work 权限管理实现完成,数据操作/界面显示控制更便捷

bg.work 权限管理实现 权限管理对有组织结构的系统重要性无需多言,没有权限限制的管理、办公系统将没有可用性可谈。说实话权限管理系统实现起来没有任何门槛,直接几个if else判断就能解决现实需求 ,但是,如果需要灵活、健壮、可维护、可扩展达,使整个开发组满意的的权限管理系统,那就另当别论了 bg.work的权限系统与本系统的数据与界面实现方式有着紧密的联系,所以在介绍权限系统前,我们要先介绍下数据与界面功能。 1、数据操作: bg.work在数据层设计了Model ORM,基本结构如下: //model对应数据库的表,基于model orm 实现,model字段可以动态读取,利用这一原则与权限系统结合,可以动态设置针对model数据控制 @Model("department", "部门") class Department:ContextModel("corp_department", "public") { companion object : RefSingleton<Department> { override lateinit var ref: Department } val id= ModelField(null, "id", FieldType.BIGINT, "标示", primaryKey = FieldPrimaryKey()) val name= ModelField(null, "name", FieldType.STRING, "名称") val comment = ModelField(null, "comment", FieldType.TEXT, "注释") } 2、界面定义 <!--基于model orm 框架,界面元素对应Model属性名称,基于这一原则,我们可以结合权限控制系统实现对界面的灵活控制--> <view type="list"> <field name="id"/> <field name="name" type="static"/> <field name="comment" type="static"/> </view> 对应界面: 3、bg.work权限系统框架结构 说明: Access Model Rule 控制Model(数据表) read:是否有权操作、读取字段设置、读取哪个用户数据、限制到什么部门、限制到个人/整个组织、限制到目标角色、附加条件等 delete:是否有权操作、删除哪个用户数据、限制到什么部门、限制到个人/整个组织、限制到目标角色、附加条件等 edit:是否有权操作、更新字段设置、更新哪个用户数据、限制到什么部门、限制到个人/整个组织、限制到目标角色、附加条件等 create:是否有权操作、添加字段设置 设置界面: Model UI Rule 对Model View 的限制 针对 model view 要展示的字段及操作按钮限制,每种 model都有对应的View Type 设置界面如下: App menu控制,也是针对管理系统的菜单进行控制: 五、总结 bg.work权限系统的加入,对后续功能的加入实现了直接控制,同时也实现了加入功能时不再考虑权限问题,所有的权限设置都推迟到系统部署或定制阶段 附加: bg.work 源码连接:鼓励请点赞 github:https://github.com/ouliuying/bgserver gitee:https://gitee.com/ouliuying/bgserver

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。