首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

Tangdao 2.0.1 发布,更新前后分离,完成基础角色权限,数据权限组件

Tangdao 是基于角色的权限管理系统(RBAC),采用Springboot开发。系统简单易懂,前端使用Vue、Quasarframework开发,页面简洁美观。后端核心框架使用Springboot、Mybatis-plus、SpringSecurity为主要,扩展基于框架的权限校验、参数校验、统一异常、统一响应的通用功能。 预览效果 前端使用: Vue、Quasarframework开发,页面简洁美观 后端使用:Springboot、Mybatis-plus主要框架开发,封装统异常处理,认证,数据权限 前端地址 后端地址 本次更新: 1、项目结构调整,使用优秀的开源工具包,简化项目重复开发量。 2、数据权限组件,简化数据权限开发流程使用注解配置的方式。 其他: 1、前端使用Vue Quasarframework框架,目前看ts写的比较全也比较好的组件框架。 2、开发业务功能如:社区、商品、支付等模块方便快捷。 3、第三方登录对接 4、微信生态小程序等接口对接 注:佛系开发,无任何计划规划。有问题可以 issues 错误问题会修复。 Copyright 2020 ruyangit Inc. Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0

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

每日一博 | 一道快速考察 Python 基础的面试题

这是前一阵子群友发在群里的一道面试题,利用 Python 字典的特性,可以巧妙地使用精简代码达成完美解。 题目 将 data 转换成 new_data 这种形式,写出转换过程。 data = { 'a_b_h':1, 'a_b_i':2, 'a_c_j':3, 'a_d':4, 'a_c_k':5, 'a_e':6 } new_data = { 'a':{ 'b':{ 'h':1, 'i':2 }, 'c':{ 'j':3, 'k':5 }, 'd':4, 'e':6 } } 可以看出,转换的过程是将 key 的下划线进行拆分,然后下划线后边的字符嵌套在前面字符的值中。 感兴趣就打开 IDE,自己先试着解一下。 解题思路 你应该很快想到,主要思路是将下划线 split 后,然后依次使用字符生成内层字典,当达到最后一个字符时将数字作为值。 那么关键点在于,如何不断地获得内层字典去修改呢?实际本题就是考察你是否理解 Python 字典是引用传递这个特性。 什么是引用传递?我们知道 Python 中字典和列表对象都是可变对象,它们的变量传递给另一个变量后,改变对象元素会使得两个变量都会同时改变,比如: new_data = {} tmp = {} new_data['a'] = tmp print(new_data) # {'a': {}} tmp['b'] = 1 print(new_data) # {'a': {'b': 1}} 如上,利用这个特性,将内层字典赋值给一个中间变量,然后改变这个中间变量,即可同步修改最终的 new_data 变量。 根据这个思路,初步代码如下: data = { 'a_b_h':1, 'a_b_i':2, 'a_c_j':3, 'a_d':4, 'a_c_k':5, 'a_e':6 } new_data = {} for key, value in data.items(): keys = key.split('_') tmp = new_data last = len(keys) - 1 # 最后一个 key 的索引值 for i, k in enumerate(keys): if i == last: tmp[k] = value continue if k not in tmp: sub_tmp = {} tmp[k] = sub_tmp tmp = sub_tmp else: tmp = tmp[k] 这也是群友给出的第一版答案,这样写并没有多大问题,但是代码比较繁琐,肯定还有优化空间。 我们可以只使用一个中间变量即可,进一步优化: for field, value in data.items(): keys = field.split('_') tmp = new_data last = len(keys) - 1 for i, k in enumerate(keys): if k not in tmp: tmp[k] = {} if i < last else value tmp = tmp[k] # 将内层 dict 传给 tmp 上面这个代码看似很简洁了,但是仍然还有两个 if 判断,如果不是使用了三元表达式的话,还会更多行。 所以可以进一步优化: for field, value in data.items(): keys = field.split('_') tmp = new_data for k in keys[:-1]: tmp = tmp.setdefault(k, {}) tmp[keys[-1]] = value 我们省略掉了 last 来判断最后一个字符的索引,直接通过 keys[:-1] 避开最后一个字符,末尾再单独生成数字键值对。 这里还使用字典的一个内置方法 —— setdefault。 dict.setdefault(key, default=None) 方法和 get 方法类似,只是如果键不存在于字典中,不仅会返回 default 参数的值,还同时会用该值自动生成一个键值对。 if k not in tmp: tmp[k] = {} v = tmp[k] # 等价于 v = tmp.setdefault(k, {}) 最终我们使用了 6 行代码就解出该题,这也是接近最简代码。 如果使用字典引用的特性是合格的话,那么当你用出 setdefault 这个方法后,面试官已经给你打了优秀,所以一定要熟悉这些数据对象的所有内置方法。 本文属于原创,首发于微信公众号「面向人生编程」,如需转载请后台留言。

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

JavaEE基础(05):过滤器、监听器、拦截器,应用详解

本文源码:GitHub·点这里 || GitEE·点这里 一、Listener监听器 1、概念简介 JavaWeb三大组件:Servlet,Listener,Filter。监听器就是指在应用程序中监听相关对象状态变化的组件。 2、事件源对象 指被监听对象。 ServletContext ServletContextListener生命周期监听,它有两个方法,出生时调用contextInitialized(),销毁时调用contextDestroyed(); ServletContextAttributeListener属性监听,它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性时attributeRemoved()。 HttpSession HttpSessionListener生命周期监听:它有两个方法,出生时调用sessionCreated(),销毁时调用sessionDestroyed(); HttpSessioniAttributeListener属性监听:它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性attributeRemoved()。 ServletRequest ServletRequestListener生命周期监听:它有两个方法,出生时调用requestInitialized(),销毁时调用requestDestroyed(); ServletRequestAttributeListener属性监听:它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性attributeRemoved()。 3、编码案例 相关监听器 TheContextListener public class TheContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("初始化:TheContextListener"); ServletContext servletContext = servletContextEvent.getServletContext() ; servletContext.setAttribute("author","cicada"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("销毁:TheContextListener"); } } TheRequestListener public class TheRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { System.out.println("初始化:TheRequestListener"); } @Override public void requestInitialized(ServletRequestEvent servletRequestEvent) { System.out.println("销毁:TheRequestListener"); } } TheSessionListener public class TheSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("初始化:TheSessionListener"); } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("销毁:TheSessionListener"); } } RequestAttributeListener public class RequestAttributeListener implements ServletRequestAttributeListener { @Override public void attributeAdded(ServletRequestAttributeEvent evt) { System.out.println("Request添加属性:"+evt.getName()+";"+evt.getValue()); } @Override public void attributeRemoved(ServletRequestAttributeEvent evt) { System.out.println("Request移除属性:"+evt.getName()+";"+evt.getValue()); } @Override public void attributeReplaced(ServletRequestAttributeEvent evt) { System.out.println("Request替换属性:"+evt.getName()+";"+evt.getValue()); } } web.xml配置文件 <!-- 监听器相关配置 --> <listener> <listener-class>com.node05.servlet.listener.TheContextListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.TheSessionListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.TheRequestListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.RequestAttributeListener</listener-class> </listener> <session-config> <!-- 设置session失效时间为1分钟 --> <session-timeout>1</session-timeout> </session-config> 测试接口 public class ListenerServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 1、获取TheContextListener初始化数据 ServletContext servletContext = this.getServletContext() ; String author = String.valueOf(servletContext.getAttribute("author")) ; System.out.println("TheContextListener Author:"+author); // 2、Request属性设置 request.setAttribute("mood","smile"); request.setAttribute("mood","agitated"); // 3、Session创建,1分钟失效,调用销毁 HttpSession session = request.getSession(true) ; session.setAttribute("casually","casually"); response.getWriter().print("Hello:Listener"); } } 二、Filter过滤器 1、过滤器简介 客户端请求Servlet时,先执行相关Filter,如果Filter通过,则继承执行请求的Servlet;如果Filter不通过,则不会执行用户请求的Servlet。过滤器可以动态地拦截请求和响应。 2、Filter接口 Filter接口定义了三个核心方法。 init() 应用程序启动时,服务器实例化Filter对象,并调用其init方法,读取web.xml配置,完成对象的初始化加载。 doFilter() 实际的过滤操作,请求达到服务器时,Servlet容器将先调用过滤器的doFilter方法。 destroy() 容器在销毁过滤器前调用该方法,释放过滤器占用的资源。 3、编码案例 编写过滤器 public class ThePrintLogFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { String myName = filterConfig.getInitParameter("myName") ; System.out.println("myName:"+myName); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest ; HttpServletResponse response = (HttpServletResponse)servletResponse ; String name = request.getParameter("name") ; if (!name.equals("cicada")){ response.getWriter().print("User Error !"); return ; } chain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { System.out.println("ThePrintLogFilter destroy()"); } } web.xml配置文件 <!-- 过滤器相关配置 --> <filter> <filter-name>thePrintLogFilter</filter-name> <filter-class>com.node05.servlet.filter.ThePrintLogFilter</filter-class> <init-param> <param-name>myName</param-name> <param-value>cicada</param-value> </init-param> </filter> <filter-mapping> <filter-name>thePrintLogFilter</filter-name> <url-pattern>/filterServletImpl</url-pattern> </filter-mapping> 测试接口 public class FilterServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("Hello:Filter"); } } 三、Interceptor拦截器 Spring框架中的拦截器Interceptor类似于Servlet中的过滤器Filter,主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。请求转发不执行拦截、过滤;重定向执行拦截和过滤。 ---END---

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

基础攻略!如何使用kubectl和HPA扩展Kubernetes应用程序

现如今,Kubernetes已经完全改变了软件开发方式。Kubernetes作为一个管理容器化工作负载及服务的开源平台,其拥有可移植、可扩展的特性,并促进了声明式配置和自动化,同时它还证明了自己是管理复杂微服务的主要参与者。而Kubernetes之所以能够在业界被广泛采用,究其原因是Kubernetes迎合了以下需求: 企业想要在不断地增长的同时维持低成本 DevOps想要一个可以大规模运行应用程序的稳定平台 开发人员希望有一个可靠并且可复制的流程来编写、测试和debug代码 但是,你是否考虑过如何在使用实际需要的资源的同时获得强大的容器编排平台?最佳资源利用的关键是知道需要扩展什么应用程序以及何时需要扩展应用程序。因此,在本文中,我们将讨论和学习如何扩展Kubernetes容器,并且我们将特别关注两类服务:kubectl和Horizontal Pod Autoscaler(HPA)。 kubectl 在绝大部分情况下和Kubernetes交互是通过一个名为kubectl的命令行工具。kubectl主要用于和Kubernetes API进行通信来创建、更新以及删除在Kubernetes内的工作负载。在下文中,我们将提供一些常见的命令,你可以利用它们开始管理Kubernetes。 大部分常见的kubectl命令都提供了要执行的特定操作或动作,比如创建、删除等。这一方法通常涉及解释描述Kubernetes中的对象(pod、服务、资源等)的文件(YAML或JSON)。这些文件可用于模板以及环境中的持续文件,并且帮助保持Kubernetes对声明式配置的关注。命令行所指定的操作将会传递到API Server,然后根据需要与Kubernetes中的后端服务进行通信。下方的表格可以帮助你安装kubectl: 请注意:随着新版本的发布,适用于Windows的kubectl的最佳版本会有所变化。想要找到目前最合适的二进制文件,请访问以下网址: https://storage.googleapis.com/kubernetes-release/release/stable.txt 并根据需要调整上述URL。 kubectl 句法 kubectl句法如下: kubectl [command] [TYPE] [NAME] [flags] Command:指你想要执行的动作(创建、删除等) Type:指你要针对其执行命令的资源类型(Pod、Service等) Name:资源对象的名称(区分大小写),如果你不指定一个名称,它会获取所有与你命令匹配的资源信息。 Flags:这部分在句法中不是必要的,但是当需要查找指定资源时,十分有用。例如,-namespace可以让你指定一个特定的命名空间,以在其中执行操作。 kubectl操作 以下示例可以帮助你熟悉运行常用的kubectl操作: kubectl apply - Apply or Update a resource from a file or stdin. # Create a service using the definition in example-service.yaml. kubectl apply -f example-service.yaml kubectl get - List one or more resources. # List all pods in plain-text output format. kubectl get pods # List all pods in plain-text output format and include additional information (such as node name). kubectl describe - Display detailed state of one or more resources, including the uninitialized ones by default. # Display the details of the node with name &lt;node-name&gt;. kubectl describe nodes &lt;node-name&gt; kubectl delete - Delete resources either from a file, stdin, or specifying label selectors, names, resource selectors, or resources. # Delete a pod using the type and name specified in the pod.yaml file. kubectl delete -f pod.yaml # Delete all the pods and services that have the label name=&lt;label-name&gt;. kubectl delete pods,services -l name=&lt;label-name&gt; kubectl logs - Print the logs for a container in a pod. # Return a snapshot of the logs from pod &lt;pod-name&gt;. kubectl logs &lt;pod-name&gt; # Start streaming the logs from pod &lt;pod-name&gt;. This is similar to the 'tail -f' Linux command. kubectl logs -f &lt;pod-name&gt; 以上都是kubectl中常用的操作,如果你想了解更多,可以查阅kubectl的官方指南。此外,我们在往期的文章中也有介绍: 你一定会用到的7条kubectl命令 使用Kubectl管理Kubernetes的全解教程 Horizontal Pod Autoscaler(HPA) Pod水平自动伸缩(HPA)是Kubernetes的一个重要功能,它可以让你配置集群以自动伸缩正在运行的服务。HPA实现为一种Kubernetes API资源和controller。资源决定controller的行为,controller会定期调整replication controller或部署中的副本数量,使观察到的平均CPU利用率与用户指定的目标相匹配。 同时,HPA实现为控制回路,其周期由controller manager的–horizontal-pod-autoscaler-sync-period标志控制(默认值为30秒)。 在每个周期期间,controller manager 会根据每个HPA定义中指定的指标来查询资源利用率。Controller manager会从资源指标API(针对per-pod资源指标)或自定义指标API(针对所有其他指标)中获得指标。 针对per-pod资源指标(如CPU),controller会从资源指标API中为HPA定位的每个Pod获取指标。然后,如果设置了目标利用率值,则controller将会把利用率值计算为每个pod中容器的同等资源请求的百分比。如果设置了目标原始值,则直接使用原始指标值。然后,controller将所有目标pod的利用率或原始值(取决于指定的目标类型)取平均值,并产生一个用于伸缩所需副本数量的比率。 针对per-pod自定义指标,controller的功能类似于per-pod资源指标,但它适用于原始值,而非利用率值。 对于对象指标,将会获取单个指标(该指标描述了所讨论的对象),并将其与目标值进行比较,以产生用于伸缩所需副本数量的比率。 HPA controller将会通过两种不同的方式获取指标:direct Heapster access和REST client access。当使用direct Heapster access时,HPA将会通过API server的服务代理子资源直接查询Heapster。请注意,Heapster需要部署在集群上并在kube-system命名空间中运行。 HPA的工作流程包含以下四个步骤,如图所示: 在设置默认30秒间隔期间,HPA会持续检查你所配置的指标值 如果达到指定阈值,则HPA尝试增加pod的数量 HPA主要更新在部署中或replication controller中的副本数量 然后,部署/replication controller将会添加任何额外所需的pod 当你推出HPA时请考虑以下因素: 默认的HPA检查间隔是30秒,这个默认值可以通过controller manager的— horizontal-pod-autoscaler-sync-period标志进行配置。 默认的HPA相关指标容差为10%。 在上一次扩展事件之后,HPA将会等待3分钟,以使指标稳定下来。这一等待事件同样可以通过— horizontal-pod-autoscaler-upscale-delay标志进行配置。 从上一次缩小事件开始,HPA将会等待5分钟,以避免autoscaler抖动。同样可以通过— horizontal-pod-autoscaler-downscale-delay标志进行配置。 与replication controller相比,HPA最适合与部署对象或Pod指标配合使用,不适用于使用直接操作的replication controller的滚动更新。当你进行部署时,需要根据部署对象来管理底层副本集的大小。 当HPA与自定义指标(如Pod指标或对象指标)一起使用时,你需要决定何时进行伸缩。由于Kubernetes支持多种指标,因此你可以同时使用多种指标来决定伸缩的时间。请注意,Kubernetes会依照次序来考虑每个指标。更多示例请查阅: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale 结 论 在本文中,我们讨论了两种扩展Kubernetes应用程序的主要工具,两者都是所有Kubernetes服务的关键组件。我们看到了如何安装并且使用不同的功能,如应用、获取、删除、描述以及kubectl的日志等。同时,我们回顾并了解有关Horizontal Pod Autoscaler的信息,例如它是如何工作的以及它对任意Kubernetes服务的重要性。在扩展微服务应用程序时,kubectl和HPA都是Kubernetes的重要功能。 在上个月发布的Rancher 2.3中,已经集成了HPA功能,可以在Rancher中通过UI使用。目前,Rancher 2.3也已经stable,如果想要更全面地了解Rancher 2.3关注我们下周三晚上的Rancher K8S云课堂吧! 欢迎添加小助手(wx:rancher2),进官方技术群,了解更多Kubernetes使用攻略

资源下载

更多资源
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文件系统,支持十年生命周期更新。

用户登录
用户注册