【SpringMVC】| 拦截器(含源码分析)

news2024/10/6 22:24:44

目录

拦截器

1.  拦截器的介绍

2. 拦截器的三个抽象方法

3. 拦截器的使用

4. 多个拦截器的执行顺序

Java核心技术大会

文末福利(Java核心技术卷) 


拦截器

拦截器能拦截请求,前面学习的过滤器也能拦截请求,那两者有什么区别呢?

过滤器:过滤器是过滤从浏览器发送的所有请求,所以过滤器就是作用在浏览器----》前端控制器DispatcherServlet之间

拦截器:前端控制器DispatcherServlet接收到请求后进行处理,去与Controller的RequestMapping请求映射进行匹配,所以拦截器就是作用在控制器Controller执行的前后

1.  拦截器的介绍

(1)SpringMVC中的拦截器用于拦截控制器方法的执行!

(2)SpringMVC中的拦截器需要实现HandlerInterceptor或者继承HandlerInterceptorAdapter!

(3)SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置。

拦截器的执行原理

preHandle():在请求被处理之前进行操作;预处理
postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果;后处理
afterCompletion:所有的请求响应结束后执行善后工作,清理对象、关闭资源 ;最终处理

拦截器实现的两种方式

继承HandlerInterceptorAdapter【处理程序拦截适配器】的父类。
实现HandlerInterceptor【处理程序拦截器】接口,推荐使用实现接口的方式,因为继承是单继承的。

2. 拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法:

(1)preHandle:控制器方法【controller】执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法。

(2)postHandle:控制器方法【controller】执行之后执行postHandle()。

(3)afterComplation:处理完视图和模型数据(ModelAndView),渲染视图完毕之后执行afterComplation()。

通过源码分析执行的顺序:首先通过前端控制器DispatcherServlet源码找到控制器方法的调用,返回的其实是一个mv(ModelAndView),在控制器方法之前执行preHandle()方法、在控制器方法之后执行postHandle()方法。 之后会去调用processDispatcherResult进行视图渲染;最后去调用afetrCompletion()方法!

processDispatcherResult处理ModelAndView,有一个render方法用来渲染视图的

渲染完视图,执行拦截器的最终处理

3. 拦截器的使用

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>springmvc-thymeleaf007</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springmvc-thymeleaf007 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring5</artifactId>
      <version>3.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.14.2</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>

</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--注册过滤器:解决post请求乱码问题-->
    <filter>
        <filter-name>encode</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--指定字符集-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <!--强制request使用字符集encoding-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--强制response使用字符集encoding-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <!--所有请求-->
    <filter-mapping>
        <filter-name>encode</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--发送put、delete请求方式的过滤器-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--注册SpringMVC框架-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置springMVC位置文件的位置和名称-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--将前端控制器DispatcherServlet的初始化时间提前到服务器启动时-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--指定拦截什么样的请求
            例如:http://localhost:8080/demo.action
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--配置包扫描-->
    <context:component-scan base-package="com.zl.controller"/>
    <!--视图控制器,需要搭配注解驱动使用-->
    <mvc:view-controller path="/" view-name="index"/>
    <!--专门处理ajax请求,ajax请求不需要视图解析器InternalResourceViewResolver-->
    <!--但是需要添加注解驱动,专门用来解析@ResponseBody注解的-->
    <!--注入date类型时,需要使用@DateTimeFormat注解,也要搭配这个使用-->
    <mvc:annotation-driven/>
    <!--开放对静态资源的访问,需要搭配注解驱动使用-->
    <mvc:default-servlet-handler/>

    <!-- 配置Thymeleaf视图解析器 -->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<a th:href="@{/testInterceptor}">测试</a>
</body>
</html>

success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
success
</body>
</html>

controller

注:此时实现的功能时通过访问index.xml,通过controller进行处理去访问success.html页面;但是此时有一个问题,如果我们知道了success.html的路径地址,就可以略过index.html直接进行访问!

package com.zl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {
    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        return "success";
    }
}

怎么解决这个问题呢?通过拦截器!

index.html提交表单

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<!--<a th:href="@{/testInterceptor}">测试</a>-->
<form th:action="@{/testInterceptor}">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="pwd"><br>
    <input type="submit" th:value="提交">
</form>
</body>
<h1 th:text="${msg}"></h1>
</html>

controller拿到数据,并放到session中去

package com.zl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;


@Controller
public class TestController {

    // 直接进行访问
    @RequestMapping("/success")
    public String success(){
        return "success";
    }

    @RequestMapping("/testInterceptor")
    public String testInterceptor(HttpServletRequest request,String username,String pwd){
        if ("root".equalsIgnoreCase(username) && "123".equalsIgnoreCase(pwd)){
            // 登录成功,存储用户名到session中去
            HttpSession session = request.getSession();
            session.setAttribute("username",username);
            return "success";
        }else {
            request.setAttribute("msg","账户或密码错误");
            return "index";
        }
    }
}

定义拦截器,进行拦截

package com.zl.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 拿到存进session中的username
        if(request.getSession().getAttribute("username") == null){
            // 表示没有登陆过,跳转到index.xml中去登录
            request.setAttribute("msg","请先去登录");
            request.getRequestDispatcher("/WEB-INF/templates/index.html").forward(request,response);
            return false;
        }
        // 表示登录过,放行
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

 在springmvc.xml中注册拦截器

注:拦截器主要放行两个页面,登录页面和登录验证的页面!

    <!--注册拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--映射要拦截的请求-->
            <mvc:mapping path="/**"/>
            <!--配置要放行的请求-->
            <mvc:exclude-mapping path="/"/><!--登录的页面-->
            <mvc:exclude-mapping path="/testInterceptor"/><!--登录验证的页面-->
            <!--配置具体的拦截器实现功能的类-->
            <bean class="com.zl.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

4. 多个拦截器的执行顺序

(1)若每个拦截器的preHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关preHandle()会按照配置的顺序执行,而postHandle()afterComplation()按照配置的反序执行

定义两个拦截器

FirstInterceptor

package com.zl.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor--->preHandle");
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor--->postHandle");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

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

SecondInterceptor

package com.zl.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor--->preHandle");
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondInterceptor--->postHandle");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

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

}

在springmvc.xml中注册拦截器 

    <!--注册拦截器,此时是对所有请求都拦截-->
    <mvc:interceptors>
        <!--方式一-->
        <bean class="com.zl.interceptor.FirstInterceptor"/>
        <!--方式二:拦截器类要写上Component注解,表示纳入Spring容器管理-->
        <ref bean="secondInterceptor"/>
    </mvc:interceptors>

执行结果如下:preHandle按照配置的顺序输出,而postHandle和afterComplation按照配置相反的顺序输出

源码分析: 

①首先在控制器controller方法上打一个断点

②进行访问时,会进入DispatcherServlet的方法栈,找到doDispatcher方法

ha实际就是HandlerAdapter适配器控制器,调用handle方法,就相当于执行控制器上的方法

③此时需要打四个断点:preHandle、执行控制器方法、postHandle、afterCompletion

执行流程:

(1)先执行前处理器preHandel,

(2)然后去执行控制器方法handle,此时就会去找控制器controller上面的方法去执行,

(3)执行后处理器方法postHandle,

(4)这些执行完毕后会调用processDispatcherResult方法中的render方法去渲染视图,渲染完毕后;最终会执行afterCimpletion方法!

跳转到preHandel 

// if中的参数是false,就会直接执行return结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

mappedHandler实际上是一个执行链,这个执行链存放的是:当前的控制器方法、和处理控制器方法的拦截器

注:此时我们可以看到有3个拦截器,我们只定义了2个,另一个实际上是SpringMVC自己创建的!

 

点开+号查看内部的结构如下:

主要包含三个部分:控制器方法拦截器集合拦截器的索引

进入到 applyPreHandle方法中进行源码分析:首先是遍历这个拦截器集合,并且是i++(就是按照配置的顺序执行)。

注:只要拦截器的preHandler全是true,那么当前的拦截器索引interceptorIndex就是当前最大的索引值;一旦出现了false,此时的拦截器索引interceptorIndex就是前一个拦截器的索引值!

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
                // 根据下标拿到每个拦截器
				HandlerInterceptor interceptor = interceptors[i];
                // 判断当前的拦截的preHandle是true还是false
				if (!interceptor.preHandle(request, response, this.handler)) {
                    // 是false就直接执行agterCompletion,然后结束
                    // 注:此时只能输出当前拦截器所有前面的拦截器的afterCimpletion方法
					triggerAfterCompletion(request, response, null);
					return false;
				}
                // 是true,就修改拦截器的索引下标 
				this.interceptorIndex = i;
			}
		}
		return true;
	}

跳转到postHandle

也是遍历拦截器集合,此时的i初始值也是当前的拦截器集合的个数相关联,但是是逆序(i--)打印的!

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

跳转到afterCompletion

也是遍历拦截器集合,此时的i开始值是与拦截器索引interceptorIndex相关联的,也是逆序(i--)打印的!所以对于preHandle是按照配置的顺序打印的;而postHandle和afterCompletion是逆序打印的!

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

(2)假如现在SecondInterceptor拦截器的preHandle()返回了falsepreHandle()返回false和它之前配置的拦截器的preHandle()都会执行postHandle()都不会执行返回false的拦截器之前的拦截器的afterComplation()会执行

再次查看preHandle的源码:

在for循环的if语句可以看出,当preHandle为false时才会去执行,此时并不会执行postHandle了,会执行afterCompletion,然后返回false直接结束当前方法!并且前面我们已经分析了afterCompletion遍历的结果是与拦截器索引interceptorIndex相关联,而这个值的大小又是当前拦截器为false时的前一个拦截器的索引值(相对于preHandle会少打印一个,少打印当前的)!

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				// preHandle为false要执行的语句
                if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

例如:当前有5个拦截器,one、two、three、four、five,此时three的preHandle返回了false;此时one、two、three的preHandle会执行、postHandle都不会执行、one、two的afterComplation会执行! 

Java核心技术大会

 

大会简介

人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的确受到了前所未有的挑战,出现了更多更强大的竞争者。

但是,迄今Java仍然有着非常庞大的开发者生态,仍是使用人数最多的编程语言,仍是服务端应用、大数据应用、企业级产品的首选。

本届技术大会由国内Java技术传播领军机构机械工业出版社华章分社发起,周志明、李三红、杨晓峰三位大会主席,与近30位国内外顶级专家将从Java语言、平台和趋势,Java应用开发和系统架构,以及Java性能优化等方面带来8大专场24场主题分享。2023年6月25日-7月1日,让我们相约「 Java核心技术大会 」

PART 1 特邀启动专场

PART 2 Java语言、平台和趋势专场

 

PART 3 Java应用开发专场

PART 4 Java应用与系统架构专场

PART 5 Java应用性能优化专场

PART 6 大数据与数据库专场

PART 7 云原生与Serverless专场

 

PART 8 AI驱动的Java编程专场

「Java核心技术大会 2023」

Core Java Week
2023年6月25日-7月1日
邀您相约
共同深入探讨 Java 生态!
直播预约:视频号“IT阅读排行榜

现场参与更有

  • 赢取Java核心技术 纸书&视频课
  • 带走CoreJava限量周边
  • 锁定购物袋超秒福利
  • 加入交流群,向专家请教、学习
  • 第一时间获取PPT等增值资源

在这里插入图片描述

 

文末福利(Java核心技术卷) 

《Java核心技术卷Ⅰ》和《Java核心技术卷Ⅱ》任选其一免费包邮送出!

本次送书 2 本! 
活动时间:截止到 2023-06-29 00:00:00

抽奖方式:利用程序进行抽奖。

参与方式:关注博主(只限粉丝福利哦)、点赞、收藏,评论区随机抽取,最多三条评论!

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

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

相关文章

【数据结构与算法C++实现】1、异或的用法

原视频为左程云的B站教学 文章目录 1 异或换值2 求出数组中唯一一个出现奇数次的数3 求出数组中的两个出现奇数次的数 异或&#xff1a; 相同为0&#xff0c;不同为1。 更好的记忆方式&#xff1a; 不进位相加 10010 ^ 01100--------11110性质 0 ^ N N&#xff0c;N ^ N 0…

广电用户画像分析之根据用户行为数据进行筛选与标签添加

在数据处理和分析领域&#xff0c;我们经常需要根据用户的行为数据进行筛选和标签添加&#xff0c;以便更好地理解用户行为和偏好。在本篇博客中&#xff0c;我们将介绍两个示例&#xff0c;展示如何根据用户的收视行为数据和订单信息进行数据处理和分析。 前情提要&#xff1…

创新型影像测量仪器有哪些

走新型工业化之路&#xff0c;加快重塑竞争新优势&#xff0c;离不开更强的创新能力、更高的创新效率。新型工业化道路的基本标志和落脚点是要做到“科技含量高、经济效益好、资源消耗低、环境污染少、人力资源优势得到充分发挥”&#xff0c;并实现这几方面的兼顾和统一。而不…

spring boot 项目实现打包依赖分离

spring boot version 2.7 &#xff08;理论上是通用的&#xff09;Maven version 3 打包结果 重要文件以及文件夹解释 lib: 存在当前项目的全部依赖 other&#xff1a;和当前项目的 groupID 不同的依赖 project&#xff1a;和当前项目groupID 相同的依赖 XX-3.0.0-SNAPSHOT.j…

jdk安装及配置

一、下载安装包&#xff1a; 阿里云盘分享 提取码&#xff1a;am66 双击该程序 点击下一步 稍作等待即可。 二、配置环境变量 再新建一个系统变量CLASSPATH .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 找到Path变量&#xff0c;双击编辑 Path变量。点击新建&…

【深度学习】GPT-2

在GPT1问世不久&#xff0c;和GPT很相似的BERT横空出世&#xff0c;并且在各方面都超越GPT-1。OpenAI在《Language Models are Unsupervised Multitask Learners》中于2019年提出的GPT-2&#xff0c;全称为Generative Pre-Training 2.0。提出语言模型式无监督的多任务学习 &…

DDS 信号发生器实验

目录 DDS 信号发生器实验 1、DDS 简介 2、实验任务 3、程序设计 3.1、DDS 顶层模块代码 3.2、clk_wiz IP 核 3.3、ILA IP 核&#xff08;集成逻辑分析器&#xff1a;Integrated Logic Analyzer&#xff0c;ILA&#xff09; 3.4、各波形参考代码 3.4.1、正弦信号波形采…

身份识别与访问管理(IAM)工具

AD360 是一款企业 IAM 解决方案&#xff0c;可帮助管理身份、保护访问并确保合规性。它具有强大的功能&#xff0c;例如自动化身份生命周期管理、安全 SSO、自适应 MFA、基于审批的工作流、UBA 驱动的身份威胁防护和历史审计报告。AD360 直观的界面和强大的功能使其成为满足现代…

行业云统领2023十大技术趋势,新华三把脉数实融合演进路径

“每一年的科技突破与环境变局&#xff0c;有一定的随机性又有一定的必然性&#xff0c;导致人类社会永远处于动态塑形的过程。”中国工程院院士陈晓红在想像未来的技术变化时认为&#xff1a;“无论怎么变化&#xff0c;人类未来图景仍然源于社会生活与经济发展的真实需求”。…

了解MySQL配置文件:位置、结构和选项

目录 1 MySQL配置文件的位置2 MySQL配置文件的结构3 MySQL配置选项4 [mysqld]部分&#xff1a;5 [client]部分&#xff1a;6 MySQL配置文件的重要性7 总结 本文详细介绍了MySQL配置文件的位置、结构和常用选项。了解如何使用MySQL配置文件来管理和配置MySQL服务器的行为和属性。…

5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界面的卡顿,…

React学习9 Router6

使用 userRoutes路由表 注册路由 Outlet指定路由组件呈现位置 ***很重要&#xff0c;userNavigate()实现编程式路由导航 函数式组件接收params参数的hook useParams() 接受search参数 接收state参数 userNavigate 实现前进后退 判断是否处于路由组件中&#xff0c;在路由器管理…

网站加密防止拷贝的php域名授权方法

1 public function getdata()2 $method DES-ECB;//加密方法3 $passwd qq496631085;//加密密钥4 $options 0;//数据格式选项&#xff08;可选&#xff09;5 $iv ;//加密初始化向量&#xff08;可选&#xff09;6 $url ba…

双因素身份验证在远程访问中的重要性

在快速发展的数字环境中&#xff0c;远程访问计算机和其他设备已成为企业运营的必要条件。无论是在家庭办公室运营的小型初创公司&#xff0c;还是团队分散在全球各地的跨国公司&#xff0c;远程访问解决方案都能保证工作效率和连接性&#xff0c;能够跨越距离和时间的阻碍。 …

MQTT(二)Java整合MQTT

Java整合MQTT 上一节知道MQTT是一个通信协议&#xff0c;需要一个代理服务Broker&#xff1b;通信设备作为客户端Client&#xff0c;后台系统服务器也作为客户端Client。 经过了解选用EMQX作为代理服务Broker&#xff08;支持WEB界面查看&#xff09; 后台服务使用Spring In…

【教学类-36-01】Midjounery生成的四张图片切片成四张小图

作品展示&#xff1a; 把一张正方形图片的四个等大小图切割成四张图片 背景需求 最近在学习ChatGPT的绘画&#xff08;midjounery AI艺术&#xff09; 我想给中班孩子找卡通动物图片&#xff08;黑白线条&#xff09;&#xff0c;打印下来&#xff0c;孩子们练习描边、涂色…

【发布】ChatGLM2-6B:性能大幅提升,8-32k上下文,推理提速42%

自3月14日发布以来&#xff0c; ChatGLM-6B 深受广大开发者喜爱&#xff0c;截至 6 月24日&#xff0c;来自 Huggingface 上的下载量已经超过 300w。 为了更进一步促进大模型开源社区的发展&#xff0c;我们再次升级 ChatGLM-6B&#xff0c;发布 ChatGLM2-6B 。 在主要评估LLM模…

《C++ Primer》--学习7

顺序容器 容器库概览 迭代器 与容器一样&#xff0c;迭代器有着公共的接口&#xff1a;如果一个迭代器提供某个操作&#xff0c;那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。 迭代器范围 一个迭代器范围是由一对迭代器表示&#xff0c;两个迭代器分别指向…

剪辑必备技巧:轻松去除视频中的多余物体

在视频剪辑过程中&#xff0c;有时我们需要去除视频中的多余物体&#xff0c;以提升视觉效果和观赏体验。今天将为您介绍一些实用的技巧&#xff0c;帮助您轻松去除视频中的多余物体&#xff0c;让您的剪辑作品更加精彩。 一、选择适当的剪辑软件进行剪辑操作 一些专业的剪辑…

基于MATLAB实现KECA、PCA和KPCA的多阶段发酵过程监测方法毕业设计(完整源码+说明文档+PPT+开题报告+数据)

文章目录&#xff0c;完整源码在文末 1. 研究目标2. 主要研究内容3. 技术路线4. 预期成果5. 功能说明6. 参考文献7. 完整仿真源码下载 1. 研究目标 实现基于KECA的青霉素发酵过程故障监测 2. 主要研究内容 1.针对KPCA监测算法在数据降维过程中簇结构信息丢失的问题&#xff…