当前位置: 首页 > news >正文

SpringBoot拦截器

目录

一、拦截器快速入门

(1)什么是拦截器

(2)拦截器的使用步骤

1、定义拦截器

🍀preHandle() 方法

🍀postHandle() 方法

🍀afterCompletion() 方法

2、注册配置拦截器

二、拦截器详解

1、拦截路径

2、拦截器执行流程

三、登录校验(图书管理系统)

1、定义拦截器

2、注册配置拦截器

3、更改图书馆管理系统代码(用户登录接口)

(1)后端代码

(2)前端代码

四、适配器模式

1、适配器模式定义

2、适配器模式角色

3、适配器模式的实现

4、适配器模式应用场景


        上篇博客完成了强制登录功能,后端程序需要根据 Session 来判断用户是否登录,但是实现方法是比较麻烦的,需要完成下面几个步骤:

1、需要修改每个接口的处理逻辑

2、需要修改每个接口的返回结果

3、接口定义修改,前段代码也需要跟着修改

        那有没有更简单的方式,统一拦截所有的请求,并进行 Session 的校验的?有,那就是Spring 框架提供的核心功能之一:拦截器


一、拦截器快速入门

(1)什么是拦截器

        拦截器是 Spring 框架提供的核心功能之一,主要用来拦截用户的请求,在指定的方法前后,根据业务需要执行预先设定的代码

        也就是说,允许开发人员提前预定义一些逻辑,在用户的请求、响应前后执行。也可以在用户请求前阻止其执行

        在拦截器当中,开发人员可以在应用程序中做一些通用性的操作,比如通过拦截器来拦截前端发来的请求,判断Session中是否有登录用户的信息,如果有 -> 就放行,如果没有 -> 就进行拦截。

        如图:

        这种情况就类似我们去银行办理业务,去银行办业务需要有带身份证,如果没有身份证,就不能取号,更不要提后续的业务,没有就要回家拿再过来,有就去取号,排队等待,办理你需要的业务

        拦截器在这里就类似你有没有身份证,有身份证才能办理后续的业务,没有就要执行其他逻辑(回家拿身份证)。

        接下来,我们来学习拦截器的基本使用。

(2)拦截器的使用步骤

        练习拦截器的使用以及后面的使用都是使用图书管理系统项目。

1、定义拦截器

        自定义拦截器,实现 HandlerInterceptor 接口,并且重写所有方法,代码如下:

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor preHandle(目标方法执行前执行).....");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor postHandle(目标方案执行后执行).....");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptor afterCompletion(视图渲染完毕后执行,最后执行).....");}
}

🍀preHandle() 方法

        目标方法执行前执行返回true:继续执行后续操作;返回false:中断后续操作。

🍀postHandle() 方法

        目标方法执行后执行

🍀afterCompletion() 方法

        视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图了,暂不了解)。

2、注册配置拦截器

        创建一个 WebConfig 类,实现WebMvcConfigurer接口,并重写addInterceptors方法(),代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求;}
}

        现在启动服务器,访问任意接口,观察打印的日志

        查询bookId=1的图书信息,如图:

        观察日志:

        可以看到,在执行目标方法前,就执行了 preHandle() 方法了因为preHandle返回了true,才能执行执行目标方法,目标方法执行完后,执行 postHandle() 方法;最后才执行 afterCompletion() 方法

        现在我们把 preHandle() 方法的返回值修改成 false试试,观察打印结果

        再次访问 /book/queryBookById?bookId=1 ,观察返回的信息,这次没有返回信息了,如图:

        再看看控制台打印的日志:

        因为 preHandle() 方法返回的是 false所有没有打印 postHandle() 和afterCompletion() 方法,也就意味着中断了后续的操作


二、拦截器详解

        拦截器的入门程序完成后,接下来我们学习拦截器的使用细节。拦截器的使用细节主要介绍两个部分:1、拦截器的拦截路径配置      2、拦截器实现原理

1、拦截路径

        拦截路径是指我们定义的这个拦截器,对哪些请求生效。

        我们在注册配置拦截器的时候,通过 addPathPatterns() 方法指定要拦截哪些请求。也可以通过 excludePathPatterns() 指定不拦截哪些请求

        上述代码中,我们配置的是 /** ,表示拦截所有的请求。

        比如用户登录校验,我们希望可以对除了登录之外所有的路径生效,代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求.excludePathPatterns("/user/login")//设置拦截器不拦截哪些请求路径;}
}

        现在请求 /user/login 接口,就不会打印上面说的那三个接口了

        因为没有拦截它,也就不会执行那三个方法,打印其日志了。

        在拦截器中除了可以设置 /** 拦截所有资源外,还有一些常见拦截路径设置:

拦截路径含义举例
/*⼀级路径能匹配/user,/book,/login,不能匹配 /user/login
/**任意级路径能匹配/user,/user/login,/user/reg
/book/*/book下的⼀级路径能匹配/book/addBook,不能匹配/book/addBook/1,/book
/book/**/book下的任意级路径能匹配/book,/book/addBook,/book/addBook/2,不能匹
配/user/login

2、拦截器执行流程

        正常的调⽤顺序:

         

        有了拦截器后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图:

        

1添加拦截器后,执行 Controller 的方法之前,请求会先被拦截器拦截住,执行 preHadnle() 方法,这个方法需要返回一个布尔类型的值。如果返回true,就表示放行本次操作,继续访问 controller中的方法;如果返回false,则拦截(controller中的方法也不会执行)。

2controller当中的方法执行完毕后在回过来执行 postHandle() 这个方法 以及 afterCompletion() 方法,执行完毕之后,最终给浏览器响应数据。


三、登录校验(图书管理系统)

        学习了拦截器的基本操作之后,接下来我们需要完成最后一步操作:通过拦截器来完成图书管理系统中的登录校验功能。

1、定义拦截器

        从 session 中获取用户信息,如果 session 中不存在,就返回false,并设置http状态码为401,否则返回true。代码如下:

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor preHandle(目标方法执行前执行).....");//获取Session,判断Session中存储的userinfo信息是否为空HttpSession session = request.getSession(true);UserInfo userInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION_KEY);if(userInfo == null || userInfo.getId() <= 0) {//用户未登录response.setStatus(401);return false;}return true;}
}

http状态码401:Unauthorized
        Indicates that authentication is required and was either not provided or has failed. If the request already included authorization credentials, then the 401 status code indicates that those credentials were not accepted.

        中文解释:未经过认证。指示身份验证是必需的,没有提供身份验证或身份验证失败。如果请求已经包含授权凭据,那么401状态码表示不接受这些凭据。

        其中 request.getSession() 方法有下面两种形式,有参和无参,如图:

        其中,无参的 getSession() 方法 默认 是 getSession(true);

         getSession(true) 表示如果有Session,则返回Session,如果没有,则创建一个Session

        getSession(false) 表示 获取Session可能会是null

2、注册配置拦截器

        配置拦截器拦截所有的请求,除了 /user/login 和前端的页面,代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求.excludePathPatterns("/user/login")//设置拦截器不拦截哪些请求路径.excludePathPatterns("/css/**")//排除前端静态资源.excludePathPatterns("/js/**").excludePathPatterns("/pic/**").excludePathPatterns("/**/*.html");}
}

也可以改成下面这样子,定义一个链表,把要排除的路径都放进链表中,代码如下:

//也可以改成下面这样子
//定义一个链表,把要排除的路径都放进链表中
@Configuration
public class WebConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;private List<String> excludePaths = Arrays.asList("/user/login","/css/**","/js/**","/pic/**","/**/*.html");@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求.excludePathPatterns(excludePaths)//设置拦截器排除拦截的路径;}
}

        运行程序,进行测试

        访问:http://127.0.0.1:8080/book_list.html?pageNum=1

        可以看到有401的状态码。

        通过fiddler抓包观察:

        返回的响应状态码就是401。

        现在进行登录,如图:

        再次访问:http://127.0.0.1:8080/book_list.html?pageNum=1,如图:有内容了

3、更改图书馆管理系统代码(用户登录接口)

(1)后端代码

        因为我们已经定义和注册配置了拦截器,所以这里统一帮我们做了校验用户是否登录,没有登录就返回false(拦截),并且设置响应的状态码为401;用户已经登录了,能获取到的Session能通过它拿到userInfo信息,userinfo也有对应的用户信息,就是用户登录了,则返回 true;就是上面定义拦截器的内容,代码如下:

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor preHandle(目标方法执行前执行).....");//获取Session,判断Session中存储的userinfo信息是否为空HttpSession session = request.getSession(true);UserInfo userInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION_KEY);if(userInfo == null || userInfo.getId() <= 0) {//用户未登录response.setStatus(401);return false;}return true;}
}

        修改 controller的"/book/getBookListByPage" 接口,也就是删除一些逻辑判断,因为拦截器已经帮我们做了这些逻辑处理,代码如下:

    @RequestMapping("/getBookListByPage")public Result<PageResult<BookInfo>> getBookListByPage(PageRequest pageRequest, HttpSession session) {log.info("查询图书的列表, 请求参数pageRequest: {}", pageRequest);//从session中获取用户信息//如果用户信息为空, 说明用户未登录
//        UserInfo loginUserInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION_KEY);
//        if(loginUserInfo == null || loginUserInfo.getId() < 0) {
//            return Result.nologin();
//        }
//        //参数校验
//        if(pageRequest.getPageNum() == null) {
//            //返回默认第一页,如果pageSize也没设置,则会使用默认的10
//            pageRequest.setPageNum(1);
//        }PageResult<BookInfo> bookList = bookService.getBookListByPage(pageRequest);return Result.success(bookList);}

        现在进行测试,未登录,访问:http://127.0.0.1:8080/book_list.html?pageNum=1,返回401状态码

        登录后,再访问,结果如下:能返回信息

        但上面没有实现强制登录功能,不应该出现401的状态码,应该跳转到登录界面,这是因为还没有改前端代码,下面修改前端代码。

(2)前端代码

getBookList();function getBookList() {$.ajax({url: "/book/getBookListByPage" + location.search,type: "get",success: function (result) {// if (result.code == "NOLOGIN") {//用户登录//     location.href = "login.html";// }if (result.data != null && result.data.records != null) {console.log("拿到参数")var finalHtml = "";for (book of result.data.records) {finalHtml += '<tr>';finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="' + book.id + '" class="book-select"></td>'finalHtml += '<td>' + book.id + '</td>';finalHtml += '<td>' + book.bookName + '</td>';finalHtml += '<td>' + book.author + '</td>';finalHtml += '<td>' + book.count + '</td>';finalHtml += '<td>' + book.price + '</td>';finalHtml += '<td>' + book.publish + '</td>';finalHtml += '<td>' + book.statusCN + '</td>';finalHtml += '<td>';finalHtml += '<div class="op">';finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')">删除</a>';finalHtml += '</div>';finalHtml += '</td>';finalHtml += '</tr>';}$("tbody").html(finalHtml);var data = result.data;//翻页信息$("#pageContainer").jqPaginator({totalCounts: data.count, //总记录数pageSize: 10,    //每页的个数visiblePages: 5, //可视页数currentPage: data.pageRequest.pageNum,  //当前页码first: '<li class="page-item"><a class="page-link">首页</a></li>',prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',//页面初始化和页码点击时都会执行onPageChange: function (page, type) {console.log("第" + page + "页, 类型:" + type);if (type == "change") {location.href = "book_list.html?pageNum=" + page;}}});}},error: function (error) {console.log(error);if(error != null && error.status == 401) {location.href = "login.html";}}});}

        也就是多增加 error 时,应该怎么做,上面是进行判断了返回响应的信息,响应是不是空,已经响应的状态码是不是401,是的话就给他跳转到登录界面。

        现在进行测试一下,URL:http://127.0.0.1:8080/book_list.html?pageNum=1,会跳转到登录界面

        观察日主,如图:

        打印了preHandle()方法执行后就没有后续的内容了。

        要是登录后,再访问 http://127.0.0.1:8080/book_list.html?pageNum=1,就会展示第一页的图书列表。

        还有其他接口的代码没改,后面会学习统一功能,到时候使用统一功能再一起改。


四、适配器模式

1、适配器模式定义

        适配器模式,也叫包装模式。将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类也可以合作无间

        简单来说就是目标类不能直接使用,通过一个新类进行包装一下,适配调用方使用。把两个不兼容的接口通过一定的方式使之兼容。

        比如下图的两个接口,本身是不兼容的(参数类型不一样,参数个数不一样等等)

        可以通过适配器的方式,使之兼容

        而在日常生活中,适配器模式也非常常见,例如转换插头、网络转接头、耳机转接头等。

        出国旅游必备物品之一就是转换插头。不同国家的插头标准是不一样的,出国后我们手机 / 电脑充电器可能就没办法使用了。比如美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。国内经常使用转换插头把两头转为三头,或者三头转两头。

2、适配器模式角色

Target目标接口(可以是抽象类或接口),客户希望直接用的接口

Adaptee适配者,但是与 Target 不兼容

Adapter适配器类,此模式的核心。通过继承或者引用适配者的对象,把适配者转为目标接口

client需要使用适配器的对象

3、适配器模式的实现

        场景:之前学习的 Slf4j 就使用了适配器模式Slf4j 提供了一系列打印日志的 API, 底层调用的是 log4j 或者 logback 来打日志,我们作为调用者,只需要调用 Slf4j 的API 即可

代码如下:

        Target:

public interface Slf4jLog {void log(String message);
}

        Adaptee:

public class Log4j {public void log4jPrint(String message) {System.out.println("我是Log4j, 打印内容是: " + message);}
}

        Adapter:

        Log4j 想使用 Slf4jLog log接口,但是不行,因为自身 打印的方法 和Slf4jLog 的不同。所以这时候就就需要使用适配器,定义一个类,通过继承 Slf4jLog 接口,来实现它的方法,再引入 Log4j,打印Log4j的内容。

public class Log4jAdapter implements Slf4jLog{private Log4j log4j;public Log4jAdapter(Log4j log4j) {this.log4j = log4j;}@Overridepublic void log(String message) {log4j.log4jPrint("我是适配器, 打印日志为: " + message);}
}

        client

public class Main {public static void main(String[] args) {Slf4jLog slf4jLog = new Log4jAdapter(new Log4j());slf4jLog.log("我是客户端");}
}

        打印内容如下:

        可以看到,适配器就是起到一层包装的效果因为接口和 Slf4jLog 不同,所以就使用适配器类 实现 Slf4jLog 接口,同时引用 Log4j,使用 Log4j 的打印方法包装一层再给 Log4j 打印)。

        最终还是给 Log4j 打印适配器的作用就是给两个不同的接口,给其中一个接口进行包装一下,再丢给另一个接口进行使用

        可以看出,有了适配器模型,对已经定义好的接口,可以不进行修改,只需要通过适配器转换下,就可以更换日志框架,保障系统的平稳运行

4、适配器模式应用场景

        一般来说,适配器模式可以看做一种 “补偿模式”,用来 补救 设计上的缺陷。应用这种模式算是 “无奈之举”,如果在设计初期,我们就能协调规避接口不兼容的问题,就不需要使用适配器模式了

        所以,适配器模式更多的应用场景主要是对正在运行的代码进行改造,并且希望可以复用原有代码实现新的功能,比如版本升级等

相关文章:

SpringBoot拦截器

目录 一、拦截器快速入门 &#xff08;1&#xff09;什么是拦截器 &#xff08;2&#xff09;拦截器的使用步骤 1、定义拦截器 &#x1f340;preHandle() 方法 &#x1f340;postHandle() 方法 &#x1f340;afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…...

uniapp中实现跳转链接到游览器(安卓-h5)

uniapp中实现跳转链接到游览器&#xff08;安卓-h5&#xff09; 项目中需要做到跳转到外部链接&#xff0c;网上找了很多都不是很符合自己的要求&#xff0c;需要编译成app后是跳转到游览器打开链接&#xff0c;编译成web是在新窗口打开链接。实现的代码如下&#xff1a; 效果&…...

WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七

应用开发第一步 功能分类&#xff1a;页面上的功能区域划分。。。。需求分析 业务逻辑 数据流 功能模块 UI/UX 编码 测试 发布 功能开发与布局 不用显式的方式设定元素的尺寸 不使用屏幕坐标来指定位置 Grid 功能最强大&#xff0c;布局最灵活的容器…...

文件格式是.pb应该怎么查看?

文件格式为.pb的文件&#xff0c;通常是Google Protocol Buffers&#xff08;简称PB&#xff09;序列化后的二进制文件。要查看.pb文件的内容&#xff0c;可以采用以下方法&#xff1a; 1. **直接打开&#xff08;不推荐&#xff09;**&#xff1a; - 直接打开.pb文件通常会显示…...

android2024 gradle8 Processor和ksp两种编译时注解实现

android编译时注解&#xff0c;老生常谈&#xff0c;外面的例子都是bindView&#xff0c;脑壳看疼了&#xff0c;自己学习和编写下。 而且现在已经进化到kotlin2.0&#xff0c;google也逐渐放弃kapt&#xff0c;进入维护状态。所以要好好看看本贴。 参考我的工程&#xff1a; h…...

elementui的table的@selection-change阻止事件改变

说明&#xff1a; 最近有个不想说的&#xff08;xxx&#xff09;业务&#xff0c;在表格勾选每一行的时候要触发一系列查询功能&#xff0c;查询失败还要把那个勾勾回退。真实蛋疼&#xff01;表格勾选的默认selection-change是change事件&#xff0c;一般change事件是在完成之…...

空间数据采集与管理:为什么选择ArcGISPro和Python?

你还在为找不到合适的数据而苦恼吗&#xff1f;你还在面对大量数据束手无策&#xff0c;不知如何处理吗&#xff1f;对于从事生产和科研的人员来说&#xff0c;空间数据的采集与管理是地理信息系统&#xff08;GIS&#xff09;和空间分析领域的关键环节。通过准确高效地采集和管…...

案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态

江苏省电子口岸有限公司&#xff0c;成立于2009年&#xff0c;由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命&#xff0c;致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…...

TCP粘包

目录 TCP粘包产生的原因 TCP粘包的现象 TCP粘包的解决方案 TCP粘包是指在TCP通信中,发送方发送的多个数据包在接收方被错误地合并成一个数据包的现象。tcp粘包在发送端和接收端都有可能发生。发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包。接收方粘包:接收方不及…...

数据泄露态势(2024年5月)

监控说明&#xff1a;以下数据由零零信安0.zone安全开源情报系统提供&#xff0c;该系统监控范围包括约10万个明网、深网、暗网、匿名社交社群威胁源。在进行抽样事件分析时&#xff0c;涉及到我国的数据不会选取任何政府、安全与公共事务的事件进行分析。如遇到影响较大的伪造…...

二手闲置平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;卖家管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;商品购买管理&#xff0c;商品配送管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&a…...

协程libgo的使用

c开源协程库libgo介绍及使用-CSDN博客 libgo库的github地址&#xff1a;GitHub - yyzybb537/libgo: Go-style concurrency in C11 使用libgo编写并行程序&#xff0c;即可以像golang一样开发迅速且逻辑简洁&#xff0c;又有C原生的性能优势。它的特点有&#xff1a; 1.提供go…...

什么叫低频晶振?低频晶振最低频率能达到多少?低频晶振封装尺寸有哪些?

低频晶振指的是那些工作在较低频率范围内的晶体振荡器&#xff0c;通常这类振荡器的标称频率低于8MHz。这些晶振在各种电子设备中都有应用&#xff0c;尤其是在那些需要精确但不需要高频振荡的应用场景中&#xff0c;比如实时时钟(RTC)、低速串行通信接口(如UART、IC等)、以及一…...

Splunk Enterprise 任意文件读取漏洞(CVE-2024-36991)

文章目录 前言漏洞描述影响版本漏洞复现POC批量检测-nuclei脚本 修复建议 前言 Splunk Enterprise 是一款强大的机器数据管理和分析平台&#xff0c;能够实时收集、索引、搜索、分析和可视化来自各种数据源的日志和数据&#xff0c;帮助企业提升运营效率、增强安全性和优化业务…...

零基础STM32单片机编程入门(九)IIC总线详解及EEPROM实战含源码视频

文章目录 一.概要二.IIC总线基本概念1.总体特征2.通讯流程 三.EEPROM介绍1.M24C08基本介绍2.向M24C08写一个字节时序图3.从M24C08读一个字节时序图 四.GPIO模拟IIC驱动M24C08读写五.CubeMX工程源代码下载六.讲解视频链接地址七.小结 一.概要 IIC(Inter&#xff0d;Integrated …...

数据库的操作

【一】库的增删改查 【0】导入数据文件 source D:\bjpowernode.sql 【1】创建数据库 语法&#xff1a; create database [if not exists] 数据库名 [character set 编码字符集]; create databases db1; # 设置库的默认编码 create databases db1 charsetgbk; 【2】查看数据…...

常见的认证方式

认证机制是一种用户确定用户身份或者权限的安全措施&#xff0c;比如用来验证某个用户是否有权限访问一个资源&#xff0c;如果认证通过&#xff0c;用户就可以成功访问&#xff0c;反之则会访问失败 常见的认证方式有四种&#xff0c;分别是 Basic、Digest、OAuth 和 Bearer …...

DolphinScheduler部署安装or基础介绍(一)

DolphinScheduler概述 Apache DolphinScheduler是一个分布式、易扩展的可视化DAG工作流任务调度平台。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用 DolphinScheduler核心架构 DolphinScheduler的主要角色如下&#xff1a; Ma…...

Failed building wheel for pyaudio Running setup.py clean for pyaudio

从错误信息来看&#xff0c;问题出在 pyaudio 包的构建过程中。具体来说&#xff0c;缺少 portaudio.h 头文件&#xff0c;这通常是因为系统上没有安装 portaudio 库。 以下是解决此问题的步骤&#xff1a; 安装系统依赖&#xff1a; 在大多数基于 Debian 的系统&#xff08;如…...

【ARMv8/v9 GIC- 700 系列 1 -- Programmers model for GIC-700】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC-700 Programmers model寄存器实现和访问模式接口宽度和数据格式访问类型安全寄存器访问地址映射和页面GIC-700 Register map pagesSummaryGIC-700 Programmers model GIC-700是ARM的一种通用中断控制器,它遵循GICv3和GICv4架构…...

exel带单位求和,统计元素个数

如果exel表格中&#xff0c;如果数据有单位&#xff0c;无法直接用 自动求和 直接求和。如下图所示&#xff0c;求和结果为0&#xff0c;显然不是我们想要的。 用下面的公式求和&#xff0c;单位不是“个”的时候记得替换单位。统计范围不是“C1:C7”也记得换一下啊&#xff01…...

JavaScript里方括号[]的使用

我们知道可用方括号来表示数组或者JSON对象的属性值&#xff0c;其实在特定场合&#xff0c;方括号还有妙用的。 比如我有数据源是一组JSON&#xff0c;其中有一个属性是时间字符串&#xff0c;我想对时间的小时、星期、日、月分别进行处理。每条JSON都各自生成一条新的JSON&am…...

俯卧撑计数器(Python)

通过 MediaPipe 检测人体姿态&#xff0c;计算俯卧撑角度和计数&#xff0c;并在图像上进行可视化展示 需要有cv2库和mediapipe库 mediapipe库&#xff1a; MediaPipe是Google开源的机器学习框架&#xff0c;用于构建实时音频、视频和多媒体处理应用程序。它提供了一组预训练的…...

UVA12342 Tax Calculator 题解

题目传送门 题目大意 题目描述 某国所得税计算十分复杂。该国政府指定你制作一个自动计算所得税的程序。以下是该国计算所得税的规则&#xff1a; 所得税免征额为 180000 180000 180000 元。应纳税额中不超过 300000 300000 300000 元的所得额&#xff0c;按 10 % 10\% …...

WebKit中Websockets的全面支持:实现高效实时通信

WebKit中Websockets的全面支持&#xff1a;实现高效实时通信 Websockets是一种网络通信协议&#xff0c;它允许在单个TCP连接上进行全双工通信&#xff0c;从而实现服务器与客户端之间的实时数据交换。WebKit作为许多流行浏览器的底层引擎&#xff0c;对Websockets提供了全面的…...

微信小程序的智慧物流平台-计算机毕业设计源码49796

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3研究方法 1.4开发技术 1.4.1 微信开发者工具 1.4.2 Node.JS框架 1.4.3 MySQL数据库 1.5论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 用户登录流程 2.2.2 数据删除流程 2.3 系统功能分…...

旅游 | 西岳华山

得到了再失去&#xff0c; 总比从来没有得到更伤人。 ——胡赛尼《追风筝的人》 目录 旅游 | 西岳华山00 | 旅游导图01 | 旅游路线1.1 北上西下&#xff08;徒步&#xff09;1.2 北上西下&#xff08;索道&#xff09;1.3 西上北下&#xff08;索道&#xff09;1.4 西上西下&am…...

如何优化Java中的内存占用?

如何优化Java中的内存占用&#xff1f; 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 理解Java内存管理机制 Java的内存管理主要由JVM负责&#xff0c;开发人员在编写代码时需要注意如何有效地…...

2024这三家上海闵行装修公司,值得一看

在繁华的上海闵行区&#xff0c;随着居民对生活品质追求的提升&#xff0c;越来越多人开始重视居住环境的打造。然而&#xff0c;面对众多装修公司的选择&#xff0c;不少消费者往往感到迷茫和困惑。今天&#xff0c;我们就来揭晓闵行区口碑与实力兼备的三家装修公司。 1、首先…...

K8S学习教程(三):在PetaExpress KubeSphere 容器部署 Wiki 系统 wiki.js 并启用中文全文检索

背景 wiki.js 是非常优秀的开源 Wiki 系统&#xff0c;尽管在与 xwiki 功能相比 &#xff0c;还不算完善&#xff0c;但也在不断进步。 常用的功能还是比较实用的&#xff0c;如&#xff1a;Wiki 写 作、分享、权限管理功能还是非常实用的&#xff0c;UI 设计非常的漂亮&#x…...