JavaWeb学习--cookie和session,实现登录的记住我和验证码功能

news2025/2/27 14:33:13

目录

(一)Cookie概述

1.什么叫Cookie

2.Cookie规范

 3.Cookie的覆盖

4.cookie的最大存活时间 ​​​​​​(Cookie的生命) 

(二) Cookie的API

1.创建Cookie:new  构造方法

 2.保存到客户端浏览器上,通过响应对象addCookie()

3.在服务器端获取cookie内容 请求对象:Cookie[] getCookies()  

(三)案例:记住我功能的实现

1.实现思路

第一步: 在servlet中写逻辑代码,判断是否勾选“记住我”

第二步:在login.jsp 获取服务器传过来的cookie的值,设置到表单元素上

(四) HttpSession

 1.什么是HttpSesssion

2.获取HttpSession对象

3.HttpSession是域对象

 4.案例:在登录中引入验证码

第一步:在login.jsp页面显示验证码

第二步:定义函数,在jsp页面编写refreshCode()方法

第三步:修改LoginServlet类的代码,当验证码错误时,显示“验证码错误”,若验证码不成功,不验证用户名和密码是否正确


(一)Cookie概述

1.什么叫Cookie

       Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。

       Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!

总结:

cookie特征:

  1. 创建于服务器,保存于客户端
  2. 不同的浏览器之间不能共享,
  3. 不能跨浏览器
  4. Cookie的key,value都是String
  5. 在之后的请求中,cookie会以请求头的方式自动发送给服务器

请求头:

缺点:

  1. 不安全,在客户端浏览器的键值不加密
  2. key,value的数据类型有限,只能存string类型的数据

2.Cookie规范

  • Cookie大小上限为4KB;(不同的浏览器cookie的内存大小可能不同

  • 一个服务器最多在客户端浏览器上保存20个Cookie;

  • 一个浏览器最多保存300个Cookie;

注意:

      不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。  

 3.Cookie的覆盖

       如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。

       如果cookie的name与path一样, 覆盖value, 如果没有设置path: 默认值, 创建Cookie的资源上级路径  

虽然name相同,但path不一样,所以没有覆盖

name相同,path相同,覆盖

cookie的path:

  • localhost:8090/bbb

访问的cookie: path为/下的cookie

  • localhost:8090/user/ccc

访问的cookie: path为/下的cookie和path为/user下的cookie

  • localhost:8090/a/b/c/d: 能访问的cookie: /c 下, /b 下 /a下 /下

path为/下的cookie,可以被所有的资源访问

某个url能访问的cookie: path为父辈级目录的Cookie,

调用setPath()给cookie设置path

 

4.cookie的最大存活时间 ​​​​​​(Cookie的生命) 

默认存活时间:会话级别,浏览器关闭,这个cookie就会被删除

调用setMaxAge(int 参数) 设置最大存活时间 单位: 秒

-1: 会话级别

>0: 存活多少秒, 时间一到,浏览器自动清除

0: 立即删除cookie

会话的概念:客户端打开浏览器,访问服务器表示会话的开始

  1. 只要浏览器不关闭, 这次会话一直存在, 这次会话内所有的请求, 共享同一个session域
  2. 当客户端关闭浏览器, 表示会话的结束
  3. 类似于生活中的通话

(二) Cookie的API

1.创建Cookie:new  构造方法

构造方法:

 2.保存到客户端浏览器上,通过响应对象addCookie()

//创建Cookie保存到客户端浏览器上
        Cookie cookie1 = new  Cookie("k1","v100");
        Cookie cookie2 = new  Cookie("k2","v200");

        //cookie的设置代码,一定在addCookie()之前
        //给cookie设置最大存活时间
        cookie1.setMaxAge(150);
        cookie2.setMaxAge(150);

        //保存到客户端
        resp.addCookie(cookie1);
        resp.addCookie(cookie2);

添加成功:

3.在服务器端获取cookie内容 请求对象:Cookie[] getCookies()  

@WebServlet("/bbb")
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //获取客户端浏览器传递Cookie
      //  System.out.println(req.getHeader("Cookie"));
        Cookie[] cookies = req.getCookies();
        //循环遍历
        for (Cookie cookie : cookies) {
            //获取Cookie的key, value
            String name = cookie.getName();
            if(name.equals("username") || name.equals("pwd")){
                String value = cookie.getValue();
                System.out.println("key:"+name+",value:"+value);
            }
        }
    }

(三)案例:记住我功能的实现

登录成功之后, 把用户名,密码保存起来, 保存方式?

(1)服务器? 客户端? 选择方案: 客户端

(2)如果保存在服务器, 存在哪

(3)如果保存在客户端, 存在哪    存在客户端浏览器

在客户端浏览器上有这三个地方可以存

那么我们应该选择哪一个来保存我们的数据呢?

       因为我们需要实现的是登录成功之后,把用户名、密码保存起来,所以这两个数据应该在服务器端的逻辑代码执行完毕之后传给客户端,所以是服务器传给客户端的数据。

      1.本地存储 localStorage, 会话存储 sessionStorage: 纯js技术, java没有

      2.Cookie:js操作, java也能操作 

      所以我们选择使用cookie来存储从服务器端传来的数据,也就是登录成功之后的用户名和密码。

1.实现思路

登录成功之后,并且用户勾选了“记住我”用户名,密码保存到cookie

第一步: 在servlet中写逻辑代码,判断是否勾选“记住我”

LoginServlet代码:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置post请求编码, 响应编码
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        //进行验证码验证
        String verify=req.getParameter("verifycode");
        HttpSession session=req.getSession();
        String code=(String)session.getAttribute("CHECKCODE_SERVER");
        if (code.equals(verify)){
            //2.获取请求参数
            String username = req.getParameter("user");
            String password = req.getParameter("password");
            //3.调用业务层LoginService的登录方法
            LoginService loginService = new LoginServiceImpl();
            LoginInfo loginInfo = loginService.login(username, password);
            if(loginInfo != null){  //登陆成功
                String rem=req.getParameter("rem");
                if(Objects.nonNull(rem)){
                    //把用户名,密码保存到cookie
                    Cookie cookie1 = new Cookie("username", username);
                    Cookie cookie2=new Cookie("pwd",password);
                    //设置存活时间  7天
                    cookie1.setMaxAge(60*60*24*7);
                    cookie2.setMaxAge(60*60*24*7);
                    //设置path为/  项目下任何资源可以访问
                    cookie1.setPath("/");
                    cookie2.setPath("/");
                    //保存到客户端
                    resp.addCookie(cookie1);
                    resp.addCookie(cookie2);
                }
                session.setAttribute("login",loginInfo);
                resp.sendRedirect("/index.jsp");
            }else{   //登录失败
                //转发到登录页面
                //把错误信息保存到request域
                req.setAttribute("error", "用户名或密码错误");
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            }
        }else{
            req.setAttribute("error","验证码错误");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }

    }
}

记住我部分:

第二步:在login.jsp 获取服务器传过来的cookie的值,设置到表单元素上

login.jsp代码:

<body>
<%
    Cookie[] cookies=request.getCookies();
    String username="";
    String password="";
    if(cookies!=null && cookies.length > 0){
        for (Cookie cookie:cookies){
            if(cookie.getName().equals("username")){
                username=cookie.getValue();
            }
            if (cookie.getName().equals("pwd")){
                password=cookie.getValue();
            }
        }
    }
%>
<div class="container" style="width: 400px;">
    <h3 style="text-align: center;">管理员登录</h3>
    <form action="/login" method="post">
        <div class="form-group">
            <label for="user">用户名:</label>
            <input type="text" name="user" class="form-control" id="user" placeholder="请输入用户名" value="<%=username%>"/>
        </div>

        <div class="form-group">
            <label for="password">密码:</label>
            <input type="password" name="password" class="form-control" id="password" placeholder="请输入密码" value="<%=password%>"/>
        </div>

        <div class="form-inline">
            <label for="vcode">验证码:</label>
            <input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/>
            <a href="javascript:refreshCode()"><img src="vcode" title="看不清点击刷新" id="vcode"/></a>
        </div>
        <div class="form-inline">
            <input type="checkbox" name="rem" class="form-control" id="rem" value="rem" />
            <label for="rem">记住我</label>
        </div>
        <hr/>
        <div class="form-group" style="text-align: center;">
            <input class="btn btn btn-primary" type="submit" value="登录">
        </div>
    </form>
    <!-- 出错显示的信息框 -->
    <div class="alert alert-warning alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert" >
            <span>&times;</span>
        </button>
        <strong>${error}</strong>
    </div>
</div>
</body>

实现:

(四) HttpSession

Cookie和HttpSession的区别:

Cookie:创建于服务器,保存于客户端

HttpSession:域对象,创建于服务器,保存于服务器,同一次会话有效

 1.什么是HttpSesssion

javax.servlet.http.HttpSession接口表示一个会话,我们可以把一个会话内需要共享的数据保存到HttpSession对象中!

每一个客户端都有自己的Session

 session作用: 域对象功能, 存,取数据

2.获取HttpSession对象

通过request对象的getSession()来获取

  • HttpSession request.getSesssion():如果当前会话已经有了session对象那么直接返回,如果当前会话还不存在会话,那么创建session并返回

  • HttpSession request.getSession(boolean):当参数为true时,与requeset.getSession()相同。如果参数为false,那么如果当前会话中存在session则返回,不存在返回null;

3.HttpSession是域对象

  • HttpServletRequest:一个请求创建一个request对象,所以在同一个请求中可以共享request,例如一个请求从AServlet转发到BServlet,那么AServlet和BServlet可以共享request域中的数据;

  • ServletContext:一个应用只创建一个ServletContext对象,所以在ServletContext中的数据可以在整个应用中共享,只要不启动服务器,那么ServletContext中的数据就可以共享;

  • HttpSession:一个会话创建一个HttpSession对象,同一会话中的多个请求中可以共享session中的数据;

下面是session的域方法:

  • void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:session.setAttribute(“xxx”, “XXX”),在session中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;

  • Object getAttribute(String name):用来获取session中的数据,当前在获取之前需要先去存储才行,例如:String value = (String) session.getAttribute(“xxx”);,获取名为xxx的域属性;

  • void removeAttribute(String name):用来移除HttpSession中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;

  • Enumeration getAttributeNames():获取所有域属性的名称;

 4.案例:在登录中引入验证码

生成验证码Servlet:

在一个矩形框内生成随机字符

/**
 * 验证码
 */
@WebServlet("/checkCode")
public class CheckCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		
		//服务器通知浏览器不要缓存
		response.setHeader("pragma","no-cache");
		response.setHeader("cache-control","no-cache");
		response.setHeader("expires","0");
		
		//在内存中创建一个长80,宽30的图片,默认黑色背景
		//参数一:长
		//参数二:宽
		//参数三:颜色
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		//获取画笔
		Graphics g = image.getGraphics();
		//设置画笔颜色为灰色
		g.setColor(Color.GRAY);
		//填充图片
		g.fillRect(0,0, width,height);
		
		//产生4个随机验证码,12Ey
		String checkCode = getCheckCode();
		//将验证码放入HttpSession中
		request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
		
		//设置画笔颜色为黄色
		g.setColor(Color.YELLOW);
		//设置字体的小大
		g.setFont(new Font("黑体",Font.BOLD,24));
		//向图片上写入验证码
		g.drawString(checkCode,15,25);
		
		//将内存中的图片输出到浏览器
		//参数一:图片对象
		//参数二:图片的格式,如PNG,JPG,GIF
		//参数三:图片输出到哪里去
		ImageIO.write(image,"PNG",response.getOutputStream());
	}
	/**
	 * 产生4位随机字符串 
	 */
	private String getCheckCode() {
		String base = "0123456789ABCDEFGabcdefg";
		int size = base.length();
		Random r = new Random();
		StringBuffer sb = new StringBuffer();
		for(int i=1;i<=4;i++){
			//产生0到size-1的随机值
			int index = r.nextInt(size);
			//在base字符串中获取下标为index的字符
			char c = base.charAt(index);
			//将c放入到StringBuffer中去
			sb.append(c);
		}
		return sb.toString();
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}

第一步:在login.jsp页面显示验证码

<div class="form-inline">
    <label for="vcode">验证码:</label>
    <input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/>
    <a href="javascript:refreshCode()"><img src="vcode" title="看不清点击刷新" id="vcode"/></a>
</div>

第二步:定义函数,在jsp页面编写refreshCode()方法

<script type="text/javascript">
        function refreshCode() {
            //每次点击时,重新生成验证码
            console.log("refreshCode....")
            //选择器 #id名
            //获取到img标签   浏览器缓存,url没有变化,使用上一次缓存的内容
            //加一个时间戳,每一次都不一样,浏览器发现参数不一样,以为是新请求,不使用上一次缓存
            $("#vcode").attr("src","/checkCode?time="+new Date().getTime())
        }
    </script>

第三步:修改LoginServlet类的代码,当验证码错误时,显示“验证码错误”,若验证码不成功,不验证用户名和密码是否正确

//进行验证码验证
        String verify=req.getParameter("verifycode");
        HttpSession session=req.getSession();
        String code=(String)session.getAttribute("CHECKCODE_SERVER");
        if (code.equals(verify)){
            //2.获取请求参数
            String username = req.getParameter("user");
            String password = req.getParameter("password");
            //3.调用业务层LoginService的登录方法
            LoginService loginService = new LoginServiceImpl();
            LoginInfo loginInfo = loginService.login(username, password);
            if(loginInfo != null){  //登陆成功
                String rem=req.getParameter("rem");
                if(Objects.nonNull(rem)){
                    //把用户名,密码保存到cookie
                    Cookie cookie1 = new Cookie("username", username);
                    Cookie cookie2=new Cookie("pwd",password);
                    //设置存活时间  7天
                    cookie1.setMaxAge(60*60*24*7);
                    cookie2.setMaxAge(60*60*24*7);
                    //设置path为/  项目下任何资源可以访问
                    cookie1.setPath("/");
                    cookie2.setPath("/");
                    //保存到客户端
                    resp.addCookie(cookie1);
                    resp.addCookie(cookie2);
                }
                session.setAttribute("login",loginInfo);
                resp.sendRedirect("/index.jsp");
            }else{   //登录失败
                //转发到登录页面
                //把错误信息保存到request域
                req.setAttribute("error", "用户名或密码错误");
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            }
        }else{
            req.setAttribute("error","验证码错误");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }

结果:

登录成功

验证码错误

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258027.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux网络测试指令

Ping Ping命令是一个网络工具&#xff0c;用于测试主机之间的可达性。它通过发送ICMP&#xff08;Internet Control Message Protocol&#xff09;回声请求消息到目标主机&#xff0c;并等待接收ICMP回声应答消息来判断目标是否可达以及测量往返时间。Ping命令对于诊断网络连接…

【伪代码】数据结构-期末复习 线性表

目录 例1 矩阵相乘 线性表 2.1 线性表的类型定义 例2-1 求并集 LALA∪LB 例2-2 有序表归并 2. 2 线性表的顺序表示和实现 1&#xff0e;构造空表 2&#xff0e;插入 3&#xff0e;删除 4&#xff0e;定位 顺序表的优点&#xff1a; 顺序表的缺点&#xff1a; 例…

<C++11> 智能指针

目录 前言 C11和boost中智能指针的关系 一、智能指针的使用及原理 1. 智能指针介绍 2. 智能指针的使用 3. 智能指针的原理 二、C中的智能指针 1. auto_ptr 2. unique_ptr 3. shared_ptr std::shared_ptr的基本设计 shared_ptr的线程安全问题 定制删除器 4. weak_ptr shared_pt…

书生实战营第四期-进阶岛第六关-MindSearch 快速部署

一、开发环境配置 1、打开codespace主页&#xff0c;选择Blank模板进行创建 Codespaces 2、创建conda环境隔离并安装依赖 conda create -n mindsearch python3.10 -y conda init 因为是新建的codespace&#xff0c;在第一次创建conda环境时&#xff0c;需要conda init 然后再…

ViT学习笔记(二) Patch+Position Embedding阶段的详细推演与理解

我认为讲得最好的一个文章&#xff1a;Vision Transformer详解-CSDN博客 有很多文章&#xff0c;自己并没有完全正确理解。 我的笔记&#xff0c;以ViT的标准应用为例&#xff1a; • 输入图像&#xff1a;输入图像的尺寸是224x224&#xff0c;且是RGB图像&#xff0c;因此输…

JS听到了强运的回响

正则表达式 介绍 正则表达式是用于匹配字符串中字符组合的模式&#xff0c;在JS中&#xff0c;正则表达式也是对象 通常用来查找&#xff0c;替换那些符合正则表达式的文本 就是筛选出符合条件的一类人 比如说 有人喜欢玩艾斯爱慕&#xff0c;那他喜欢的就是这一类人&…

工业4.0下的IT网络与OT网络

https://zhuanlan.zhihu.com/p/498984722 随着“中国制造2025”的深入推进&#xff0c;制药行业以手工为主的传统生产方式正在被以“工业4.0 ”为核心的自动化生产方式逐步替代。 为了实现生产自动化&#xff0c;很多制药企业都引入了由PLC&#xff08;可编程逻辑控制器 &am…

C# MVVM 牛牛的实现依赖注入和MVVM绑定(DependencyInjection+CommunityToolkit)

这段时间在网上发现搜索MVVM数据绑定时&#xff0c;发现很多都是最基本的数据绑定&#xff0c;完全没有考虑依赖注入的问题&#xff0c;这里实现一下我们的方法&#xff0c;让我们的数据绑定和依赖注入都变得简单起来。 安装资源包 首先我们要下载一下资源包DependencyInject…

gitee常见命令

目录 1.本地分支重命名 2.更新远程仓库分支 3.为当前分支设置远程跟踪分支 4.撤销已经push远程的代码 5.idea->gitee的‘还原提交’ 需要和本地当前的代码解决冲突 解决冲突 本地工作区的差异代码显示 本地commit和push远程 6.idea->gitee的‘将当前分支重置到此…

【JAVA高级篇教学】第二篇:使用 Redisson 实现高效限流机制

在高并发系统中&#xff0c;限流是一项非常重要的技术手段&#xff0c;用于保护后端服务&#xff0c;防止因流量过大导致系统崩溃。本文将详细介绍如何使用 Redisson 提供的 RRateLimiter 实现分布式限流&#xff0c;以及其原理、使用场景和完整代码示例。 目录 一、什么是限流…

Python画泰勒图

1. 安装画泰勒图的库 pip install SkillMetricsSkillMetrics库在图的设置细节&#xff08;模型标记符号、colorbar&#xff09;有很多不足&#xff0c;比如无法按颜色区分每个散点。 注意&#xff01;&#xff01;&#xff01; 提前算好数据的标准差、相关系数和中心化均方根…

可视化建模以及UML期末复习篇----UML图

这是一篇相对较长的文章&#xff0c;如你们所见&#xff0c;比较详细&#xff0c;全长两万字。我不建议你们一次性看完&#xff0c;直接跳目录找你需要的知识点即可。 --------欢迎各位来到我UML国&#xff01; 一、UML图 总共有如下几种&#xff1a; 用例图&#xff08;Use Ca…

【MySQL】——​​用一文领悟表的增删查改

目录 前言 &#x1f343;1.表的增加 &#x1f359;1.1增——insert &#x1f359;1.2插入否则更新 &#x1f364;1.2.1影响行说明 &#x1f342;2.表的查询 &#x1f358;2.1查询——select &#x1f358;2.2特殊表查询 &#x1f365;2.2.1添加表达式 &#x1f365;…

福昕PDF低代码平台

福昕PDF低代码平台简介 福昕PDF 低代码平台是一款创新的工具&#xff0c;旨在简化PDF处理和管理的流程。通过这个平台&#xff0c;用户可以通过简单的拖拽界面上的按钮&#xff0c;轻松完成对Cloud API的调用工作流&#xff0c;而无需编写复杂的代码。这使得即使没有编程经验的…

【数据结构实战】二叉树——从根节点到叶节点

&#x1f3dd;️专栏&#xff1a; 【数据结构实战篇】 &#x1f305;主页&#xff1a; f狐o狸x 目录 一、堆的应用 1.1 堆排序 1.2 topk问题 二、二叉树 2.1 二叉树链式结构的实现 2.2 二叉树的遍历 2.2.1 前序、中序以及后序遍历 2.2.2 层序遍历 2.3 节点个数以及高度等 2.3.…

命令模式的理解和实践

在软件开发中&#xff0c;设计模式是开发者们经过长期实践总结出来的、可复用的解决方案&#xff0c;用于解决常见的设计问题。命令模式&#xff08;Command Pattern&#xff09;是行为型设计模式之一&#xff0c;它通过将一个请求封装成一个对象&#xff0c;从而允许用户用不同…

vue-router查漏补缺

一、动态路由匹配 1.带参数的动态路由匹配 import User from ./User.vue// 这些都会传递给 createRouter const routes [// 动态字段以冒号开始{ path: /users/:efg, component: User }, ]这种方式的路由会匹配到/users/abc或者/users/123,路径参数用冒号:表示&#xff0c;并…

Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】

anaconda可以提供多个独立的虚拟环境&#xff0c;方便我们学习深度学习&#xff08;比如复现论文&#xff09;&#xff1b; Pycharm编辑器可以高效的编写python代码&#xff0c;也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程&#xff1a; 1.Anaconda安装 下载Ana…

三维测量与建模笔记 - 6.2 结构光三维成像简介

简介 双目视觉系统中&#xff0c;找到左右图像中的同名点是很困难的。 即便是经过了极线校正&#xff0c;也存在很多问题比如高光等造成无匹配。对于结构光方案来说&#xff0c;找到同名点的过程会相对简单些。 结构光方案中&#xff0c;会增加一个投射器&#xff0c;将编码后的…

this version of the Java Runtime only recognizes class file versions up to 52.0

问题描述 Exception in thread "main" java.lang.UnsupportedClassVersionError: com/xxx/Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versi…