【JavaWeb】登录校验-会话技术(三)过滤器Filter与拦截器Interceptor、异常处理

过滤器Filter

什么是Filter?

  • Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一。
  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
    • 使用了过滤器之后,要想访问web服务器上的资源,必须先经过滤器,过滤器处理完毕之后,才可以访问对应的资源。
  • 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

image-20230112120955145.png

Filter快速入门案例

Filter过滤器的基本使用操作:

  1. 定义过滤器 :定义一个类,实现 Filter 接口,并重写其所有方法。
  2. 配置过滤器: Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持。

定义过滤器

//定义一个类,实现一个标准的Filter过滤器的接口
public class DemoFilter implements Filter {	//导入jakarta包@Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Override //拦截到请求之后调用, 调用多次public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("Demo 拦截到了请求...放行前逻辑");//放行chain.doFilter(request,response);}@Override //销毁方法, 只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}
  • init方法:过滤器的初始化方法。在web服务器启动的时候会自动的创建Filter过滤器对象,在创建过滤器对象的时候会自动调用init初始化方法,这个方法只会被调用一次
  • doFilter方法:这个方法是在每一次拦截到请求之后都会被调用,所以这个方法是会被调用多次的,每拦截到一次请求就会调用一次doFilter()方法。
  • destroy方法: 是销毁的方法。当我们关闭服务器的时候,它会自动的调用销毁方法destroy,而这个销毁方法也只会被调用一次

配置过滤器
定义完Filter之后,Filter其实并不会生效,还需要完成Filter的配置:

  1. 在Filter类上添加一个注解:@WebFilter,并指定属性urlPatterns,通过这个属性指定过滤器要拦截哪些请求。
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {@Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Override //拦截到请求之后调用, 调用多次public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("Demo 拦截到了请求...放行前逻辑");//放行chain.doFilter(request,response);}@Override //销毁方法, 只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}
  1. 在启动类上面加上一个注解@ServletComponentScan,来开启SpringBoot项目对于Servlet组件的支持。
@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {public static void main(String[] args) {SpringApplication.run(TliasWebManagementApplication.class, args);}}

注意事项:

  • 在过滤器Filter中,如果不执行放行操作,将无法访问后面的资源。
  • 放行操作:chain.doFilter(request, response);

Filter详解

主要介绍以下3个方面的细节:

  1. 过滤器的执行流程。
  2. 过滤器的拦截路径配置。
  3. 过滤器链。
执行流程

image-20230106222559935.png

  • 过滤器当中我们拦截到了请求之后,如果希望继续访问后面的web资源,就要执行放行操作,放行就是调用 FilterChain对象当中的doFilter()方法。、
  • 在调用doFilter()这个方法之前所编写的代码属于放行之前的逻辑。
  • 在放行后访问完 web 资源之后还会回到过滤器当中,回到过滤器之后如有需求还可以执行放行之后的逻辑,放行之后的逻辑我们写在doFilter()这行代码之后。
@WebFilter(urlPatterns = "/*") 
public class DemoFilter implements Filter {@Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("DemoFilter   放行前逻辑.....");//放行请求filterChain.doFilter(servletRequest,servletResponse);System.out.println("DemoFilter   放行后逻辑.....");}@Override //销毁方法, 只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}

image-20230106224322625.png

拦截路径

Filter可以根据需求,配置不同的拦截资源路径:

拦截路径urlPatterns值含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/emps/*访问/emps下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截
过滤器链

过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链。
image-20230107084730393.png
比如:在我们web服务器当中,定义了两个过滤器,这两个过滤器就形成了一个过滤器链。

  • 这个链上的过滤器在执行的时候会一个一个的执行,会先执行第一个Filter,放行之后再来执行第二个Filter,如果执行到了最后一个过滤器放行之后,才会访问对应的web资源。
  • 访问完web资源之后,按照我们刚才所介绍的过滤器的执行流程,还会回到过滤器当中来执行过滤器放行后的逻辑,而在执行放行后的逻辑的时候,顺序是反着的。
  • 先要执行过滤器2放行之后的逻辑,再来执行过滤器1放行之后的逻辑,最后在给浏览器响应数据。

以上就是当我们在web应用当中配置了多个过滤器,形成了这样一个过滤器链以及过滤器链的执行顺序。

注意事项:

  • 以注解方式配置的Filter过滤器,它的执行优先级是按过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。
  • 假如我们想让某个过滤器先执行,就需要修改类名

登录校验-Filter

登录校验的基本流程:

  • 访问登录接口login,登录成功之后在服务端生成一个JWT令牌,并且把JWT令牌返回给前端,前端将JWT令牌存储下来。
  • 在后续的每一次请求当中,都会将JWT令牌携带到服务端,请求到达服务端之后,要想去访问对应的业务功能,此时必须先要校验令牌的有效性。
  • 使用过滤器校验令牌的有效性:
    • 无效:响应错误信息,禁止放行;
    • 存在且有效:放行,访问对应web资源。

思考:

  1. 所有的请求,拦截到了之后,都需要校验令牌吗?
    • 答案:登录请求例外
  2. 拦截到请求后,什么情况下才可以放行,执行业务操作?
    • 答案:有令牌,且令牌校验通过(合法);否则都返回未登录错误结果

image-20230112122130564.png

具体操作流程:

  1. 获取请求url
  2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
  3. 获取请求头中的令牌(token)
  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
  5. 解析token,如果解析失败,返回错误结果(未登录)
  6. 放行

代码实现:
登录校验过滤器:LoginCheckFilter

@Slf4j
@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {//前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;//1.获取请求urlString url = request.getRequestURL().toString();log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("/login")){chain.doFilter(request, response);//放行请求return;//结束当前方法的执行}//3.获取请求头中的令牌(token)String token = request.getHeader("token");log.info("从请求头中获取的令牌:{}",token);//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)if(!StringUtils.hasLength(token)){log.info("Token不存在");Result responseResult = Result.error("NOT_LOGIN");//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json = JSONObject.toJSONString(responseResult);response.setContentType("application/json;charset=utf-8");//响应response.getWriter().write(json);return;}//5.解析token,如果解析失败,返回错误结果(未登录)try {JwtUtils.parseJWT(token);}catch (Exception e){log.info("令牌解析失败!");Result responseResult = Result.error("NOT_LOGIN");//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json = JSONObject.toJSONString(responseResult);response.setContentType("application/json;charset=utf-8");//响应response.getWriter().write(json);return;}//6.放行chain.doFilter(request, response);}
}

在上述过滤器的功能实现中,我们使用到了一个第三方json处理的工具包fastjson。我们要想使用,需要引入如下依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version>
</dependency>

拦截器Interceptor

拦截器Interceptor快速入门案例

什么是拦截器?

  • 是一种动态拦截方法调用的机制,类似于过滤器。
  • 拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。

拦截器的作用:

  • 拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。

在拦截器当中,我们通常也是做一些通用性的操作,比如:我们可以通过拦截器来拦截前端发起的请求,将登录校验的逻辑全部编写在拦截器当中。

拦截器的使用步骤和过滤器类似,也分为两步:

  1. 定义拦截器
  2. 注册配置拦截器

自定义拦截器:实现HandlerInterceptor接口,并重写其所有方法

//自定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {//目标资源方法执行前执行。 返回true:放行    返回false:不放行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle .... ");return true; //true表示放行}//目标资源方法执行后执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ... ");}//视图渲染完毕后执行,最后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion .... ");}
}

注意:

  • preHandle方法:目标资源方法执行前执行。 返回true:放行 返回false:不放行
  • postHandle方法:目标资源方法执行后执行
  • afterCompletion方法:视图渲染完毕后执行,最后执行

注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法

@Configuration  //声明为Spring的配置类
public class WebConfig implements WebMvcConfigurer {//自定义的拦截器对象@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)}
}

Interceptor详解

拦截器的使用细节我们主要介绍两个部分:

  1. 拦截器的拦截路径配置
  2. 拦截器的执行流程
拦截路径
  • 在注册配置拦截器的时候,我们要指定拦截器的拦截路径。
  • 在配置拦截器时,不仅可以指定要拦截哪些资源,还可以指定不拦截哪些资源。
    • 通过addPathPatterns("要拦截路径")方法,指定要拦截哪些资源。
    • 通过excludePathPatterns("不拦截路径")方法,指定哪些资源不需要拦截
@Configuration  
public class WebConfig implements WebMvcConfigurer {//拦截器对象@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表示拦截所有请求).excludePathPatterns("/login");//设置不拦截的请求路径}
}

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

拦截路径含义举例
/*一级路径能匹配/depts/emps/login,不能匹配 /depts/1
/**任意级路径能匹配/depts/depts/1/depts/1/2
/depts/*/depts下的一级路径能匹配/depts/1,不能匹配/depts/1/2/depts
/depts/**/depts下的任意级路径能匹配/depts/depts/1/depts/1/2,不能匹配/emps/1
执行流程

image-20230107112136151.png

  • 当我们打开浏览器来访问部署在web服务器当中的web应用时,此时我们所定义的过滤器会拦截到这次请求。拦截到这次请求之后,它会先执行放行前的逻辑,然后再执行放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的 controller 当中的接口方法。
  • Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。
  • 当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行preHandle()方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回 true,就表示放行本次操作,才会继续访问controller中的方法;如果返回 false,则不会放行(controller中的方法也不会执行)。
  • 在controller当中的方法执行完毕之后,再回过来执行postHandle()这个方法以及afterCompletion() 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。

接下来我们就来演示下过滤器和拦截器同时存在的执行流程

  • 开启LoginCheckInterceptor拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle .... ");return true; //true表示放行}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ... ");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion .... ");}
}
@Configuration  
public class WebConfig implements WebMvcConfigurer {//拦截器对象@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**")//拦截所有请求.excludePathPatterns("/login");//不拦截登录请求}
}
  • 开启DemoFilter过滤器
@WebFilter(urlPatterns = "/*") 
public class DemoFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("DemoFilter   放行前逻辑.....");//放行请求filterChain.doFilter(servletRequest,servletResponse);System.out.println("DemoFilter   放行后逻辑.....");}
}

重启SpringBoot服务后,清空日志,打开Postman,测试查询部门:
image-20230107113653871.png
image-20230107114008004.png

以上就是拦截器的执行流程。通过执行流程分析,大家应该已经清楚了过滤器和拦截器之间的区别,其实它们之间的区别主要是两点:

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
  • 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

登录校验- Interceptor

和登录校验Filter过滤器当中的逻辑是完全一致的。现在我们只需要把这个技术方案由原来的过滤器换成拦截器interceptor就可以了。

登录校验拦截器
因为我们要在Controller方法运行之前执行校验操作,因此我们要在preHandle中编写代码。

//自定义拦截器
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {//目标资源方法执行前执行。 返回true:放行    返回false:不放行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)/*HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;此处我们不再需要强转,因为方法已经将HttpServletRequest和HttpServletResponse作为参数传进来了。*///1.获取请求urlString url = request.getRequestURL().toString();log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("/login")){log.info("登录操作,放行");return true;}//3.获取请求头中的令牌(token)String token = request.getHeader("token");log.info("从请求头中获取的令牌:{}",token);//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)if(!StringUtils.hasLength(token)){log.info("Token不存在");Result responseResult = Result.error("NOT_LOGIN");//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json = JSONObject.toJSONString(responseResult);response.setContentType("application/json;charset=utf-8");//响应response.getWriter().write(json);return false;}//5.解析token,如果解析失败,返回错误结果(未登录)try {JwtUtils.parseJWT(token);}catch (Exception e){log.info("令牌解析失败!");Result responseResult = Result.error("NOT_LOGIN");//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json = JSONObject.toJSONString(responseResult);response.setContentType("application/json;charset=utf-8");//响应response.getWriter().write(json);return false;}//6.放行return true;}//目标资源方法执行后执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ... ");}//视图渲染完毕后执行,最后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion .... ");}
}

注册配置拦截器

@Configuration  
public class WebConfig implements WebMvcConfigurer {//拦截器对象@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");}
}

异常处理

当前问题

image-20230107121909087.png
当我们没有做任何的异常处理时,我们三层架构处理异常的方案:

  • Mapper接口在操作数据库的时候出错了,此时异常会往上抛(谁调用Mapper就抛给谁),会抛给service。
  • service 中也存在异常了,会抛给controller。
  • 而在controller当中,我们也没有做任何的异常处理,所以最终异常会再往上抛。最终抛给框架之后,框架就会返回一个JSON格式的数据,里面封装的就是错误的信息,但是框架返回的JSON格式的数据并不符合我们的开发规范。

解决方案

那么在三层构架项目中,出现了异常,该如何处理?

  • 方案一:在所有Controller的所有方法中进行try…catch处理
    • 缺点:代码臃肿(不推荐)
  • 方案二:全局异常处理器
    • 好处:简单、优雅(推荐)

image-20230107122904214.png

全局异常处理器

如何定义全局异常处理器:

  1. 定义一个类,在类上加上一个注解@RestControllerAdvice,加上这个注解就代表我们定义了一个全局异常处理器。
  2. 在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解@ExceptionHandler。通过@ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。
@RestControllerAdvice
public class GlobalExceptionHandler {//处理异常@ExceptionHandler(Exception.class) //指定能够处理的异常类型public Result ex(Exception e){e.printStackTrace();//打印堆栈中的异常信息//捕获到异常之后,响应一个标准的Resultreturn Result.error("对不起,操作失败,请联系管理员");}
}

@RestControllerAdvice = @ControllerAdvice + @ResponseBody
处理异常的方法返回值会转换为json后再响应给前端

以上就是全局异常处理器的使用,主要涉及到两个注解:

  • @RestControllerAdvice //表示当前类为全局异常处理器
  • @ExceptionHandler //指定可以捕获哪种类型的异常进行处理

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

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

相关文章

在线PS新功能:一键抠图轻松搞定

Photoshop&#xff0c;设计界的巨头软件&#xff0c;是多少设计小白入门的噩梦。Photoshop下载难度大&#xff0c;Photoshop收费贵&#xff0c;PS暂存盘已满&#xff0c;PS操作难度大...为了减少设计师被Photoshop压制&#xff0c;设计工具市场不断升级发展&#xff0c;即时设计…

大连网站制作需要注意哪些问题

在制作大连网站时&#xff0c;需要注意以下几个问题&#xff1a; 1. 目标受众&#xff1a;首先要明确网站的目标受众是谁&#xff0c;根据受众的特点和需求来设计网站的内容和结构。比如&#xff0c;如果目标受众是年轻人&#xff0c;网站的设计风格可以更加时尚和前卫&#xf…

昇思MindSpore学习笔记6-05计算机视觉--SSD目标检测

摘要&#xff1a; 记录MindSpore AI框架使用SSD目标检测算法对图像内容识别的过程、步骤和方法。包括环境准备、下载数据集、数据采样、数据集加载和预处理、构建模型、损失函数、模型训练、模型评估等。 一、概念 1.模型简介 SSD目标检测算法 Single Shot MultiBox Detecto…

Java的数学学习系统-计算机毕业设计源码 56236

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.1.1技术可行性 2.1.2经济可行性 2.1.3操作可行性 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 …

前端javascript中的排序算法之冒泡排序

冒泡排序&#xff08;Bubble Sort&#xff09;基本思想&#xff1a; 经过多次迭代&#xff0c;通过相邻元素之间的比较与交换&#xff0c;使值较小的元素逐步从后面移到前面&#xff0c;值较大的元素从前面移到后面。 大数据往上冒泡&#xff0c;小数据往下沉&#xff0c;也就是…

【企业级监控】源码部署Zabbix与监控主机

Zabbix企业级分布式监控 文章目录 Zabbix企业级分布式监控资源列表基础环境一、LNMP环境搭建&#xff08;在zbx主机上&#xff09;1.1、配置Yum仓库1.1.1、下载阿里云的仓库文件1.2.2、安装PHP7的仓库1.2.3、生成Mariadb10.11的仓库文件1.2.4、快速重建Yum缓存 1.2、安装PHP7.4…

Python函数语法详解(与C++对比学习)

一、Python函数的形式 def function_name (参数, ...) -> return value_type:# 函数体return value# 看具体需求# 如果没有return语句&#xff0c;函数执行完毕后也会返回结果# 只是结果为None。return None可以简写为return 二、函数名 这里可以与C中进行类比&#xff0c…

强化学习总结(有具体代码实现)

文章目录 第一部分 强化学习基础第1章 强化学习概述1.1 强化学习概念1.2 强化学习的环境1.3 强化学习的目标1.4 强化学习的数据 第2章 多臂老虎机问题&#xff08;MAB问题&#xff09;2.1 问题描述2.1.1 问题定义2.1.2 形式化描述2.1.3 累积懊悔2.1.4 估计期望奖励 2.2 解决方法…

windows10 +VS2019环境下的PCL安装和配置

今天想做点云重建&#xff0c;千篇一律&#xff0c;PCL少不了。一路跑下来觉得PCL的安装和环境配置还挺麻烦的&#xff0c;比OpenCV真的麻烦很多&#xff0c;有点不想写详细安装和配置过程了&#xff0c;偷个懒&#xff0c;就转载一下大佬的文章吧&#xff0c;下面的博主们已经…

PostgreSQL 中如何处理数据的并发更新冲突解决?

文章目录 一、并发更新冲突的场景二、PostgreSQL 中的并发控制机制&#xff08;一&#xff09; 封锁机制&#xff08;二&#xff09; 事务隔离级别 三、并发更新冲突的解决方法&#xff08;一&#xff09; 重试机制&#xff08;二&#xff09; 使用乐观并发控制&#xff08;三&…

用这款免费爬虫神器,不用手动撸代码了!

很多人学习Python和我说是为了“爬虫”&#xff0c;爬虫的用处确实很丰富&#xff0c;如&#xff1a; 市场研究&#xff0c;了解竞争对手信息&#xff0c;爬虫收集舆论信息、产品动态。 价格分析&#xff0c;通过抓取不同平台商品价格&#xff0c;监测价格波动&#xff0c;…

PDManer使用教程及安装包

以下安装包版本比较低&#xff0c;用习惯了&#xff0c;需要高版本可以去官网下载 链接&#xff1a;https://pan.baidu.com/s/1Hj4zJ0UCcdk0YQTlteVCTQ?pwdv72v 提取码&#xff1a;v72v 使用教程 连接数据库 导入表信息 创建关系图 第一步 第二步 如果列显示不全 &#x…

【LLM大模型】机器学习导论(西瓜书)[推荐阅读]

哈喽啊大家&#xff0c;今天又来给大家推荐一本机器学习方面的书籍<机器学习西瓜书>。本书作为该领域的入门教材&#xff0c;在内容上尽可能涵盖机器学习基础知识的各方面。 为了使尽可能多的读者通过本书对机器学习有所了解&#xff0c;作者试图尽可能少地使用数学知识…

【内网渗透】MSF渗透阶段的常用指令笔记

目录 渗透阶段划分 msfvenom 常用参数 各平台生成payload命令 Meterpreter Meterpreter的常用命令 基本命令 常用命令 针对安卓手机的一些命令 针对Windows的一些命令 文件系统命令 生成木马反弹shell(以linux靶机为例) 木马生成 配置监控 攻击利用 辅助模块 怎…

QT TCP多线程网络通信

学习目标&#xff1a; TCP网络通信编程 学习前置环境 运行环境:qt creator 4.12 QT TCP网络通信编程-CSDN博客 Qt 线程 QThread类详解-CSDN博客 学习内容 使用多线程技术实现服务端计数器 核心代码 客户端 客户端&#xff1a;负责连接服务端&#xff0c;每次连接次数1。…

从零开始做题:MP3

题目 给出一个mp3文件 解题 右键->selection->save selection->另存为xxx.png即可 8750d5109208213f E:\逐鹿\MISC\tools\MP3Stego_1_1_19\MP3Stego>.\decode -X cipher.mp3 MP3StegoEncoder 1.1.19 See README file for copyright info Input file cipher.mp3…

秒懂设计模式--学习笔记(8)【结构型-组合模式】

目录 7、组合模式7.1 组合模式&#xff08;Composite&#xff09;7.2 叉树结构7.3 文件系统7.4 目录树展示7.5 自相似性的涌现7.6 组合模式的各角色定义7.7 组合 7、组合模式 7.1 组合模式&#xff08;Composite&#xff09; 是针对由多个节点对象&#xff08;部分&#xff0…

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…

Thread类的start()方法和run()方法的区别

在Java多线程编程中&#xff0c;Thread类是一个非常重要的类&#xff0c;它提供了创建和管理线程的能力。对于初学者来说&#xff0c;理解Thread类的start()方法和run()方法之间的区别尤为重要。本文将深入探讨这两者之间的不同&#xff0c;帮助读者更好地掌握Java多线程编程的…

web端的vscode编辑器

下载code-server到本地 略 参考 https://blog.csdn.net/kfashfasf/article/details/137110668 运行code-server 到用户目录下设置 vim ~/.config/code-server/config.yaml . bind-addr: 0.0.0.0:8080 auth: password password: xxxxxx cert: false运行 [centosamazon22 ~…