建站哪家技术好/万能导航网
前言🍭
❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️
Spring + Spring MVC + MyBatis_冷兮雪的博客-CSDN博客
本章是讲Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节,要实现的目标有以下 3 个:
- 使用拦截器实现用户登录权限的统一验证;
- 统⼀数据格式返回;
- 统⼀异常处理。
一、用户登录权限效验🍭
1、最初用户登录验证🍉
用户登录权限的发展从之前每个方法中自己验证用户登录权限,到现在统⼀的用户登录验证处理,它是⼀个逐渐完善和逐渐优化的过程。
@RestController
@RequestMapping("/user")
public class UserController {/*** 某⽅法 1*/@RequestMapping("/m1")public Object method(HttpServletRequest request) {// 有 session 就获取,没有不会创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute("userinfo") != null) {// 说明已经登录,业务处理return true;} else {// 未登录return false;}}/*** 某⽅法 2*/@RequestMapping("/m2")public Object method2(HttpServletRequest request) {// 有 session 就获取,没有不会创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute("userinfo") != null) {// 说明已经登录,业务处理return true;} else {// 未登录return false;}}// 其他⽅法。。。
}
从上述代码可以看出,每个方法中都有相同的用户登录验证权限,它的缺点是:
- 每个方法中都要单独写用户登录验证的方法,即使封装成公共方法,也⼀样要传参调用和在方法中进行判断。
- 添加控制器越多,调用用户登录验证的方法也越多,这样就增加了后期的修改成本和维护成本。
- 这些用户登录验证的方法和接下来要实现的业务几何没有任何关联,但每个方法中都要写⼀遍。 所以提供⼀个公共的 AOP 方法来进行统⼀的用户登录权限验证迫在眉睫。
2、Spring AOP 用户统⼀登录验证的问题🍉
说到统⼀的用户登录验证,我们想到的第⼀个实现方案是 Spring AOP 前置通知或环绕通知来实现,具体实现代码如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class UserAspect {// 定义切点⽅法 controller 包下、⼦孙包下所有类的所有⽅法@Pointcut("execution(* com.example.demo.controller..*.*(..))")public void pointcut() {}// 前置⽅法@Before("pointcut()")public void doBefore() {}// 环绕⽅法@Around("pointcut()")public Object doAround(ProceedingJoinPoint joinPoint) {Object obj = null;System.out.println("Around ⽅法开始执⾏");try {// 执⾏拦截⽅法obj = joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("Around 方法结束执行");return obj;}
}
如果要在以上 Spring AOP 的切面中实现用户登录权限效验的功能,有以下两个问题:
- 定义拦截的规则(表达式)非常难。(我们要对⼀部分方法进行拦截,而另⼀部分方法不拦截,如注册方法和登录方法是不拦截的,这样 的话排除方法的规则很难定义,甚至没办法定义)。
-
在切面类中拿到 HttpSession 比较难
Spring 拦截器🍉
对于以上问题 Spring 中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步骤:
- 创建自定义拦截器,实现 HandlerInterceptor 接口的 preHandle(执行具体方法之前的预处理方法。
- 将自定义拦截器加入WebMvcConfigurer 的 addInterceptors 方法中。
具体实现如下:
目录结构:
Ⅰ、实现拦截器🍓
关键步骤:
a.实现 HandlerInterceptor 接口
b.重写 preHeadler 方法,在方法中编写自己的业务代码
package com.example.demo.config;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class LoginInterceptor implements HandlerInterceptor {/*** 此方法返回一个 boolean,如果为 true 表示验证成功,可以继续执行后续流程如果是 false 表示验证失败,后面的流程不能执行了* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//用户登录业务判断HttpSession session=request.getSession(false);if (session != null && session.getAttribute("userinfo") != null) {// 说明用户已经登录return true;}// 可以调整到登录页面 or 返回一个 401/403 没有权限码response.sendRedirect("/login.html");
// response.setStatus(403);return false;}
}
Ⅱ、将拦截器添加到配置文件中,并且设置拦截的规则🍓
package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/login") // 排除的url地址(不拦截的url地址).excludePathPatterns("/user/reg");}
}
其中:
- addPathPatterns:表示需要拦截的 URL,**表示拦截任意方法(也就是所有方法)。
- excludePathPatterns:表示需要排除的 URL。
说明:以上拦截规则可以拦截此项目中的使用 URL,包括静态文件(图片文件、JS 和 CSS 等文件)。
排除所有的静态资源:
// 拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 拦截所有接⼝.excludePathPatterns("/**/*.js").excludePathPatterns("/**/*.css").excludePathPatterns("/**/*.jpg").excludePathPatterns("/login.html").excludePathPatterns("/**/login"); // 排除接⼝}
UserController:
package com.example.demo.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {/* @GetMappingpublic String getMethod(){return "执行GET请求!";}@PostMappingpublic String postMethod(){return "执行POST请求!";}*/@RequestMapping("/getuser")public String getUser() {System.out.println("执行了 get User~");return "get user";}@RequestMapping("/login")public String login() {System.out.println("执行了 login~");return "login~";}@RequestMapping("/reg")public String reg() {System.out.println("执行了 reg~");return "reg~";}
}
Ⅲ、启动项目:🍓
不拦截:
拦截:http://localhost:8080/user/getuser
为什么会显示重定向次数过多?
这是因为这个login.html页面也被拦截了,所以它去访问时候就会一直重定向重定向去访问。
解决方法:
Ⅳ、拦截器实现原理🍓
正常情况下的调用顺序:
然而有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图所示:
所有的 Controller 执行都会通过⼀个调度器 DispatcherServlet 来实现,这⼀点可以从 Spring Boot 控制台的打印信息看出,如下图所示:
而所有方法都会执行 DispatcherServlet 中的 doDispatch 调度方法,doDispatch 源码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv = null;Exception dispatchException = null;try {processedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;mappedHandler = this.getHandler(processedRequest);if (mappedHandler == null) {this.noHandlerFound(processedRequest, response);return;}HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}this.applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception var20) {dispatchException = var20;} catch (Throwable var21) {dispatchException = new NestedServletException("Handler dispatch failed", var21);}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}}
从上述源码可以看出在开始执行 Controller 之前,会先调用 预处理方法 applyPreHandle,而applyPreHandle 方法的实现源码如下:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
// 获取项⽬中使⽤的拦截器 HandlerInterceptorHandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}return true;}
从上述源码可以看出,在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor 并执行拦截器中的 preHandle 方法,这样就和咱们前面定义的拦截器对应上了,如下图所示:
此时用户登录权限的验证方法就会执行,这就是拦截器的实现原理。
二、统⼀异常处理🍭
Ⅰ、实现🍓
统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知, 也就是执行某个方法事件,具体实现代码如下:
package com.example.demo.config;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;@ControllerAdvice
@ResponseBody
public class MyExHandler {/*** 拦截所有的空指针异常,进行统一的数据返回*/@ExceptionHandler(NullPointerException.class)public HashMap<String, Object> nullException(NullPointerException e) {HashMap<String, Object> result = new HashMap<>();result.put("code", "-1");result.put("msg", "空指针异常:" + e.getMessage()); // 错误码的描述信息result.put("data", null);return result;}@ExceptionHandler(Exception.class)//保底的默认异常public HashMap<String, Object> exception(Exception e) {HashMap<String, Object> result = new HashMap<>();result.put("code", "-1");result.put("msg", "异常:" + e.getMessage()); // 错误码的描述信息result.put("data", null);return result;}}
Ⅱ、添加异常🍓
UserController
@RequestMapping("/login")public String login() {Object obj = null;obj.hashCode();System.out.println("执行了 login~");return "login~";}@RequestMapping("/reg")public String reg() {int num = 10 / 0;System.out.println("执行了 reg~");return "reg~";}
Ⅲ、启动程序:🍓
login:
reg:
方法名和返回值可以自定义,其中最重要的是 @ExceptionHandler(Exception.class) 注解。
以上方法表示,如果出现了异常就返回给前端⼀个 HashMap 的对象,其中包含的字段如代码中定义的那样。 我们可以针对不同的异常,返回不同的结果。
三、统一数据返回格式🍭
1.创建一个类,并添加 @ControllerAdvice
2.实现ResponseBodyAdvice接口,并重写supports和beforeBodywrite (统一对象就是此方法中实现的)
1、为什么需要统一数据返回格式?🍉
统一数据返回格式的优点有很多,比如以下几个:
- 方便前端程序员更好的接收和解析后端数据接口返回的数据。
- 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就行了,因为所有接口都是这样返回的。
- 有利于项目统⼀数据的维护和修改。
- 有利于后端技术部门的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。
2、统一数据返回格式的实现🍉
Ⅰ、实现🍓
统⼀的数据返回格式可以使用 @ControllerAdvice + ResponseBodyAdvice 的方式实现。
package com.example.demo.config;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;/*** 此方法返回 true 则执行下面 beforeBodyWrite 方法* 反之则不执行*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg", "");result.put("data", body);// 需要特殊处理,因为 String 在转换的时候会报错if (body instanceof String) {try {return objectMapper.writeValueAsString(result);} catch (JsonProcessingException e) {e.printStackTrace();}}return result;}
}
如果没有对Sting进行特殊处理,就会有异常出现:
Ⅱ、添加实现类🍓
UserController
@RequestMapping("/getnum")public Integer getNumber() {return new Random().nextInt(10);}@RequestMapping("/getuser")public String getUser() {System.out.println("执行了 get User~");return "get user";}
Ⅲ、启动程序🍓
Ⅳ、总结🍓
上面只是以一种简单的方式来向大家介绍如何去统一数据返回格式,在实际工作中并不会这样去使用
而是将统⼀的返回格式(包含:status、data、msg 字段)进行封装成一个类:
根据不同操作成功和操作失败的情况,重写了不同的方法:
package com.example.demo.common;import lombok.Data;import java.io.Serializable;/*** 统一数据格式返回*/
@Data
public class AjaxResult implements Serializable {//支持序列化// 状态码private Integer code;// 状态码描述信息private String msg;// 返回的数据private Object data;/*** 操作成功返回的结果,需要 data*/public static AjaxResult success(Object data) {AjaxResult result = new AjaxResult();result.setCode(200);result.setMsg("");result.setData(data);return result;}//重载successpublic static AjaxResult success(int code, Object data) {AjaxResult result = new AjaxResult();result.setCode(code);result.setMsg("");result.setData(data);return result;}public static AjaxResult success(int code, String msg, Object data) {AjaxResult result = new AjaxResult();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}/*** 返回失败结果*/public static AjaxResult fail(int code, String msg) {AjaxResult result = new AjaxResult();result.setCode(code);result.setMsg(msg);result.setData(null);return result;}public static AjaxResult fail(int code, String msg, Object data) {AjaxResult result = new AjaxResult();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}
}
相关文章:

SpringBoot统⼀功能处理
前言🍭 ❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 本章是讲Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节&…...

LeetCode 每日一题 2023/8/14-2023/8/20
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 8/14 617. 合并二叉树8/15 833. 字符串中的查找与替换8/16 2682. 找出转圈游戏输家8/17 1444. 切披萨的方案数8/18 1388. 3n 块披萨8/19 2235. 两整数相加8/20 8/14 617. 合…...

进入微服务阶段后的学习方法
微服务SpringCloud学习的特点 陌生,多,复杂。 技术陌生,技术栈多,实现复杂。 学习方式 对于每一个组件: 1.知道是什么、有什么用 2.知道操作步骤(跟着讲义操作即可),包括&#…...

C/C++中const关键字详解
为什么使用const?采用符号常量写出的代码更容易维护;指针常常是边读边移动,而不是边写边移动;许多函数参数是只读不写的。const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替),分类如下:…...
【2023新教程】树莓派4B开机启动-树莓派第一次启动-树莓派不使用显示器启动-树莓派从购买到启动一步一步完全版!
背景 闲来无事,在咸鱼上买了一个树莓派4B。买来配件都十分齐全,于是就想着启动来测试一下。下面是树莓派无显示器第一次启动的全过程,包含安装系统。 网上的教程大多需要额外使用显示器、鼠标、键盘之类的外设。然而,树莓派本身就…...

LA@2@1@线性方程组和简单矩阵方程有解判定定理
文章目录 矩阵方程有解判定定理线性方程组有解判定特化:齐次线性方程组有解判定推广:矩阵方程 A X B AXB AXB有解判定证明推论 矩阵方程有解判定定理 线性方程组有解判定 线性方程组 A x b A\bold{x}\bold{b} Axb有解的充分必要条件是它的系数矩阵A和增广矩阵 ( A , b ) (A,…...

如何使用ChatGPT创作一个小说式的虚构的世界
世界构建也许是小说写作中最重要的一环,但也可能非常耗时。让ChatGPT加快这一过程吧。 写小说最棒的一点就是有机会从零开始创造一个新世界。你可以创造超凡脱俗的景观,赋予人物魔法。神话故事可以存在于你小说中的现实世界,而传统可以帮助你…...

用于量子通信和互联网的光量子芯片
近年来,新兴的光量子芯片在量子通信和量子互联网领域取得了重大进展。光量子芯片芯片具有可扩展、稳定和低成本等特点,为微型化应用开辟了新的可能性。 7月14日,一篇发表在《light: science & applications》的文章概述了用于量子通信的光…...

11. Vuepress2.x 关闭夜间模式
修改 docs/.vuepress/config.ts 配置文件 设置 themeConfig.darkMode属性详见 官网 module.exports {host: localhost, // ipport: 8099, //端口号title: 我的技术站, // 设置网站标题description: 描述:我的技术站,base: /, //默认路径head: [// 设置 favor.ico&a…...

netty实现websocket通信
调用注意: 1、端口一定要是可以访问的。 2、依赖必须注意和其他版本冲突,比如redis的springboot starter包,会与5.0版本冲突。 <netty.version>4.1.74.Final</netty.version> <dependency><groupId>io…...

两个list如何根据一个list中的属性去过滤掉另一个list中不包含这部分的属性,用流实现
你可以使用Java 8的流来实现这个功能。假设你有两个包含对象的List,每个对象有一个属性,你想根据一个List中的属性值来过滤掉另一个List中不包含这个属性值的对象。下面是一种使用流的方式来实现这个功能 import java.util.ArrayList; import java.util…...

Blender 混合现实3D模型制作指南【XR】
本教程分步展示如何: 减少 3D 模型的多边形数量,使其满足 Microsoft Dynamics 365 Guides 和使用 Microsoft Power Apps 创建的应用程序中包含的混合现实组件的特定性能目标的性能需求。将 3D 模型的多种材质(颜色)组合成可应用于…...

kubeasz在线安装K8S集群单master集群(kubeasz安装之二)
一、介绍 Kubeasz 是一个基于 Ansible 自动化工具,用于快速部署和管理 Kubernetes 集群的工具。它支持快速部署高可用的 Kubernetes 集群,支持容器化部署,可以方便地扩展集群规模,支持多租户,提供了强大的监控和日志分…...

『C语言』数据在内存中的存储规则
前言 小羊近期已经将C语言初阶学习内容与铁汁们分享完成,接下来小羊会继续追更C语言进阶相关知识,小伙伴们坐好板凳,拿起笔开始上课啦~ 一、数据类型的介绍 我们目前已经学了基本的内置类型: char //字符数据类型 short …...

基于ssm+vue的新能源汽车在线租赁管理系统源码和论文PPT
基于ssmvue的新能源汽车在线租赁管理系统源码和论文PPT010 开发环境: 开发工具:idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具:navcat,小海豚等 开发技术:java ssm tomcat8.5 摘 要 随着科学技术的飞速发展࿰…...

深入解析IDS/IPS与SSL/TLS和网络安全
目录 防火墙 IDS IPS DMZ VPN VPS SSL/TLS 动态IP 静态IP 防火墙 防火墙是一种网络安全设备,用于监控和控制网络流量,保护网络免受未经授权的访问、恶意攻击和威胁。防火墙可以基于规则进行数据包过滤,允许或阻止特定类型的流量通过…...

在Visual Studio上,使用OpenCV实现人脸识别
1. 环境与说明 本文介绍了如何在Visual Studio上,使用OpenCV来实现人脸识别的功能 环境说明 : 操作系统 : windows 10 64位Visual Studio版本 : Visual Studio Community 2022 (社区版)OpenCV版本 : OpenCV-4.8.0 (2023年7月最新版) 实现效果如图所示࿰…...

搭建openGauss 5.0 一主一从复制集群
openGauss是一款支持SQL2003标准语法,支持主备部署的高可用关系型国产数据库。 多种存储模式支持复合业务场景,新引入提供原地更新存储引擎。NUMA化数据结构支持高性能。Paxos一致性日志复制协议,主备模式,CRC校验支持高可用。支…...

Docker碎碎念
docker和虚拟机的区别 虚拟机(VM)是通过在物理硬件上运行一个完整的操作系统来实现的。 每个虚拟机都有自己的内核、设备驱动程序和用户空间,它们是相互独立且完全隔离的。 虚拟机可以在不同的物理服务器之间迁移,因为它们是以整…...

【C++】extern
目录 1. 变量声明和定义的关系 2. 默认状态下,const对象仅在文件内有效 3. 链接指示:extern "C" 3.1 声明一个非C的函数 3.2 链接指示与头文件 3.3 指向extern "C"函数的指针 3.4 链接指示对整个声明都有效 3.5 导出C函数到…...

2023全网Mysql 合集(25w字)附课程 从安装到高级,实战
mysql学习 1.安装mysql 安装教程 2.mysql的详细学习教程 mysql的详细教程 3.mysql 的高级优化 MySQL高级篇(SQL优化、索引优化、锁机制、主从复制) 4.MySQL 面试 MySQL数据库面试题总结 二.mysql实战 一、创建数据表并插入数据 1、学生表 Stud…...

张俊林:由ChatGPT反思大语言模型(LLM)的技术精要
转自:https://mp.weixin.qq.com/s/eMrv15yOO0oYQ-o-wiuSyw 导读:ChatGPT出现后惊喜或惊醒了很多人。惊喜是因为没想到大型语言模型(LLM,Large Language Model)效果能好成这样;惊醒是顿悟到我们对LLM的认知及发展理念&a…...

单机编排docker compose
Docker之旅(8)-单机编排docker compose 当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦而且容易出错, 并且每个容器之间也会有先后启动的顺序依赖等。这个时候推荐使用 docker 单机 编排工具 docker-compose,docker-compose …...

C++ 面向对象三大特性——多态
✅<1>主页:我的代码爱吃辣 📃<2>知识讲解:C 继承 ☂️<3>开发环境:Visual Studio 2022 💬<4>前言:面向对象三大特性的,封装,继承,多态ÿ…...

相同数字的积木游戏
题目描述 题目描述 小华和小薇一起通过玩积木游戏学习数学。 他们有很多积木,每个积木块上都有一个数字,积木块上的数字可能相同。 小华随机拿一些积木挨着排成一排,请小薇找到这排积木中数字相同目所处位置最远的2块积木块,计算…...

安防监控视频云存储EasyCVR平台H.265转码功能更新:新增分辨率配置
安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上,视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…...

图数据库_Neo4j学习cypher语言_常用函数_关系函数_字符串函数_聚合函数_数据库备份_数据库恢复---Neo4j图数据库工作笔记0008
然后再来看一些常用函数,和字符串函数,这里举个例子,然后其他的 类似 可以看到substring字符串截取函数 可以看到截取成功 聚合函数 这里用了一个count(n) 统计函数,可以看到效果 关系函数,我们用过就是id(r) 可以取出对应的r的id来这样.....

LeetCode150道面试经典题-- 加一(简单)
1.题目 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 2.示例 示例 1: 输入&am…...

Centos7 配置Docker镜像加速器
docker实战(一):centos7 yum安装docker docker实战(二):基础命令篇 docker实战(三):docker网络模式(超详细) docker实战(四):docker架构原理 docker实战(五):docker镜像及仓库配置 docker实战(六):docker 网络及数据卷设置 docker实战(七):docker 性质及版本选择 认知升…...

微信小程序中pdf的上传、下载及excel导出
微信小程序中pdf的上传、下载及excel导出 pdf上传上传1:上传2: pdf下载导出excel pdf上传 上传两种方法: 上传1: 1.用vant weapp组件: //pdf上传--vant weapp组件 <view class"content"><van-u…...