五:Day11_SpringMVC03

news2024/11/29 2:33:42

一、拦截器

SpringMVC给出了拦截器来实现单元方法的拦截,拦截器的执行是在DispatcherServlet之后和单元方法之前的。

注意:只有URL匹配到了控制单元,拦截器才能生效。

2. 使用拦截器

2.1 创建拦截器类
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor.preHandle");
        return fasle;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor.postHandle");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor.afterCompletion");
    }
}
2.2 配置拦截器

拦截器是由DispatcherServlet接收到请求后来调用的,所有需要将拦截器配置为bean,并且配置其拦截范围。

 <!--配置注解扫描路径-->
        <context:component-scan base-package="com.bjsxt.controller"></context:component-scan>
    <!--配置拦截器-->
        <mvc:interceptors>
            <!--配置具体的拦截器的bean及其拦截范围-->
            <mvc:interceptor>
                <!--配置拦截的单元方法的访问路径,第一个/表示项目根目录--> 
                <mvc:mapping path="/myController/demo"/>
                <!--配置自定义拦截器的bean对象,只在当前mvc:interceptor内有效-->
                <bean class="com.bjsxt.interceptor.MyInterceptor"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

3. 拦截方法介绍

3.1 preHandle方法

作用:

执行拦截的方法preHandle(),返回false表示拦截此次请求,返回true表示放行。

执行时机:

单元方法执行之前。

参数:

HttpServletRequest request:此次拦截的请求的request对象。

HttpServletResponse response:此次拦截的请求的response对象。

Object handler:HandlerMethod类型,存储了拦截的单元方法的method对象。

返回值:

boolean类型,false表示拦截,true表示放行。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HandlerMethod hm=(HandlerMethod)handler;//强转为HandlerMethod类型
    Method method = hm.getMethod();//获取此次请求的单元方法的方法对象
    System.out.println(method.getName());
    System.out.println("MyInterceptor.preHandle");
    return false;
}
3.2 postHandle方法

作用:

执行拦截的方法postHandle(),可以对ModelAndView进行操作,Model数据进行校验,View操作等。

执行时机:

单元方法执行之后,视图解析器解析渲染视图之前。

参数:

HttpServletRequest request:此次拦截的请求的request对象。

HttpServletResponse response:此次拦截的请求的response对象。

Object handler:HandlerMethod类型,存储了拦截的单元方法的method对象。

ModelAndView:存储了model和view信息的对象。

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    //重置跳转的资源路径
    String viewName = modelAndView.getViewName();
    //modelAndView.setViewName("forward:/bb.jsp");
    //获取Model对象中存储的流转数据
    Map<String, Object> model = modelAndView.getModel();
    System.out.println("MyInterceptor.postHandle----"+viewName+"-----"+model.get("str"));
}
3.3 afterCompletion方法

作用:

执行拦截的方法afterCompletion(),无论是否出现异常都会执行,可以处理异常,清理资源等。

执行时机:

视图解析器解析渲染视图完成之后。

参数:

HttpServletRequest request:此次拦截的请求的request对象。

HttpServletResponse response:此次拦截的请求的response对象。

Object handler:HandlerMethod类型,存储了拦截的单元方法的method对象。

Exception:存储异常信息的对象,如果没有异常信息则默认为null。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  System.out.println("MyInterceptor.afterCompletion");
}

自定义拦截器,拦截器SpringMVC提供的,只拦截控制单元。

拦截控制单元:

1.执行控制单元之前 执行拦截器preHandle方法。对请求进行相关的处理。

2.执行控制单元之后 执行拦截器postHandle方法。对应modelandview进行相关操作。

3.向客户端完成响应 执行拦截器afterCompletion方法。进行相关结尾的操作,无论是否出现异常都会执行。

public class MyInterceptor01 implements HandlerInterceptor {
  // 执行控制单元之前  执行
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("preHandle 执行了 111");
      //false,不放行     true,放行
      return true;
  }
​
  // 控制单元执行完成后 执行
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      System.out.println("postHandle 执行了 111");
  }
  /*  
* 没有使用@ResponseBody注解:渲染完页面后执行
* 使用了@ResponseBody注解:不再需要渲染页面。postHandle 执行后 执行 afterCompletion
*
* 页面中内容响应完成后执行 afterCompletion
* */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion 执行了 111");
}
}
3.4 拦截器执行顺序总结

4. 拦截配置说明

拦截器类创建好后需要在springmvc.xml文件中配置拦截器的bean以及其拦截范围。

 <!--
    配置拦截器
        作用:
            让声明的拦截器类生效完成单元方法请求的拦截
        使用:
            在springmvc.xml文件中使用<mvc:interceptors>标签声明拦截的配置信息
            在<mvc:interceptors>标签下使用子标签完成拦截器的配置
                全局拦截
                     在<mvc:interceptors>直接声明bean标签配置拦截器的bean,拦截所有的单元方法请求。
                局部拦截
                    在<mvc:interceptors>标签下使用子标签<mvc:interceptor>来声明局部拦截
                    在<mvc:interceptor>标签下使用子标签配置拦截返回以及拦截器的bean
                        <mvc:mapping path="/demo"/> 要拦截的范围,可以声明多个
                        <bean id="mm" class="com.bjsxt.inter.MyInter"></bean> 拦截器
-->
<!--配置拦截器-->
<mvc:interceptors>
    <!--配置拦截器的bean对象,拦截所有的单元方法-->
        <bean class="com.bjsxt.interceptor.MyInterceptor2"></bean>
    <!--配置具体的拦截器的bean极其拦截范围,可以配置多个-->
    <mvc:interceptor>
        <mvc:mapping path="/myController/demo"/><!--配置拦截的单元方法的访问路径,第一个/表示项目根目录,可以多个-->
        <mvc:mapping path="/myController/kk/*"/><!--支持*通配符表示任意个数的任意字符,**表示路径及子路径-->
        <bean class="com.bjsxt.interceptor.MyInterceptor"></bean><!--配置拦截器的bean对象,只在当前mvc:interceptor内有效-->
    </mvc:interceptor>
</mvc:interceptors>

5. 拦截器栈

拦截器栈指多个拦截器。当一个控制单元被多个拦截器拦截时,就形成了拦截器栈。拦截器栈中拦截器有着严格的执行顺序。执行顺序按照配置顺序执行。先配置的优先级更高。

例如:拦截器A和拦截器B,优先级更高指以控制单元(demo)为核心,前面的方法优先级高的先执行,后面的方法优先级高的后执行。

preHandle1 -> preHandle2 -> demo -> postHandle2 -> postHandle1 -> afterCompletion2 -> afterCompletion1。

配置拦截器栈分为局部配置和全局配置。全

全局配置:

<mvc:interceptors>
    <bean class="com.bjsxt.inteceptor.MyInteceptor"></bean>
    <bean class="com.bjsxt.inteceptor.MyInteceptor2"></bean>
</mvc:interceptors>



局部配置:

因为在<mvc:interceptor>中只能有一个<bean>,所有如果希望使用局部方式配置拦截器栈,需要配置多个<mvc:interceptor>标签。

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/show2"/>
        <bean class="com.bjsxt.inteceptor.MyInteceptor2"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/show2"/>
        <bean class="com.bjsxt.inteceptor.MyInteceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

6. 拦截器和过滤器的区别(面试题)

  1. 来源不同

    拦截器是SpringMVC中的技术,过滤器是Java EE中的技术。

  2. 生效位置不同

    拦截器是进入DispatcherServlet后才能执行,过滤器是进入到Servlet容器后就可以触发。

  3. 目标不同

    拦截器拦截的目标是HandlerMethod(控制单元,控制器方法),过滤器可以过滤所有的URL。

  4. 运行机制不同

    拦截器是在HandlerMethod执行前后和视图处理完成后执行,分为三部分。过滤器只能在目标资源前后执行。

  5. 接口中方法类型不同

    拦截器中的方法都是default方法,可以重写也可以不重写。过滤器中的方法都是abstract方法,如果当前类不是抽象类,必须重写。

  6. 上下文不同

    拦截器被Spring MVC管理,可以获取到Spring容器中内容。Filter被Tomcat管理,所以无法获取Spring容器内容。

    1.过滤器(Filter):由JavaEE提供的过滤器. 请求到达资源(servlet,页面,css,js,img,...)之前都要经过过滤器,资源响应回到客户端之前经过过滤器。

    2.拦截器(Interceptor):由SpringMVC提供的拦截器. 请求到到控制单元之前经过拦截器(preHandle),控制单元执行完成后经过拦截器(postHandle),向页面响应完成,经过拦截器(afterCompletion)。

二、跨域

1. 跨域介绍

项目和项目之前访问的网址或ip:port称为域(domain)。

跨域:当前项目的协议、ip、端口和访问的URL的协议、IP、端口中有一个不同,这种访问就叫跨域。

例如:当前项目http://localhost:8080 访问了 http://127.0.0.1:8080 就是跨域访问。

2. 什么时候有跨域

跨域只发生在Ajax请求中。

Ajax研发之初为了保证安全性,设置默认情况下不允许跨域访问。

3. 跨域的支持

浏览器为了保证Ajax默认不允许跨域实现,浏览器中都有一个同源策略。

同源策略:当使用ajax请求时,不允许跨域访问。只能访问当前域的资源。

4. 解决跨域的方式

解决跨域的方法有很多,常见的解决方案:

  • jsonp : Spring 4的支持。

  • 设置响应头:Spring 5支持。只需要在允许被跨域访问的方法上面添加@CrossOrigin注解即可。

5. @CrossOrigin解释说明

只要在控制单元方法上添加了@CrossOrigin注解后,会在响应头中添加Access-Control-Allow-Origin:*。

Access-Control-Allow-Origin是HTTP协议中允许哪些IP的项目跨域访问,*表示所有IP。

等效于在响应头中直接添加允许跨域参数:

@RequestMapping("/demo")
@ResponseBody
public String demo(HttpServletResponse response){
    response.setHeader("Access-Control-Allow-Origin","*");
    return "hello";
}

为了简单直接使用@CrossOrigin注解:

@RequestMapping("/demo")
@ResponseBody
@CrossOrigin
public String demo(){
    return "hello";
}

三、Spring MVC异常处理

1. 介绍

在Spring MVC支持异常处理。不会呈现给用户500界面。而是当出现异常时交给某个特定的控制器。

如果是一个上线的项目,呈现了500界面,会非常影响用户体验度。同时也显示公司实力有问题、不专业。

2. 局部配置

配置在@Controller的控制器类中,只有当前这个控制器类的控制单元出现异常时才能执行,其他类的控制单元出现异常不能执行。

每个控制器类中可以有多个处理异常的方法。每个方法上面只需要有@ExceptionHandler,千万别添加了@RequestMapping注解。

@Controller
public class DemoController {
    @RequestMapping("/demo")
    @ResponseBody
    public String demo2(){
        Object obj = null;
        obj.toString();
        return "demo2";
    }

    @ExceptionHandler(value = ArithmeticException.class)
    public String myexception(){
        System.out.println("Demo-1");
        return "forward:/exception.jsp";
    }

    @ExceptionHandler(value = Exception.class)
    public String myexception2(){
        System.out.println("Demo-2");
        return "forward:/exception2.jsp";
    }
}

3. 全局配置

因为@ControllerAdvice已经继承了@Component注解,所以类上只添加这个注解就可以了。

不需要在添加@Controller注解了。

小提示:

如果配置了局部异常处理器和全局异常处理器,优先匹配局部异常处理器。

@ControllerAdvice
public class MyExceptionController {
    @ExceptionHandler(value = ArithmeticException.class)
    public String myexception(){
        System.out.println("MyException-1");
        return "forward:/exception.jsp";
    }
    @ExceptionHandler(value = Exception.class)
    public String myexception2(){
        System.out.println("MyException-2");
        return "forward:/exception2.jsp";
    }
}

4. 使用配置文件配置

在Spring MVC中包含HandlerExceptionResolver组件,专门负责处理异常的。接口中只包含一个resolveException方法。

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.NullPointerException">/error1.jsp</prop>
            <prop key="java.lang.Exception">/error2.jsp</prop>
        </props>
    </property>
</bean>

四、Spring MVC数据校验

1. 数据校验介绍

  • 数据校验分为客户端数据校验和服务端数据校验。常用在登录、注册功能中。
  • 数据校验是软件开发过程中必不可少的一个环节。一个项目只有客户端数据校验是不严谨的,为了防止不法人员直接通过URL或HTTP工具非法访问服务端,发送非法数据,保险起见,服务端也应该具有数据校验,这种客户端和服务端都有数据校验时,称为双重校验
  • 客户端数据校验直接使用客户端脚本校验即可。例如在B/S模型项目中,可以选择使用JavaScript或jQuery进行客户端数据校验。
  • 服务端数据校验根据使用的技术完成校验。如果是Servlet技术可以自己编写校验逻辑,所有的校验过程都是通过正则表达式、等值判断等进行校验。而在Spring MVC中数据校验包含两种:(1)基于注解方式 。 (2)自定义校验类的方式。

2. 基于注解方式

2.1 JSR介绍

JCP(Java Community Process)是一个开发的国际组织,里面包含了一些Java开发者和其他被允许加入的成员。JCP组织主要负责对Java社区进行发展和更新。维护的规范包含:J2ME、J2SE、J2EE、XML等相关规范。组织成员可以提交JSR(Java Specification Requests,Java 规范提案),待组织成员通过提案后会把相关内容加入到下一个版本的规范中。

2.2 JSR 303介绍

JSR 303是Java EE 6规范的子规范。叫做Bean Validation。这些规范都是注解

在Java开发中使用的最多的JSR 303具体实现就是Hibernate框架中Hibernate-Validator。它对JSR 303的所有约定(constraint)都做了实现,同时还进行了一定的扩充。

2.3 Hibernate Validator包含的内容

Hibernate Validator对JSR实现都存在于Validation-api.jar的javax.validation.constraints包中。

里面所有注解都包含message属性,表示校验不通过后日志打印的信息。

Hibernate Validator对JSR 303具体实现的解释:

注解含义
@AssertFalse类型必须是布尔,取值必须为false
@AssertTrue类型必须是布尔,取值必须为true
@DecimalMax("3")最大值为3,value属性是String类型
@DecimalMin("1")最小值为1,value属性是String类型
@Digits(integer = 10,fraction = 3)integer:整数位最大长度,fraction小数位最大长度
@Email必须是邮箱地址。只要中间包含@,且@前后都具有超过1位的字符就能通过校验。字符可以是数字字母下划线
@Future类型必须是时间类型,允许为null,如果设置值必须是一个将来的时间
@FutureOrPresent类型必须是时间类型,允许为null,如果设置值必须是一个将来或现在的时间(精确到秒)
@Max(5)最大值为5,value属性是long类型
@Min(1)最小值为1,value属性是long类型
@Negative必须是负数,对数据类型没有要求
@NegativeOrZero必须是负数或零,对数据类型没有要求
@NotBlank用在String类型。不能是空白(null和"")
@NotEmpty用在String类型。不能是空白(null和"")
@NotNull不能为null,可以是""。可以用在所有类型中。对于八大基本数据类型来说,永远不为null
@Null必须为Null。可以用在所有类型中。对于八大基本数据类型来说,永远不可能为null
@Past类型必须是时间类型,必须是一个过去的时间。精确到秒
@PastOrPresent类型必须是时间类型,必须是一个过去的时间或现在的时间。精确到秒
@Pattern(regexp = "\w{1,6}")必须满足正则表达式。regexp是必有属性
@Positive必须是正数,对数据类型没有要求
@PositiveOrZero必须是正数或零,对数据类型没有要求
@Size(min = 1,max = 10)用在String类型。个数必须在1和10之间

Hibernate-Validator额外补充,这些注解都在Hibernate-validator.jar的org.hibernate.validator.constraints包中。

注解含义
@Length(min = 1,max = 10)用在String类型。长度需要在1和10之间
@Range(min = 1,max = 10)数据类型没有要求。取值范围需要在1和10之间
@URL(port = 8080,host = "127.0.0.1",protocol = "https")需要是一个合法的URL。默认情况下只要是以http:开头即可。可以通过port限制端口、host限制主机名、protocol限制协议
2.4 注解方式的具体实现
2.4.1 添加依赖

除了项目正常的依赖以外,额外需要导入Hibernate-validator依赖。

注意:对于Tomcat8插件来说,最高支持到6.1.x版本,对于更高的6.2.x或7.x版本是不支持的。导入后启动会报异常。如果希望使用更高版本的依赖,可以使用更高版本Tomcat(本机Tomcat)。

对于Tomcat8插件正确的依赖导入示范:

如果导入过其他版本的Hibernate-Validator,一定要先停止Tomcat8插件,再clean一下。否则即使导入的是下面版本,也会报上面的异常。

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.7.Final</version>
</dependency>
2.4.2 在实体类属性上添加注解

示例中只是以NotNull和Length进行举例。

(1)@NotNull中message是可选属性,如果设置了message,在违反规则后日志会打印message中内容。

(2)@Length是设置字符串长度。

所以name必须不能是null的,且长度是2-6位。

注解放在实体类的属性上面,每个实体类属性都支持配置多个注解,这些注解同时生效。

public class People {
    @NotNull(message = "姓名不能是null")
    @Length(min = 2,max = 6,message = "长度应该是2-6位")
    private String name;
    private String age;
    // 省略Getter和Setter
}
2.4.3 编写控制单元

控制单元中必须添加@Valid注解,否则校验不生效。

@RequestMapping("/valid")
public String testValid(@Valid People peo){
    System.out.println(peo);
    return "/abc.jsp";
}

如果配置了日志文件,需要将日志级别设置为WARN。

五、Spring MVC中包含哪些组件

        组件是将处理某类问题的代码进行封装的整体模块。一个大的问题可以拆分为不同的小问题,解决每个小问题的代码封装可以称之为组件,但是组件又是无法独立运行的,必须结合其他组件一起才能最终解决问题。

        SpringMVC将Servlet访问的流程整体封装了起来,浏览器发起请求后调用单元方法来处理请求,这个整个过程从接收到请求,到找到单元方法并调用执行,再到响应结果给浏览器都是由不同的组件协同来实现的,有如下组件:

不同的组件在整个运行过程中的具体表现其实就是不同的对象,也就是不同对象之间的相互调用完成了请求的处理,组件的初始化应该在请求来之前就完成的,当服务器启动的时候会先完成对DispactherServlet的初始化创建,在DispatcherServlet被初始化的时候其底层内部也会完成第2到第10个组件的初始化,调用其initStrategies方法来完成。 

 protected void initStrategies(ApplicationContext context) {
    this.initMultipartResolver(context);
    this.initLocaleResolver(context);
    this.initThemeResolver(context);
    this.initHandlerMappings(context);
    this.initHandlerAdapters(context);
    this.initHandlerExceptionResolvers(context);
    this.initRequestToViewNameTranslator(context);
    this.initViewResolvers(context);
    this.initFlashMapManager(context);
}

2.常用组件说明

DispatcherServlet:前端控制器。Spring MVC的入口,也是整个流程控制中心。其他组件由DispatcherServlet统一调度,降低了组件和组件之间的耦合度。

MultipartResovler:多部分处理器。文件上传时需要使用。

LocaleResolver:解决客户端的区域和时区问题。

ThemeResolver:主题解析器。提供自定义布局。

HandlerMapping: 映射处理器。主要负责处理URL,并找到对应的HandlerMethod。简单说就是找@RequestMapping注解中映射路径是否有和URL匹配的。

HandlerAdapter:适配器。负责调用具体的HandlerMethod。

HandlerExceptionResovler:异常处理器。异常处理,根据不同异常返回视图。

RequestToViewNameTranslator:从请求中获取到视图名称。

ViewResovler:视图解析器,负责解析字符串视图名和物理视图文件的。

FlashMapManager:主要用于存储属性的,本质是一个Map。多用在重定向时。FlashMap在重定向之前存储,重定向之后删除。

ModelAndView:模型和视图。Spring MVC中提供的模型和视图接口。

HandlerInterceptor:拦截器。拦截控制器资源的。

六、SpringMVC运行原理(常见面试题)

  1. 客户端向服务端发起请求,Spring MVC总体入口中央调度器DispatcherServlet进行请求分发。

  2. 中央调度器DispatcherServlet把URL交给映射处理器HandlerMapping进行解析URL。

  3. 映射处理器HandlerMapping将请求映射为HandlerExecutionChain处理器执行链

    1. 可以为多个处理器拦截器HandlerInterceptor

    2. 处理器Handler对象(处理Controller)。

  4. 将处理器执行链HandlerExecutionChain返回到中央调度器DispatcherServlet。

  5. DispatcherServlet根据返回的处理器执行链HandlerExecutionChain获得的处理器Handler,根据处理器Handler选择处理器适配器HandlerAdapter。

    1. 执行拦截器的preHandle()方法。调用具体的Handler处理器(处理Controller),在填充Handler的入参过程中会执行数据转换、数据格式化、数据验证,调用具体的Controller完成处理功能,并创建ModelAndView对象。

    2. 执行拦截器的postHandle()方法。

  6. 将ModelAndView对象返回到处理器适配器HandlerAdapter。

  7. 处理器适配器HandlerAdapter将ModelAndView对象返回到中央调度器DispatcherServlet。

  8. 中央调度器DispatcherServlet调用视图解析器ViewResolver解析视图。

  9. 将解析的视图View对象返回到中央调度器DispatcherServlet。

  10. 渲染视图,将视图返回到中央调度器DispatcherServlet,执行拦截器afterCompletion()方法。

  11. 中央调度器DispatcherServlet相应回到浏览器。

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

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

相关文章

S5PV210(十):LCD

本文主要探讨210的LCD相关知识。 LCD LCD称液晶(透光背光呈色),可在电信号驱动下使液晶分子旋转,呈现不同的颜色(被动发光) lcd接口为TTL接口(5V为1&#xff0c;0V为0),不能传输太远,远距离传输方式:SoC(TTL) ->VGA-> LCD(TTL) 其他显设备:CRT(…

Java基础篇 | 多线程详解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

【数据结构】深入浅出讲解计数排序【图文详解,搞懂计数排序这一篇就够了】

计数排序 前言一、计数排序算法核心思路映射 概念补充绝对映射相对映射 二、计数排序算法核心实现步骤三、码源详解四、效率分析&#xff08;1&#xff09;时间复杂度 — O&#xff08;Max&#xff08;N&#xff0c;range&#xff09;&#xff09;&#xff08;2&#xff09;空间…

74HC138逻辑芯片

文章目录 74系列逻辑芯片——74HC138基础信息描述特征应用范围 功能信息封装引脚基本电路 扩展性能分析 74系列逻辑芯片——74HC138 基础信息 描述 74HC138器件设计用于需要极短传播延迟时间的高性能存储器解码或数据路由应用&#xff1b;在高性能存储系统中&#xff0c;可使用…

【C语言】扫雷游戏的一步一步的实现

文章目录 一、扫雷游戏分析和设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析1.2.2 ⽂件结构设计 二、扫雷游戏代码实现总结 一、扫雷游戏分析和设计 1.1 扫雷游戏的功能说明 • 使⽤控制台实现经典的扫雷游戏 • 游戏可以通过菜单实现继续玩或者退出游…

时序分解 | Matlab实现EMD经验模态分解时间序列信号分解

时序分解 | Matlab实现EMD经验模态分解时间序列信号分解 目录 时序分解 | Matlab实现EMD经验模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现EMD经验模态分解时间序列信号分解 Matlab语言 算法新颖小众&#xff0c;用的人很少&#xf…

面试10000次依然会问的【ReentrantLock】,你还不会?

引言 在并发编程的世界中&#xff0c;ReentrantLock扮演着至关重要的角色。它是一个实现了重入特性的互斥锁&#xff0c;提供了比synchronized关键字更加灵活的锁定机制。ReentrantLock属于java.util.concurrent.locks包&#xff0c;是Java并发API的一部分。 与传统的synchro…

如何使用CodeceptJS、Playwright和GitHub Actions构建端到端测试流水线

介绍 端到端测试是软件开发的一个重要方面&#xff0c;因为它确保系统的所有组件都能正确运行。CodeceptJS是一个高效且强大的端到端自动化框架&#xff0c;与Playwright 结合使用时&#xff0c;它成为自动化Web、移动甚至桌面 (Electron.js) 应用程序比较好用的工具。 在本文中…

2023-11 | 短视频批量下载/爬取某个用户的所有视频 | Python

这里以鞠婧祎的个人主页为demo https://www.douyin.com/user/MS4wLjABAAAACV5Em110SiusElwKlIpUd-MRSi8rBYyg0NfpPrqZmykHY8wLPQ8O4pv3wPL6A-oz 【2023-11-4 23:02:52 星期六】可能后面随着XX的调整, 方法不再适用, 请注意 找到接口 找到https://www.douyin.com/aweme/v1/web/…

rust入门基础案例:猜数字游戏

案例出处是《Rust权威指南》&#xff0c;书中有更加详细的解释。从这个例子中&#xff0c;我们可以了解到 rust 的两个操作&#xff1a; 如何从控制台读取用户输入rust 如何生成随机数 代码格式化 编译器可在保存时对代码做格式化处理&#xff0c;底层调用 rustfmt 来实现&a…

【gpt redis】原理篇

用的黑马程序员redis课程的目录&#xff0c;但是不想听讲了。后续都是用gpt文档获取的。 1.课程介绍(Av766995956,P145) 2.Redis数据结构-动态字符串(Av766995956,P146) sds 1M是个界限 其实他是个由c语言实现的结构体 有这么几个参数 len alloc flag char[] len是实际长度 …

【漏洞复现】Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 1.5、深度利用1、反弹Shell 说明内容漏洞编号CVE-2017-5645漏洞名称Log4j Server …

Python 中的 Gzip 解压

我们将介绍Python中的gzip解压。 我们还将介绍如何使用 gzip 解压缩来解压缩压缩内容。 Python 中的 Gzip 解压 Python 中构建了许多用于压缩和解压缩目的的库&#xff0c;但我们将介绍 Gzip 库。 它是一种流行的数据压缩工具。 我们可以使用 gzip 通过将数据编码为人类无法读…

字符型液晶显示器LCD 1602的显示控制(Keil+Proteus)

前言 趁机把LCD 1602的实验完成了&#xff0c;那个电路图有几个地方没弄懂&#xff0c;但是去掉也没有报错&#xff0c;就没管了。 LCD1602_百度百科 (baidu.com)https://baike.baidu.com/item/LCD1602/6014393?frge_ala LCD1602液晶显示屏通过电压来改变填充在两块平行板之…

Python算法例5 x的n次幂

1. 问题描述 实现函数Pow&#xff08;x&#xff0c;n&#xff09;&#xff0c;计算并返回x的n次幂。 2. 问题示例 Pow&#xff08;2.1&#xff0c;2&#xff09;4.41&#xff1b;Pow&#xff08;0&#xff0c;1&#xff09;0&#xff1b;Pow&#xff08;1&#xff0c;0&…

C++——类和对象之运算符重载

运算符重载 本章思维导图&#xff1a; 注&#xff1a;本章思维导图对应的xmind文件和.png文件都已同步导入至”资源“ 文章目录 运算符重载[toc] 1. 运算符重载的意义2. 函数的声明2.1 声明运算符重载的注意事项 3. 函数的调用4. const成员函数4.1 const成员函数的声明4.2 注意…

C++查漏补缺与新标准(C++20,C++17,C++11)02 C++快速回顾(二)

本内容参考C20高级编程 C风格的数组 //形如 int myArray[3]{2};一个比较新颖的获取C风格数组大小的函数std::size()&#xff0c;返回size_t类型&#xff08;在中定义的无符号整数&#xff09; #include <iostream> using namespace std;int main() {int myArray[5] {…

UML---用例图

UML–用例图 0.用例图简介 用例图是一种UML&#xff08;统一建模语言&#xff09;的图形化表示方法&#xff0c;用于描述系统的功能和行为。它可以帮助系统分析师和开发人员理解系统的需求&#xff0c;用例图由参与者、用例和它们之间的关系组成。 1.用例图的组成部分 系统…

【RabbitMQ】RabbitMQ 消息的可靠性 —— 生产者和消费者消息的确认,消息的持久化以及消费失败的重试机制

文章目录 前言&#xff1a;消息的可靠性问题一、生产者消息的确认1.1 生产者确认机制1.2 实现生产者消息的确认1.3 验证生产者消息的确认 二、消息的持久化2.1 演示消息的丢失2.2 声明持久化的交换机和队列2.3 发送持久化的消息 三、消费者消息的确认3.1 配置消费者消息确认3.2…

订单业务和系统设计(一)

一、背景简介 订单其实很常见&#xff0c;在电商购物、外卖点餐、手机话费充值等生活场景中&#xff0c;都能见到它的影子。那么&#xff0c;一笔订单的交易过程是什么样子的呢&#xff1f;文章尝试从订单业务架构和产品功能流程&#xff0c;描述对订单的理解。 二、订单业务…