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

spring boot(学习笔记第十三课)

spring boot(学习笔记第十三课)

  • 传统后端开发模式和前后端分离模式的不同,Spring Security的logout,invalidateHttpSession不好用,bug?

学习内容:

  1. 传统后端开发模式 vs 前后端分离模式
  2. Spring Security的logout功能
  3. invalidateHttpSession不好用,bug?原来还是功力不够!

1. 传统后端开发模式 vs 前后端分离模式

  1. 传统后端开发模式
    上面主要练习传统后端开发模式,在这种模式下,页面的渲染都是请求后端,在后端完成页面的渲染。认证的页面都是通过https://localhost:8080/loginPage进行用户名和密码的form填写,之后重定向到需要认证的资源的页面。
    正如[spring boot(学习笔记第十二课)](https://blog.csdn.net/s在这里插入图片描述
    ealaugh1980/article/details/140224760)的练习的那样,在传统后端开发模式,需要配置各种页面.
    .formLogin(form -> form.loginPage("/loginPage").loginProcessingUrl("/doLogin")//这里的url不用使用controller进行相应,spring security自动处理.usernameParameter("uname")//页面上form的用户名.passwordParameter("passwd").defaultSuccessUrl("/index")//默认的认证之后的页面.failureForwardUrl("/loginPasswordError"))//默认的密码失败之后的页面
    .exceptionHandling(exceptionHandling ->exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()))
    
  2. 前后端分离开发模式
    现在web application的已经过渡到了前后端分离开发模式,而spring boot security也兼容这种模式。
    在这里插入图片描述
    接下来通过使用postman,模拟下前后端分离模式的spring security开发和使用场景。
    • 指定认证成功和失败的handler
      注意,这里一定要去掉 .loginPage("/loginPage")
      .formLogin(form -> form.loginProcessingUrl("/loginProcess")//这里对于前后端分离,提供的非页面访问url.usernameParameter("uname").passwordParameter("passwd").successHandler(new SuccessHandler()).failureHandler(new FailureHandler()))
      
    • 定义认证成功和失败的handler
      //success handlerprivate static class SuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authentication authentication) throws IOException {Object principal = authentication.getPrincipal();httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter printWriter = httpServletResponse.getWriter();httpServletResponse.setStatus(200);Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", principal);ObjectMapper om = new ObjectMapper();printWriter.write(om.writeValueAsString(map));printWriter.flush();printWriter.close();}}//failure handlerprivate static class FailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AuthenticationException authenticationException) throws IOException {httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter printWriter = httpServletResponse.getWriter();httpServletResponse.setStatus(401);Map<String, Object> map = new HashMap<>();map.put("status", 401);if (authenticationException instanceof LockedException) {map.put("msg", "账户被锁定,登陆失败");} else if (authenticationException instanceof BadCredentialsException) {map.put("msg", "账户输入错误,登陆失败");} else {map.put("msg", authenticationException.toString());}ObjectMapper om = new ObjectMapper();printWriter.write(om.writeValueAsString(map));printWriter.flush();printWriter.close();}
      
    • 一定要将/loginProcesspermitAll打开。注意,这里的习惯是将认证相关的url都定义成login开头的,并且一起进行/login*permitAll设定
          @BeanSecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(auth ->auth.requestMatchers("/login*").permitAll()
      
    • 使用postman进行认证测试。
      • pattern-1 正确的密码和用户名
        这里使用http://localhost:8080/loginProcess?uname=finlay_user&passwd=123456进行访问。注意,一定要是用post,不能使用get
        这里看到SuccessHandler
        在这里插入图片描述
    • pattern-2 错误的密码和用户名
      在这里插入图片描述
    • 认证成功,但是访问资源权限不够,需要设置exceptionHandling
      • 设置 exceptionHandling.accessDeniedHandler
       .exceptionHandling(exceptionHandling ->exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()))
      
      • 定义 exceptionHandler
        注意,在上一课传统后端开发模式的时候,定义的是redirect到画面,但是前后端分离模式,定义JSON返回值
        • 传统后端开发模式
        // 传统后端开发模式
        private static class CustomizeAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.sendRedirect("/loginNoPermissionError");}
        }
        
        • 传统前后端分离开发模式(JSON返回)
        // 传统前后端开发模式
        private static class CustomizeAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.sendRedirect("/loginNoPermissionError");}
        }
        
        • 访问/loginProcess,使用finlay_user(ROLE==user)进行登录
          在这里插入图片描述
        • 访问/db/hello,这里需要ROLE==DBA)进行登录,但是目前的httpSession不满足条件。在这里插入图片描述

2. Spring Security的logout功能

这里httpSession的如果需要logout,这里练习如何进行logout动作。

  1. 传统后端开发模式如何开发logout
    注意,这里传统后端开发模式需要将successHandlerfailureHandlerlogoutSuccessHandler都注释掉,否则,这个的对应的url设置都会无效
    .formLogin(form ->form.loginProcessingUrl("/loginProcess")//这里对于前后端分离,提供的非页面访问url.usernameParameter("uname").passwordParameter("passwd").loginPage("/loginPage").failureForwardUrl("/loginPasswordError").successForwardUrl("/index"))
    //                                .successHandler(new SuccessHandler())
    //                                .failureHandler(new FailureHandler())).logout(httpSecurityLogoutConfigurer ->httpSecurityLogoutConfigurer.logoutUrl("/logout").clearAuthentication(true).invalidateHttpSession(true).logoutSuccessUrl("/loginPage"))
    //                                .logoutSuccessHandler(new MyLogoutHandler())).exceptionHandling(exceptionHandling ->exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler())).csrf(csrf -> csrf.disable())//csrf跨域访问无效.sessionManagement(session -> session.maximumSessions(-1).maxSessionsPreventsLogin(true));
    
    • 设置logout处理的url
      .logoutUrl(“/logout”),这里的/logouot不需要进行对应,spring boot security会进行响应处理。
    • 对logout进行处理
       .logout(httpSecurityLogoutConfigurer ->httpSecurityLogoutConfigurer.logoutUrl("/logout").clearAuthentication(true).invalidateHttpSession(true).logoutSuccessUrl("/loginPage"))
      
      • clearAuthenticationSpring Security 中的一个方法,用于清除当前用户的认证信息,即使当前用户注销登录。在 SecurityContextHolder 中保存的 SecurityContext 对象将被清除,这意味着在下一次调用 SecurityContextHolder.getContext() 时,将不再有认证信息。
      • .invalidateHttpSession(true)是将httpSession删除,彻底进行logout
      • .logoutSuccessUrl("/loginPage"))调用将重定向到行的页面/logoutPage,这里是使用登录的页面。注意,这里如果调用.logoutSuccessHandler(new MyLogoutHandler())进行设定的话,就是使用前后端分离开发模式logoutSuccessUrl("/loginPage")即便设置也会无效
    • 设置logout处理页面(controller在页面上表示登录用户的用户名
       @GetMapping("/logoutPage")public String logoutPage(Model model) {String userName = "anonymous";Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication != null && authentication.isAuthenticated()) {if (authentication.getName() != null) {userName = authentication.getName();}}model.addAttribute("login_user",userName);return "logout";}
      
    • 设置logout处理页面(html
      <!DOCTYPE html>
      <html lang="en">
      <head><meta charset="UTF-8"><title>logout</title>
      </head>
      <body>
      <div th:text="${login_user}"></div>
      <form th:action="@{/logout}" method="post"><button type="submit" class="btn">Logout</button>
      </form>
      </body>
      </html>
      
    • 使用logout功能进行logout
      在这里插入图片描述
      在显示logout按钮的同时,也显示出了Authentication authentication = SecurityContextHolder.getContext().getAuthentication();取出来的login_user名字。
    • 点击logout按钮,成功后返回 .logoutSuccessUrl("/loginPage"))在这里插入图片描述
  2. 前后端分离开发模式如何开发logout
    • .logoutSuccessUrl("/loginPage"))替换成 .logoutSuccessHandler(new MyLogoutHandler()))

       .logout(httpSecurityLogoutConfigurer ->httpSecurityLogoutConfigurer.logoutUrl("/logout").clearAuthentication(true).invalidateHttpSession(true)
      //                                .logoutSuccessUrl("/loginPage")).logoutSuccessHandler(new MyLogoutHandler()))
      
    • 定义MyLogoutHandlerlogout结果包装成JSON格式,传给前端。

          private static class MyLogoutHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {HttpSession session = request.getSession(false);if (session != null) {// 使会话失效session.invalidate();}response.setContentType("application/json;charset=utf-8");PrintWriter printWriter = response.getWriter();response.setStatus(200);Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", "logout OK");ObjectMapper om = new ObjectMapper();printWriter.write(om.writeValueAsString(map));printWriter.flush();printWriter.close();}}
      
    • 如果logout完毕了,没有有效httpSession,那么访问/db/hello资源的话,怎么让spring security返回JSON,让前端框架接收到呢。这里需要AuthenticationEntryPoint

      • 设定AuthenticationEntryPoint
        .logout(httpSecurityLogoutConfigurer ->httpSecurityLogoutConfigurer.logoutUrl("/logout").clearAuthentication(true).invalidateHttpSession(true)
        //                                .logoutSuccessUrl("/loginPage")).logoutSuccessHandler(new MyLogoutHandler()))
        .exceptionHandling(exceptionHandling ->exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()).authenticationEntryPoint(new RestAuthenticationEntryPoint()))
        
      • 定义AuthenticationEntryPoint
            private static class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setContentType("application/json");String body = "{\"error\":\"Not Authenticated\"}";OutputStream out = response.getOutputStream();out.write(body.getBytes());out.flush();}}
        
    • 使用postman模拟前端进行login在这里插入图片描述

    • 模拟前端调用/logout进行logout在这里插入图片描述

    • 模拟前端调用/db/hello进行没有httpSession的访问,期待返回authenciationErrorJSON应答。
      在这里插入图片描述

3. invalidateHttpSession不好用,bug?原来还是功力不够!

  1. sessionManagement的设定
    .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true));
    
    在之前的设定中,一直设定的是.maximumSessions(-1),这个参数的意思是同一个用户同时登录spring boot security应用的数量,-1代表是没有限制,任意多个。在真正的系统中,一般会设定为1,意味着如果这个用户在另一个终端登录另外一个httpSession,那么当前的httpSession会被挤掉。
    那也意味着某一个用户执行,login->logout->login是能够在第二个login能够成功的,因为这里中间的logout已经invalidateHttpSession(true)了,但是试试果真如此吗?
  2. sessionManagement的设定maximumSessions(1),之后进行postman测试
    • 使用finlay_dba用户进行认证
      这里没有问题,认证OK。
      在这里插入图片描述
    • 访问http://localhost:8080:logout用户进行logout
      这里的logout也没有问题,成功。在这里插入图片描述
    • 访问http://localhost:8080/loginProcess用户进行再次login
      期待能够正常再次login,但是很遗憾,这里返回exceptionMaximum sessions of 1 for this principal exceeded
      在这里插入图片描述
  3. 如何解决问题
    • 问题在于尽管如下代码,在logout的时候进行了处理,但是和期待不同
      spring boot security不会将httpSession彻底无效化,调用了之后,spring boot security还是认为有httpSession正在登录,并没有过期expired
       .logout(httpSecurityLogoutConfigurer ->httpSecurityLogoutConfigurer.logoutUrl("/logout").clearAuthentication(true).invalidateHttpSession(true)
      
    • 在一个csdn旺枝大师文章中,给出了解决方法。
      spring boot security使用SessionRegistryhttpSession进行管理,所以需要这里Autowired出来SessionRegistryjava bean,使用这个java beanLogoutSuccessHandler里面进行sessionexpireNow的调用。
      • 首先配置SessionRegistry
        @Configuration
        public class SessionRegistryConfig {@Beanpublic SessionRegistry getSessionRegistry(){return new SessionRegistryImpl();}}
        
        注意,这里的SessionRegistryImplspring boot security的内部类,直接使用,不需要定义。
      • SecurityConfig里面直接Autowired
        @Configuration
        public class SecurityConfig {@BeanPasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}@Autowiredprivate SessionRegistry sessionRegistry;
        
      • SecurityConfig里面的MyLogoutHandler增加处理,调用expireNow()
         private static class MyLogoutHandler implements LogoutSuccessHandler {private SecurityConfig securityConfig = null;public MyLogoutHandler(SecurityConfig securityConfig) {this.securityConfig = securityConfig;}@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {HttpSession session = request.getSession(false);if (session != null) {// 使会话失效session.invalidate();}List<Object> o = securityConfig.sessionRegistry.getAllPrincipals();//退出成功后删除当前用户sessionfor (Object principal : o) {if (principal instanceof User) {final User loggedUser = (User) principal;if (authentication.getName().equals(loggedUser.getUsername())) {List<SessionInformation> sessionsInfo = securityConfig.sessionRegistry.getAllSessions(principal, false);if (null != sessionsInfo && sessionsInfo.size() > 0) {for (SessionInformation sessionInformation : sessionsInfo) {sessionInformation.expireNow();}}}}}response.setContentType("application/json;charset=utf-8");PrintWriter printWriter = response.getWriter();response.setStatus(200);Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", "logout OK");ObjectMapper om = new ObjectMapper();printWriter.write(om.writeValueAsString(map));printWriter.flush();printWriter.close();}}
        
    • 进行login->logout->login的动作验证
      • 首先login
        在这里插入图片描述
      • 其次访问http://localhost:8080/logout在这里插入图片描述
      • 最后再次访问http://localhost:8080/loginProcess
        到此为止,完美的动作确认结束!在这里插入图片描述

相关文章:

spring boot(学习笔记第十三课)

spring boot(学习笔记第十三课) 传统后端开发模式和前后端分离模式的不同&#xff0c;Spring Security的logout&#xff0c;invalidateHttpSession不好用&#xff0c;bug&#xff1f; 学习内容&#xff1a; 传统后端开发模式 vs 前后端分离模式Spring Security的logout功能inv…...

聊聊不再兼容安卓的鸿蒙

鸿蒙NExt已经确定不再兼容安卓系统&#xff0c;这意味着鸿蒙系统在更新迭代上将会展现出更加迅猛的速度。不过&#xff0c;这样的变化也给开发者们带来了不小的挑战。如今&#xff0c;鸿蒙的开发主要推荐使用的是ArkTS&#xff0c;而不是我们熟悉的Java SDK。对于大量习惯于使用…...

创建一个矩形,当鼠标进入这个矩形的时候,这个矩形边线变色,且鼠标变成手型

1.概要 创建一个矩形&#xff0c;当鼠标进入这个矩形的时候&#xff0c;这个矩形边线变色&#xff0c;且鼠标变成手型 2.代码 #include <QApplication> #include "customRectWidget.h" /** qt 6.7版&#xff0c; 创建一个矩形&#xff0c;当鼠标进入这个矩形…...

AI自动生成PPT哪个软件好?高效制作PPT优选这4个

7.15初伏的到来&#xff0c;也宣告三伏天的酷热正式拉开序幕~在这个传统的节气里&#xff0c;人们以各种方式避暑纳凉&#xff0c;享受夏日的悠闲时光。 而除了传统的避暑活动&#xff0c;我们还可以用一种新颖的方式记录和分享这份夏日的清凉——那就是通过PPT的方式将这一传…...

LruCache、Glide和SmartRefreshLayout使用总结

&#xff08;一&#xff09;Android智能下拉刷新框架-SmartRefreshLayout https://github.com/scwang90/SmartRefreshLayout?tabreadme-ov-file &#xff08;二&#xff09;LruCache使用 使用它可以进行图片的内存缓存 public class ImageLoaderUtil {private LruCache<St…...

Redis中数据分片与分片策略

概述 数据分片是一种将数据分割并存储在多个节点上的技术&#xff0c;可以有效提高系统的扩展性和性能。在Redis中&#xff0c;数据分片主要用于解决单个实例存储容量和性能瓶颈的问题。通过将数据分散存储到多个Redis节点中&#xff0c;可以将负载均衡到不同的服务器上&#…...

leetcode_169. 多数元素

leetcode_169. 多数元素 问题描述 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums …...

STM32 GPIO的工作原理

STM32的GPIO管脚有下面8种可能的配置:&#xff08;4输入 2 输出 2 复用输出) &#xff08;1&#xff09;浮空输入_IN_FLOATING 在上图上&#xff0c;阴影的部分处于不工作状态&#xff0c;尤其是下半部分的输出电路&#xff0c;实际上是与端口处于隔离状态。黄色的高亮部分显示…...

板级调试小助手(2)ZYNQ自定义IP核构建属于自己的DDS外设

一、前言 在上期文章中讲述了小助手的系统结构和原理。在PYNQ的框架开发中&#xff0c;我们一般可以将PL端当做PS端的一个外设&#xff0c;通过读写寄存器的方式来操作外设的功能&#xff0c;就类似于在开发ARM和DSP中操作外设一样&#xff0c;不同时的是&#xff0c;我们可以通…...

vim+cscope+ctags

一、简单安装 1.安装cscope # apt install cscope 2.安装ctags # apt install ctags 3.taglist安装 下载Vim source code browser plugin - Browse /vim-taglist at SourceForge.net&#xff0c;解压和复制文件 # unzip taglist_46.zip# cp doc/taglist.txt /usr/share/…...

Java 8的变革:函数式编程和Lambda表达式探索

文章目录 一、函数接口二、Lambda表达式简介三、Lambda表达式外部参数四、Lambda范例五、Runnable Lambda表达式 一、函数接口 函数接口是一个具有单个抽象方法的接口&#xff0c;接口设计主要是为了支持 Lambda 表达式和方法引用&#xff0c;使得 Java 能更方便地实现函数式编…...

Java集合框架的内部揭秘:List、Set与Map的深潜之旅

Java集合框架是一套强大的工具&#xff0c;为开发者提供了灵活的数据管理方式。本文将深入剖析List、Set和Map的内部机制&#xff0c;通过详细的示例和扩展讨论&#xff0c;带你领略这些数据容器的真谛。 一、List&#xff1a;有序序列的深度剖析 List接口是一个可以包含重复…...

爬虫(二)——爬虫的伪装

前言 本文是爬虫系列的第二篇文章&#xff0c;主要讲解关于爬虫的简单伪装&#xff0c;以及如何爬取B站的视频。建议先看完上一篇文章&#xff0c;再来看这一篇文章。要注意的是&#xff0c;本文介绍的方法只能爬取免费视频&#xff0c;会员视频是无法爬取的哦。 爬虫的伪装 …...

空安全编程的典范:Java 8中的安全应用指南

文章目录 一、Base64 编码解码1.1 基本的编码和解码1.2 URL 和文件名安全的编码解码器1.3 MIME Base64编码和解码 二、Optional类三、Nashorn JavaScript 一、Base64 编码解码 1.1 基本的编码和解码 Base64 编码&#xff1a; 使用 Base64.getEncoder().encodeToString(origin…...

Docker Machine 深入解析

Docker Machine 深入解析 引言 Docker Machine 是 Docker 生态系统中的一个重要工具,它简化了 Docker 容器环境的配置和管理过程。本文将深入探讨 Docker Machine 的概念、功能、使用场景以及如何在实际环境中高效利用它。 什么是 Docker Machine? Docker Machine 是一个…...

20.x86游戏实战-远线程注入的实现

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…...

06MFC之对话框--重绘元文件

文章目录 实现示例展示需要绘制的窗口/位置控件位置更新下一次示例粗细滑动部分更新重绘元文件(窗口变化内容消失)方法一:使用元文件方法二:兼容设备方法三:使用自定义类存储绘图数据除画笔外功能处理画笔功能处理保存前面画的线及色彩实现示例展示 需要绘制的窗口/位置 …...

鼠标的发明和鼠标“变形记”

注&#xff1a;机翻&#xff0c;未校对。 Who Invented the Computer Mouse? 谁发明了电脑鼠标&#xff1f; It was technology visionary and inventor Douglas Engelbart (January 30, 1925 – July 2, 2013) who revolutionized the way computers worked, turning it fr…...

快捷:通过胶水语言实现工作中测试流程并行、加速

通过胶水语言实现工作中测试流程并行、加速 通过胶水语言实现工作中测试流程并行、加速工作场景&#xff08;背景&#xff09;问题抽象&#xff08;挑战&#xff09;如何做&#xff08;行动&#xff09;获得了什么&#xff08;结果&#xff09;后记相关资源 通过胶水语言实现工…...

MySQL 和 PostgreSQL,我到底选择哪个?

MySQL 和 PostgreSQL 是两个广泛使用的关系型数据库管理系统&#xff08;RDBMS&#xff09;。它们都具有强大的功能和广泛的社区支持&#xff0c;但在某些方面存在一些差异。本文将详细比较 MySQL 和 PostgreSQL&#xff0c;包括它们的特点、性能、扩展性、安全性以及适用场景等…...

Java —— 内部类

Java内部类 1.什么是内部类&#xff1f; 将一个类A定义在另一个类B里面&#xff0c;里面的类A就称为内部类&#xff08;InnerClass&#xff09;&#xff0c;类B则称为外部类&#xff08;OuterClass&#xff09;。 2.为什么需要内部类&#xff1f; 具体来说&#xff0c;当一…...

高职院校人工智能人才培养成果导向系统构建、实施要点与评量方法

一、引言 近年来&#xff0c;人工智能技术在全球范围内迅速发展&#xff0c;对各行各业产生了深远的影响。高职院校作为培养高技能人才的重要基地&#xff0c;肩负着培养人工智能领域专业人才的重任。为了适应社会对人工智能人才的需求&#xff0c;高职院校需要构建一套科学、…...

ffmpeg中的超时控制

在FFmpeg库中&#xff0c;很多函数没有直接的参数可以设置超时。 那么有哪些函数可以通过设置 AVFormatContext 的 interrupt_callback 来实现超时控制&#xff1f; avformat_open_input&#xff1a; 打开输入文件或流。这个函数会阻塞&#xff0c;尤其是在网络流的情况下&…...

搜维尔科技:【研究】触觉技术将在5年内以8种方式改变人们的世界

触觉技术在过去几年中发展迅猛&#xff0c;大大提高了反馈的精确度和真实度。其应用产生了真正的影响&#xff0c;数百家公司和企业都集成了触觉技术来增强培训和研究模拟。 虽然触觉技术主要用于 B2B 层面&#xff0c;但触觉技术可能会彻底改变我们的生活&#xff0c;尤其是通…...

项目收获总结--MyBatis的知识收获

MyBatis的知识收获 一、概述二、获取自动生成的(主)键值三、将sql执行结果封装为目标返回对象的方式和原理四、延迟加载实现原理五、批量插入六、自带分页与分页插件原理七、Mapper(Dao)接口与XML映射文件关系八、模糊查询like语句九、#{}和${}的区别十、二级缓存案例实战 一、…...

数据库管理-第221期 Oracle的高可用-04(20240717)

数据库管理221期 2024-07-17 数据库管理-第221期 Oracle的高可用-04&#xff08;20240717&#xff09;1 ADG2 连接配置2.1 TNS2.2 JDBC2.3 JAVA连接池2.3.1 Oracle UCP2.3.2 应用连接池基础配置 总结 数据库管理-第221期 Oracle的高可用-04&#xff08;20240717&#xff09; 作…...

navicat15已连接忘记密码

1.导出链接 2.使用文本打开 connections.ncx UserName"root" PasswordXXXX 3.复制加密密码&#xff0c;在线解密 代码在线运行 - 在线工具 php解密代码 <?php class NavicatPassword {protected $version 0;protected $aesKey libcckeylibcckey;protected…...

企业管理必备:学会寻找客户绝佳方法。

无论是日常沟通、工作交流&#xff0c;还是社交娱乐&#xff0c;微信都扮演着重要的角色。而在微信的使用过程中&#xff0c;添加好友是一项基本而重要的操作&#xff0c;但是您真的会添加微信好友吗&#xff1f; 试试这个神器——微信管理系统&#xff0c;下面分享它快速加客…...

昇思25天学习打卡营第29天 | 文本解码原理--以MindNLP为例

今天是29天&#xff0c;学习了文本解码原理--以MindNLP为例。 MindNLP 是一个基于 MindSpore 的开源自然语言处理&#xff08;NLP&#xff09;库。它具有以下特点&#xff1a; 支持多种 NLP 任务&#xff1a;如语言模型、机器翻译、问答、情感分析、序列标记、摘要等&#xff…...

元服务体验-服务发现

服务发现&#xff0c;无论线上或线下的方式都可以发现元服务。 线上&#xff1a;基于用户意图。从精准意图的搜索、用户事件触发的推荐到主动探索等场景。用户可以在设备的负一屏、全局搜索、应用市场、桌面等场景发现元服务。 线下&#xff1a;用户在 HarmonyOS Connect标签…...

公司自己做网站多少费用/企业管理培训

在做一个取子节点的程序中遇到的一个问题&#xff0c;本来用childNodes是很容易搞定的事情&#xff0c;结果... <div id"mylist"><li>first</li><li>second</li><li>third</li></div> <script language"jav…...

群晖套件wordpress/百度网址

1、局部变量能否和全局变量重名&#xff1f; 答&#xff1a;能&#xff0c;局部会屏蔽全局。要用全局变量&#xff0c;需要使用"::" ;局部变量可以与全局变量同名&#xff0c;在函数内引用这个变量时&#xff0c;会用到同名的局部变量&#xff0c;而不会用到全局变量…...

wordpress做css/ui培训

意甲冠军&#xff1a; 给k(1<k<10^15)&#xff0c;先询问k 大只包含数字5和6的数目是多少 实例 1那是&#xff0c;5 &#xff0c;3那是&#xff0c;55 。4那是&#xff0c;56 思考&#xff1a; 首先&#xff0c;我们可以找到。有许多2这是头号&#xff0c;有两个数字4个月…...

大气网站背景/百度热榜排行

本文之初&#xff0c;道声张老师一路走好&#xff0c;您给我们留下的不止那么几本书&#xff0c;几个视频…… 财政局和市民卡公司有个对账业务&#xff0c;在这个业务中需要用到socket传送一些报文内容&#xff0c;主要传送的是对账文件名以及队长文件内容签名加密后的内容。 …...

公司设计网站需要多少钱/营销推广型网站

原标题&#xff1a;浪潮信息打造新型液冷超算方案&#xff0c;助力创新港建设高性能计算平台当下&#xff0c;高性能计算平台是数字技术发展的主要驱力&#xff0c;同时也是科学发展、人才培养、服务社会的重要支撑。浪潮信息聚焦西安交通大学师生以及中国西部科技创新港科研人…...

学做网站 为了熊掌号/百度推广系统营销平台

在开发过程中&#xff0c;收到这样一个问题反馈&#xff0c;在网站上传 100 MB 以上的文件经常失败&#xff0c;重试也要等老半天&#xff0c;这就难为需要上传大规格文件的用户了。那么应该怎么做才能快速上传&#xff0c;就算失败了再次发送也能从上次中断的地方继续上传呢&a…...