Cookie,Session与Token

news/2024/12/24 10:51:23/文章来源:https://www.cnblogs.com/qinLiCode/p/18442907

参考资料

水平有限,欢迎交流!仅做学习交流使用
一定要看,非常透彻!【Cookie、Session、Token究竟区别在哪?如何进行身份认证,保持用户登录状态?】
黑马jwt详解
Javaweb程序设计与项目案例 郭煦

直接上结论

共同点

Cookie,Session与Token 三者都实现了 Http 无状态这一特点的补充,通过存储在不同硬件或不同算法加密来存储用户状态

不同点

Cookie 将用户状态保存在客户端(如浏览器)
Session 将用户状态保存在服务器端

Cookie 详解

Cookie 是服务器发送到用户浏览器并保存在本地的小块数据。Cookie 由浏览器(客户端)管理,每次请求都会自动发送到服务器。需要注意的是,由于隐私和安全原因,许多现代浏览器对第三方 Cookie(即由不同于当前浏览网站的域发送的 Cookie)进行了限制。此外,一些用户也可能选择禁用 Cookie,这可能会影响依赖于 Cookie 的功能正常运作。

特点

  1. 存储限制:每个域名下可以存储的 Cookie 数量有限,通常不超过 20 个。
  2. 大小限制:每个 Cookie 的大小通常限制在 4 KB 左右。
  3. 安全问题:Cookie 可以被客户端篡改,因此不适用于存储敏感信息。
  4. 作用域:Cookie 可以设置作用域,例如仅在当前域名下有效。

分类

此外,Cookie 还可以分为会话 Cookie 和持久性 Cookie:

  • 会话 Cookie 只在用户与网站交互期间存在(存放在客户端内存),并且在用户关闭浏览器时就会被删除。
  • 持久性 Cookie 有一个明确的过期日期,即使用户关闭浏览器后,Cookie 也会被保留 (存放在客户端硬盘),直到过期日期为止。

用途

  • 会话管理:通过 Cookie 识别用户身份,实现用户登录状态的持久化。
  • 个性化设置:存储用户偏好设置,如语言、主题等。

流程

Cookies 是网站用来在用户浏览器上存储小量数据的一种机制。它们用于跟踪用户的活动,保存用户的偏好设置,以及实现其他功能性的需求。下面是 Cookie 的基本工作流程:

  1. 用户首次访问一个网站(此时不存在 Cookie),浏览器向服务器发送请求。
  2. 服务器处理请求,并根据需要将数据发送给浏览器,同时可以附加一个或多个 Cookie。Set-Cookie: name = value
  3. 浏览器接收到响应后,会检查是否有任何 Cookie 信息,并存储这些 Cookie 在本地硬盘上。
  4. 当浏览器后续请求同一站点时,浏览器都会自动包含这个 Cookie 在 HTTP 请求头中 发送给服务器。
  5. 服务器根据接收到的 Cookie 来识别用户,从而提供个性化的网页内容或者恢复用户的偏好设置等。
    image-20241001152305819

常用方法

image-20241001152320560

案例

import java.io.IOException;
import java.io.PrintWriter;//tomcat版本10.1 用的jakarta,版本较低可将jakarta换为javax!
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;@WebServlet("/CookieDemo")
public class CookieDemo extends HttpServlet{@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubPrintWriter out = resp.getWriter();Cookie[] cookies = req.getCookies();resp.setContentType("text/html;charset = UTF-8");boolean flag = false;if(cookies!=null) {for (Cookie cookie : cookies) {if(cookie.getName().equals("ip")) {out.write("welcome!上次ip为:"+ cookie.getValue());flag = true;break;}}if(!flag) {out.write("欢迎新用户!");Cookie c = new Cookie("ip",req.getRemoteAddr());c.setMaxAge(1*60);//单位:s  这里为1minresp.addCookie(c);}}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubsuper.doPost(req, resp);}
}

image-20241001152344437

Session 详解

Session 是服务器端用来跟踪用户会话的一种机制。当用户首次访问服务器时,服务器会创建一个 Session,并生成一个唯一的 Session ID,这个 ID 通常会存储在 Cookie 中,随请求发送回服务器。

特点:

  1. 存储位置:Session 数据存储在服务器端,安全性较高。
  2. 存储限制:由于存储在服务器,理论上没有大小限制,但会占用服务器资源。
  3. 生命周期:可以设置 Session 的过期时间,过期后自动销毁。
  4. 作用域:通常与浏览器窗口或标签页的生命周期相关。

用途:

  • 用户身份验证:存储用户登录后的会话信息。
  • 购物车:存储用户的购物车数据。

常用功能

image-20241001152359210

流程

  1. 用户发起请求:当用户打开浏览器并访问一个网站时,浏览器向服务器发送一个 HTTP 请求。
  2. 服务器创建 Session:服务器接收到请求后,如果发现这是一个新用户(即没有可用的 Session ID),则会创建一个新的 Session 并分配一个唯一的 Session ID 给这个用户。如果用户之前已经有过会话,则服务器会从请求中提取已有的 Session ID。
  3. 存储 Session 数据:服务器会在服务器端存储与 Session ID 相关的信息,比如用户的偏好设置、购物车中的商品或者其他状态信息。
  4. 返回响应和 Session ID:服务器处理完请求后,会将处理结果和 Session ID 一起返回给客户端。通常,Session ID 是通过 Cookie 或者 URL 参数传递给客户端的。
  5. 客户端存储 Session ID:客户端(通常是浏览器)接收到响应后,会存储 Session ID(如果通过 Cookie 传递的话)。对于后续请求,浏览器会自动将 Session ID 发送给服务器。
  6. 使用 Session 数据:对于用户后续的请求,服务器会读取 Session ID,并查找与此 ID 相关联的数据来个性化用户的体验或继续处理用户的请求。
  7. Session 的结束:Session 通常会在一定时间后因无活动而超时,或者当用户显式地登出时结束。服务器会清除与该 Session ID 相关的数据。
    image-20241001152414209

补充说明

Session 的创建

Session 的超时时间设置

设置 Session 超时可以通过多种方式来实现,这取决于使用的编程语言和框架。以下是三种常见的方法来设置 Session 的超时时间:

1. Tomcat 全局配置

image-20241001152543133

2. 通过配置文件设置

许多 Web 应用框架允许你在配置文件中设置 Session 的超时时间。这种方式的好处是可以全局控制所有 Session 的超时时间,而无需修改代码。

示例:jsp 项目中web. Xml 中的配置

image-20241001152627837

<session-config><session-timeout>2</session-timeout>
</session-config>

示例:Java Spring Boot 中的配置

在 Spring Boot 中,可以通过 application.propertiesapplication.yml 文件来设置 Session 的超时时间:

server.tomcat.session-timeout=30 # 单位为分钟

3. 在代码中动态设置

在某些情况下,你可能希望针对不同的用户或操作设置不同的 Session 超时时间。这时可以在代码中动态地设置超时时间。

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;public class SessionServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {// 获取 HttpSession 对象HttpSession session = request.getSession();// 设置 Session 的超时时间为 30 分钟(以毫秒为单位)long timeoutInMillis = 30 * 60 * 1000; // 30 minutessession.setMaxInactiveInterval(timeoutInMillis / 1000); // 注意这里需要转换成秒// 输出确认信息response.getWriter().println("Session timeout set to " + session.getMaxInactiveInterval() + " seconds.");}
}

4. 使用中间件或过滤器,拦截器(本质还是 3)

对于一些框架,如 Node. Js 或者 Ruby on Rails,你可以编写中间件或者过滤器来控制 Session 的超时时间。
在 Java Web 开发中,Filter 和 Interceptor 是两种不同的机制,它们都可以用来拦截请求并在请求处理前后执行某些操作。尽管 Filter 和 Interceptor 都可以用来实现类似的功能,但是它们的应用场景和配置方式略有不同。

使用 Filter 设置 Session 的超时时间

Filter 是 Servlet 规范的一部分,可以直接在 Servlet 容器中使用。如果你想在 Filter 中设置 Session 的超时时间,可以通过以下步骤实现:

  1. 创建 Filter 类:首先创建一个实现了 javax.servlet.Filter 接口的类。
  2. 重写 doFilter 方法:在这个方法中,你可以获取 HttpSession 并设置其超时时间。
  3. 注册 Filter:在 web. Xml 中或者通过注解的方式注册你的 Filter。
示例代码
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebFilter(urlPatterns = {"/*"})
public class SessionTimeoutFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化方法,可以在这里进行一些初始化工作}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;// 获取 HttpSession 对象HttpSession session = httpRequest.getSession();// 设置 Session 的超时时间为 30 分钟(以秒为单位)int timeoutInSeconds = 30 * 60; // 30 minutessession.setMaxInactiveInterval(timeoutInSeconds);// 执行下一个 Filter 或者目标资源chain.doFilter(request, response);}@Overridepublic void destroy() {// 销毁方法,可以在这里进行一些清理工作}
}
使用 Interceptor 设置 Session 的超时时间

Interceptor 是特定框架(如 Spring MVC 或 Struts 2)提供的机制,用于拦截请求并在请求处理前后执行操作。如果你使用的是 Spring MVC,可以通过定义一个 HandlerInterceptor 来设置 Session 的超时时间。

示例代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class SessionTimeoutInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {// 获取 HttpSession 对象HttpSession session = request.getSession();// 设置 Session 的超时时间为 30 分钟(以秒为单位)int timeoutInSeconds = 30 * 60; // 30 minutessession.setMaxInactiveInterval(timeoutInSeconds);return true; // 返回 true 表示继续处理请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {// 在请求处理之后执行的操作}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {// 在请求完成之后执行的操作}
}
注册 Interceptor

要让 Interceptor 生效,还需要在 Spring MVC 的配置类中注册它:

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 WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SessionTimeoutInterceptor());}
}

Session 的销毁

情形一

Session 超时

情形二

调用 HttpSession 的 invalidate ()

情形三

会话式 session 保存 session-id 时,用户关闭浏览器

案例

![[Pasted image 20240929213640.png]]
login. jsp 文件如下

<%@ page contentType="text/html; charset=UTF-8"%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>  
<head>  
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">  
<title>Login</title>  
</head>  
<body>  <fieldset>    <legend>登录</legend>   
<!-- 表单数据的提交方式为POST -->  <form action="SessionDemoServlet" method="post">  <table cellpadding="2" align="center">  <tr>                <td align="right">用户名:</td>  <td>                    <!-- 1.文本输入框控件 -->  <input type="text" name="username" />      </td>  </tr>            <tr>                <td align="right">密码:</td>  <!-- 2.密码输入框控件 -->  <td><input type="password" name="password" /></td>  </tr>            <tr>                <td colspan="2"  align="center">  <!-- 3.提交按钮控件 -->  <input type="submit" value="登录" />    
<!-- 4.重置按钮控件,单击后会清空当前form -->  <input type="reset" value="重填" />      </td>  </tr>        </table>    </form>   </fieldset>
</body>  
</html>

welcome. jsp 如下

<%@ page contentType="text/html;charset=UTF-8"%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  
<title>Insert title here</title>  
</head>  
<body>  
欢迎<%= session.getAttribute("name") %>,登陆成功!  
<a href="LogoutServlet">退出</a>  
</body>  
</html>

SessionDemoServlet. java

import java.io.IOException;  
import java.io.PrintWriter;  import jakarta.servlet.ServletException;  
import jakarta.servlet.annotation.WebServlet;  
import jakarta.servlet.http.HttpServlet;  
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpServletResponse;  
import jakarta.servlet.http.HttpSession;  @WebServlet("/SessionDemoServlet")  
public class SessionDemoServlet extends HttpServlet{  protected void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException {  response.setContentType("text/html;charset = utf-8");  String userName = request.getParameter("username");  String password = request.getParameter("password");  if(userName.equals("芩离")&&password.equals("123456")) {//改成自己的!  HttpSession session = request.getSession();  session.setAttribute("name", userName);  response.sendRedirect("welcome.jsp");  }  else{  PrintWriter out = response.getWriter();  out.print("用户名或密码错误,返回<a href=\'login.jsp\'>登录</a>");response.setHeader("refresh","3;url = login.jsp");//失败后三秒跳转登录页}  }  protected void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {  super.doGet(request, response);  }  
}

LogoutServlet. java

import java.io.IOException;  import jakarta.servlet.ServletException;  
import jakarta.servlet.annotation.WebServlet;  
import jakarta.servlet.http.HttpServlet;  
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpServletResponse;  
import jakarta.servlet.http.HttpSession;  @WebServlet("/LogoutServlet")  
public class LogoutServlet extends HttpServlet{  @Override  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  HttpSession session = req.getSession();  session.removeAttribute("name");  session.invalidate();  resp.sendRedirect("login.jsp");  }  }

Token 详解

Token 是一种无状态的认证机制,通常用于 RESTful API。Token 通常是一个加密的字符串,包含了用户的身份信息和一些验证信息。

特点:

  1. 无状态:服务器不需要存储 Session 信息,每次请求都独立验证 Token。
  2. 安全性:Token 可以包含过期时间,减少被盗用的风险。
  3. 跨域:Token 可以跨域使用,适合分布式系统。
  4. 自定义:Token 的内容可以根据需要自定义。

常见类型:

  • JWT(JSON Web Token):一种开放标准(RFC 7519),用于在网络应用环境间安全地传递声明。
  • OAuth:一个行业标准的协议,允许用户提供一个令牌来访问他们存储在另外的服务提供者上的信息,而无需将他们的凭据提供给第三方应用。

用途:

  • API 认证:用于保护 RESTful API,确保请求者的身份。
  • 单点登录(SSO):允许用户使用一套凭证访问多个系统。
    image-20241001152705939

jwt 工具类及其使用

依赖

要想使用JWT令牌,需要先引入JWT的依赖:

<!-- JWT依赖-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

工具类

import io.jsonwebtoken.Claims;  
import io.jsonwebtoken.JwtBuilder;  
import io.jsonwebtoken.Jwts;  
import io.jsonwebtoken.SignatureAlgorithm;  
import java.nio.charset.StandardCharsets;  
import java.util.Date;  
import java.util.Map;  public class JwtUtil {  /**  * 生成jwt  * 使用Hs256算法, 私匙使用固定秘钥  *  * @param secretKey jwt秘钥  * @param ttlMillis jwt过期时间(毫秒)  * @param claims    设置的信息  * @return  */  public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {  // 指定签名的时候使用的签名算法,也就是header那部分  SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;  // 生成JWT的时间  long expMillis = System.currentTimeMillis() + ttlMillis;  Date exp = new Date(expMillis);  // 设置jwt的body  JwtBuilder builder = Jwts.builder()  // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的  .setClaims(claims)  // 设置签名使用的签名算法和签名使用的秘钥  .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))  // 设置过期时间  .setExpiration(exp);  return builder.compact();  }  /**  * Token解密  *  * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个  * @param token     加密后的token  * @return  */  public static Claims parseJWT(String secretKey, String token) {  // 得到DefaultJwtParser  Claims claims = Jwts.parser()  // 设置签名的秘钥  .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))  // 设置需要解析的jwt  .parseClaimsJws(token).getBody();  return claims;  }  
}

校验过滤器的注册

@Configuration  
@Slf4j  
public class WebMvcConfiguration extends WebMvcConfigurationSupport {  @Autowired  private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;   /**  * 注册自定义拦截器  *  * @param registry  */  protected void addInterceptors(InterceptorRegistry registry) {  log.info("开始注册自定义拦截器...");  registry.addInterceptor(jwtTokenAdminInterceptor)  .addPathPatterns("/admin/**")  .excludePathPatterns("/admin/employee/login");  }
}

令牌校验

import com.sky.constant.JwtClaimsConstant;  
import com.sky.context.BaseContext;  
import com.sky.properties.JwtProperties;  
import com.sky.utils.JwtUtil;  
import io.jsonwebtoken.Claims;  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  
import org.springframework.web.method.HandlerMethod;  
import org.springframework.web.servlet.HandlerInterceptor;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  /**  * jwt令牌校验的拦截器  */  
@Component  
@Slf4j  
public class JwtTokenAdminInterceptor implements HandlerInterceptor {  @Autowired  private JwtProperties jwtProperties;  /**  * 校验jwt  *     * @param request  * @param response  * @param handler  * @return  * @throws Exception  */    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  //判断当前拦截到的是Controller的方法还是其他资源  if (!(handler instanceof HandlerMethod)) {  //当前拦截到的不是动态方法,直接放行  return true;  }  //1、从请求头中获取令牌  String token = request.getHeader(jwtProperties.getAdminTokenName());  //2、校验令牌  try {  log.info("jwt校验:{}", token);  Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);  Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());  log.info("当前员工id:{}", empId);  BaseContext.setCurrentId(empId);  //3、通过,放行  return true;  } catch (Exception ex) {  //4、不通过,响应401状态码  response.setStatus(401);  return false;  }  }  
}

Controller层

@PostMapping("/login")@ApiOperation(value = "员工登录")public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {log.info("员工登录:{}", employeeLoginDTO);Employee employee = employeeService.login(employeeLoginDTO);//登录成功后,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.EMP_ID, employee.getId());String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder().id(employee.getId()).userName(employee.getUsername()).name(employee.getName()).token(token).build();return Result.success(employeeLoginVO);}

Service层

public Employee login(EmployeeLoginDTO employeeLoginDTO) {String username = employeeLoginDTO.getUsername();String password = employeeLoginDTO.getPassword();//1、根据用户名查询数据库中的数据Employee employee = employeeMapper.getByUsername(username);//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)if (employee == null) {//账号不存在throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);}//密码比对// 对前端明文密码进行md5加密,然后再进行比对password = DigestUtils.md5DigestAsHex(password.getBytes());//md5加密if (!password.equals(employee.getPassword())) {//密码错误throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);}if (Objects.equals(employee.getStatus(), StatusConstant.DISABLE)) {//账号被锁定throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);}//3、返回实体对象return employee;}

Mapper层

@Select("select * from employee where username = #{username}")Employee getByUsername(String username);

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

A. 2025--[炼石计划--NOIP模拟三]--T1--矩形

赛时草了个 \(O(n^4 \log (n))\) 竟然能过 70 分虽然本来就是这么分配的,发现正解只需将二分改为双指针就可以了,最气的是上面计算的时候用到还是尺取下面就用的二分(唐诗)。 其实这题就是暴力,然后在低级的暴力上加一些操作变得稍微高级一点。 计算的话直接暴力查找不同颜…

深度学习(UNet)

和FCN类似,UNet是另一个做语义分割的网络,网络从输入到输出中间呈一个U型而得名。 相比于FCN,UNet增加了更多的中间连接,能够更好处理不同尺度上的特征。 网络结构如下:下面代码是用UNet对VOC数据集做的语义分割。import torch import torch.nn as nn import torch.optim …

【防忘笔记】测试过程与技术

测试人员应该想些什么 我自己是做后端的,对于模棱两可的需求和莫名其妙的测试case是深恶痛绝的,所以有时候我就会想测试人员应该会需要注意什么?以他们的角度,他们更在乎什么 最近有机会了解相关的知识,遂整理记录一下,以便之后在工作中更好的理解发生的各种事情 以客户为…

论文总结1--基于深度强化学习的四足机器人步态分析--2024.10.01

四足机器人的运动控制方法研究 1.传统运动控制 - 基于模型的控制方法目前,在四足机器人研究领域内应用最广泛的控制方法就是基于模型的控制方法,其中主要包括基于虚拟模型控制(Virtual Model Control,VMC)方法 、基于零力矩点(Zero Moment Point,ZMP) 的控制方法、弹簧…

Linux系统密码忘记

Linux系统密码忘记 1.故障背景误删除或修改/etc/passwd导致无法远程登录. 禁止root远程登录,没有添加普通用户,无法远程登录. root密码忘记,无法远程登录. linux无法启动.2.解决方法 root密码,恢复有备份的系统文件,都要重启系统,才能进入救援模式.解决方案 应用场景系统自带的…

应用中的错误处理概述

title: 应用中的错误处理概述 date: 2024/10/1 updated: 2024/10/1 author: cmdragon excerpt: 摘要:本文介绍了Nuxt中的错误处理机制,包括全局错误处理器和组件层级错误捕获,以及错误传递规则和生产环境下的处理方式 categories:前端开发tags:错误处理 Nuxt应用 全局处理…

TypeScrip在vue中的使用----defineEmits

向父元素发送消息 之前的语法: 在TS语法中,我们既要对defineEmits做类型约束,又要对emits做类型约束。 最主要是对defineEmits做一个泛型的约束。//在泛型对象中,有几个事件就写几个约束 type emitsType = {//()中有n个参数,第一个固定的是e,其他有具体参数决定。具体的写…

电影《749局》迅雷BT下载/百度云下载资源[MP4/2.12GB/5.35GB]超清版

电影《749局》:近未来的冒险与成长之旅电影《749局》是一部融合了科幻、冒险与奇幻元素的电影,由陆川编剧并执导,王俊凯、苗苗、郑恺、任敏、辛柏青领衔主演,李晨特邀主演,张钧甯、李梦、杨皓宇特别主演。该片于2024年10月1日在中国大陆上映,以其独特的科幻设定、宏大的视…

电影《749局》迅雷百度云下载资源4K分享[1.16GB/2.72GBMKV]高清加长版【1280P已完结】

电影《749局》的深度剖析与全面解读电影《749局》是一部集科幻、冒险、动作与奇幻元素于一体的力作,由陆川编剧并执导,王俊凯、苗苗、郑恺、任敏、辛柏青领衔主演,李晨特邀主演,张钧甯、李梦、杨皓宇特别主演。影片于2024年国庆档在中国大陆上映,以其独特的科幻设定、宏大…

南沙C++信奥赛陈老师解一本通题 1983:【19CSPJ普及组】公交换乘

​【题目描述】著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案: 1、在搭乘一次地铁后可以获得一张优惠票,有效期为 4545 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。在有效期内指开始乘公交车的…

Flutter 实现骨架屏CE

什么是骨架屏 在客户端开发中,我们总是需要等待拿到服务端的响应后,再将内容呈现到页面上,那么在用户发起请求到客户端成功拿到响应的这段时间内,应该在屏幕上呈现点什么好呢? 答案是:骨架屏 那么什么是骨架屏呢,来问下 GPT:骨架屏(Skeleton Screen)是一种现代的用户…

[rCore学习笔记 028] Rust 中的动态内存分配

引言 想起我们之前在学习C的时候,总是提到malloc,总是提起,使用malloc现场申请的内存是属于堆,而直接定义的变量内存属于栈. 还记得当初学习STM32的时候CubeIDE要设置stack 和heap的大小. 但是我们要记得,这么好用的功能,实际上是操作系统在负重前行. 那么为了实现动态内存分配…