Spring MVC学习 | 注解配置Spring MVC总结

news2024/9/23 19:26:32

文章目录

  • 一、注解配置Spring MVC
    • 1.1 初始化类
    • 1.2 Spring MVC配置类
    • 1.3 完整配置过程
  • 二、总结
    • 2.1 常用组件
    • 2.2 执行流程


学习视频🎥:https://www.bilibili.com/video/BV1Ry4y1574R

一、注解配置Spring MVC

1.1 初始化类

🔑注解配置的原理

  • 在servlet3.0之后的环境中,服务器(或者说容器)会在类路径(src目录下)中查询javax.servlet.ServletContainerInitializer接口的实现类,如果找到该实现类就用他来配置服务器
  • 而Spring中就提供了ServletContainerInitializer接口的一个实现类——SpringServletContainerInitializer,该实现类中又会查询WebApplicationInitializer接口的实现类,在Spring3.2之后,对WebApplicationInitializer创建了一个便利的基础实现类——AbstractAnnotationConfigDispatcherServletInitializer,因此我们创建的初始化配置类WebInit只需继承AbstractAnnotationConfigDispatcherServletInitializer并重写其方法,此时服务器会自动查找到我们创建的初始化类WebInit,然后用它来配置服务器

🔑初始化类需要重写的几个方法

方法方法返回值类型解释
getRootConfigClasses()Class<?>[]指定Spring配置类;将Spring配置类的class对象添加到Class数组中返回即可;可以指定多个Spring配置类,也可以不指定(因为方法的默认返回值是长度为0的数组)
getServletConfigClasses()Class<?>[]指定Spring MVC配置类;将Spring MVC配置类的class对象添加到Class数组中返回即可;同样可以指定多个Spring MVC配置类
getServletMappigs()String[]指定前端控制器DispatcherServlet的映射规则(资源路径);将资源路径添加到String数组中返回即可;相当于web.xml中<url-pattern>标签的作用,可以设置多个资源路径
getServletFilters()Filter[]配置过滤器;将过滤器类的class对象添加到Class数组中返回即可,过滤器的class在数组中位置决定了过滤器的配置顺序;也可以配置多个过滤器

❓ 关于Spring配置类

  • 在Spring的学习中,可以创建一个类,类上添加@Configuration@ComponnetScan等注解,将类标识为配置类,然后在类中通过@Bean注解添加其他配置,用于代替Spring的配置文件,Spring MVC配置类与之类似
  • 在Spring MVC中添加Spring配置类属于SSM整合部分,这里只是简单创建一个被@Configuration标识的类作为Spring配置类,不添加其他功能实现;或者不添加也可以

1.2 Spring MVC配置类

💬概述:Spring MVC配置类命名为WebConfig,用于代替Spring MVC的核心配置文件——springmvc.xml,springmvc.xml中配置过的功能就是WebConfig类中需要实现的功能

🔑WebConfig的具体实现

💡 前5个必须配置,后面的选择配置

  • 将WebConfig标识为配置类:在类上添加@Conguration注解

  • 开启组件扫描:在WebConfig配置类上添加@ComponnetScan注解,注解的basePackages属性中添加需要扫描的包或类(basePackages是数组,可以添加多个扫描包或类)

  • 开启注解驱动:在WebConfig类上添加@EnableWebMvc注解,表示开启注解驱动的意思,无需添加属性

  • 开放对静态资源的访问(配置默认servlet):在springmvc.xml中开放对静态资源的访问使用的是<mvc:default-servlet-handler>标签,不是简单的<bean>标签,所以在配置类中实现该功能需要先实现WebMvcConfigurer接口,然后实现接口的configureDefaultServletHandling()方法,在方法中直接通过形参configurer调用enable()方法即可

    /**
     * 1. 开放对静态资源的访问(配置默认servlet)
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    
  • 配置thymeleaf视图解析器(了解):在springmvc.xml文件配置thymeleaf时需要添加两个属性内部Bean,所以在配置类配置thymeleaf需要先创建出两个内部Bean,然后给thymeleafView视图解析器的属性赋值

    /**
     * 2.1 配置模板解析器
     */
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = 
            ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
            webApplicationContext.getServletContext());
    
        // 设置视图前缀
        templateResolver.setPrefix("/WEB-INF/templates/");
        // 设置视图后缀
        templateResolver.setSuffix(".html");
        // 设置编码方式
        templateResolver.setCharacterEncoding("UTF-8");
        // 设置模板
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }
    
    /**
     * 2.2 配置模板引擎,并为模板引擎注入模板解析器属性
     */
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }
    
    /**
     * 2.3 配置thymeleaf视图解析器,并为解析器注入模板引擎属性
     */
    @Bean
    public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
        // 先创建一个thymeleaf视图解析器对象
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    
        // 设置编码方式
        viewResolver.setCharacterEncoding("utf-8");
    
        // 注入模板引擎属性
        viewResolver.setTemplateEngine(templateEngine);
    
        return viewResolver;
    }
    
  • 配置拦截器:与开放对静态资源的访问类似,在springmvc.xml文件中配置拦截器使用的同样是mvc名称空间中的标签<mvc:interceptors>,所以配置拦截器同样需要实现WebMvcConfigurer接口,然后实现addInterceptors()方法,配置拦截器需要创建拦截器对象以及设置拦截路径

    • 创建拦截器对象:先创建好拦截器类TestInterceptor,然后在方法中直接new一个拦截器类对象即可

    • 设置拦截路径:调用形参registryaddInterceptor()方法,并将拦截器对象TestInterceptor传入,然后addInterceptor()方法后通过addPathPatterns()方法设置拦截路径

  • 配置异常处理器

    • 配置异常处理器有两种方式

      ① 异常处理器在springmvc.xml中是通过<bean>标签配置的,所以在配置类中需要使用@Bean标识对应方法即可,然后在方法中直接new一个异常处理器对象(即SimpleMappingExceptionResolver类型的对象)
      ② 异常处理器的配置还有另外一种方法——实现WebMvcConfigurer接口的方法configureHandlerExceptionResolvers()或者extendedHandlerExceptionResolvers(),同样需要在方法中new一个SimpleMappingExceptionResolver类型的对象,该方法的形参就是一个异常处理器集合resolvers,通过异常处理器对象对属性赋值后,最后将该对象添加到resolvers集合中,由此可见,该方法可以配置多个异常处理器

    • 配置异常处理器时需要实现的两个功能,即给异常处理器对象的两个属性(exceptionMappingsexceptionAttribute)赋值

      ① 创建异常与视图名的映射关系:先创建一个Properties类型的对象prop,然后通过prop对象调用setProperty()方法,将异常对应的全类名与视图名建立映射关系(形成键值对),然后调用异常处理器对象中exceptionMappings属性对应的set方法,即setExceptionMappongs(),将prop传入即可

      ❓ 关于Properties类:Properties类继承Hashtable类,而Hashtable类实现了Map接口,所以Properties类也是通过键值对的形式对数据进行存储,一般用于操作.properties文件(也是键值对形式存储数据)

      ② 设置request域中异常信息的数据名(键):直接调用exceptionAttribute属性对应的set方法——setExceptionAttribute()方法给属性赋值即可,属性值就对应request域中异常信息的键

    /**
     * 4. 方式一配置异常处理器
     */
    @Bean
    public SimpleMappingExceptionResolver getExResolver() {
        // 创建异常处理器对象
        SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
        // 创建一个Properties对象,用于建立异常与视图名的映射关系
        Properties prop = new Properties();
    
        // 将数学异常与视图名error进行绑定
        prop.setProperty("java.lang.ArithmeticException", "error");
    
        // 给异常处理器的exceptionMappings属性赋值
        exResolver.setExceptionMappings(prop);
    
        // 给exceptionAttribute赋值,设置request域中异常信息的键
        exResolver.setExceptionAttribute("ex");
    
        return exResolver;
    }
    
    /*+---------------------------------------------------------------------------------+*/
    
    /**
     * 4. 方式二配置异常处理器
     */
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        // 创建异常处理器对象
        SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
        // 创建一个Properties对象,用于建立异常与视图名的映射关系
        Properties prop = new Properties();
    
        // 将数学异常与视图名error进行绑定
        prop.setProperty("java.lang.ArithmeticException", "error");
    
        // 给异常处理器的exceptionMappings属性赋值
        exResolver.setExceptionMappings(prop);
    
        // 给exceptionAttribute赋值,设置request域中异常信息的键
        exResolver.setExceptionAttribute("ex");
    
        resolvers.add(exResolver);
    }
    
  • 使用视图控制器:视图控制器同样需要实现WebMvcConfigurer接口的方法addViewControllers(),方法中直接通过形参registry调用方法addViewController()设置请求路径,然后在addViewController()方法后直接调用setViewName()方法设置请求路径对应的视图名

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 首页
        registry.addViewController("/").setViewName("index");
    }
    

1.3 完整配置过程

  1. 先删掉web.xml配置文件和springmvc.xml核心配置文件

  2. 创建出初始化类WebInit

    public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        /**
         * 指定Spring配置类
         * @return 返回Class数组,数组元素为配置类的class对象
         */
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    
        /**
         * 指定Spring MVC配置类
         * @return 返回Class数组,数组元素为配置类的class对象
         */
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{WebConfig.class};
        }
    
        /**
         * 指定DispatcherServlet的映射规则,即资源路径
         * @return 返回资源路径的字符串数组
         */
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        /**
         * 配置过滤器
         * @return 返回过滤器数组
         */
        @Override
        protected Filter[] getServletFilters() {
            // 1. 创建字符集过滤器CharacterEncodingFilter
            CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
            // 1.1 设置encoding属性为utf-8
            encodingFilter.setEncoding("utf-8");
    
            // 2. 创建请求方式过滤器
            HiddenHttpMethodFilter httpMethodFilter = new HiddenHttpMethodFilter();
    
            // 3. 创建过滤器数组并返回
            return new Filter[]{encodingFilter, httpMethodFilter};
        }
    }
    
  3. 创建Spring配置类SpringConfig(这里只是简单的创建,并无具体实现)

    @Configuration
    public class SpringConfig {
        
        // coding..
    }
    
  4. 创建Spring MVC配置类WebConfig

    @Configuration
    @ComponentScan(basePackages = "com.key.mvc")
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
    
        /**
         * 1. 开放对静态资源的访问(配置默认servlet)
         */
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    
        /* 2. 配置thymeleaf视图解析器 */
    
        /**
         * 2.1 配置模板解析器
         */
        @Bean
        public ITemplateResolver templateResolver() {
            WebApplicationContext webApplicationContext = 
                ContextLoader.getCurrentWebApplicationContext();
            // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
            ServletContextTemplateResolver templateResolver = 
                new ServletContextTemplateResolver(webApplicationContext.getServletContext());
    
            // 设置视图前缀
            templateResolver.setPrefix("/WEB-INF/templates/");
            // 设置视图后缀
            templateResolver.setSuffix(".html");
            // 设置编码方式
            templateResolver.setCharacterEncoding("UTF-8");
            // 设置模板
            templateResolver.setTemplateMode(TemplateMode.HTML);
            return templateResolver;
        }
    
        /**
         * 2.2 配置模板引擎,并为模板引擎注入模板解析器属性
         */
        @Bean
        public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver);
            return templateEngine;
        }
    
        /**
         * 2.3 配置thymeleaf视图解析器,并为解析器注入模板引擎属性
         */
        @Bean
        public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
            // 先创建一个thymeleaf视图解析器对象
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    
            // 设置编码方式
            viewResolver.setCharacterEncoding("utf-8");
    
            // 注入模板引擎属性
            viewResolver.setTemplateEngine(templateEngine);
    
            return viewResolver;
        }
    
        /**
         * 3. 配置拦截器
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 创建拦截器对象
            TestInterceptor testInterceptor = new TestInterceptor();
    
            // 添加拦截器对象,并设置拦截路径
            registry.addInterceptor(testInterceptor).addPathPatterns("/**");
        }
    
        /**
         * 4. 配置异常处理器
         */
        @Bean
        public SimpleMappingExceptionResolver getExResolver() {
            // 创建异常处理器对象
            SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
            // 创建一个Properties对象,用于建立异常与视图名的映射关系
            Properties prop = new Properties();
    
            // 将数学异常与视图名error进行绑定
            prop.setProperty("java.lang.ArithmeticException", "error");
    
            // 给异常处理器的exceptionMappings属性赋值
            exResolver.setExceptionMappings(prop);
    
            // 给exceptionAttribute赋值,设置request域中异常信息的键
            exResolver.setExceptionAttribute("ex");
    
            return exResolver;
        }
    
    
        /**
         * 5. 配置视图控制器
         */
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            // 首页
            registry.addViewController("/").setViewName("index");
            // 用户测试页面
            registry.addViewController("/testUser").setViewName("test-user");
            // 测试成功页面
            registry.addViewController("/success").setViewName("success");
            // 测试报文信息转换页面
            registry.addViewController("/testHttpMsg").setViewName("test-httpMsg");
        }
    }
    
  5. 对xml文件测试过的功能进行再测试一次:异常处理、拦截器、报文信息转换、域对象共享数据等


二、总结

2.1 常用组件

常用组件组件的实现和使用作用
前端控制器(中心控制器) DispatcherServlet由框架提供类型,开发人员只需在配置文件或配置类进行配置对请求和相应进行统一处理,是整个控制层的中心,调用其他组件对请求进行处理
处理器映射器 HandlerMapping直接由框架提供,无需创建和配置根据请求路径、请求方式等信息查找对应的处理器Handler,即控制器方法,然后获取控制器方法中所有相关对象(包括控制器对象及其对应的拦截器对象等),最后返回一个HandlerExecutionChain对象(处理执行链)
处理器 Handler直接由框架提供,无需创建和配置相当于控制器方法,对用户的请求做具体的处理,并将视图名交给视图解析器
处理器适配器 HandlerAdapter直接由框架提供,无需创建和配置执行Handler(控制器方法),并返回一个ModelAndView对象
视图解析器 ViewResolver/ThymeleafView由框架或其他依赖jar包提供类型,开发人员只需在配置文件或配置类进行配置根据视图名对视图进行解析,返回解析后的视图对象
视图 View框架提供视图类View,开发人员只需设置视图名将视图数据展示到页面

2.2 执行流程

📚常见八股文:Spring MVC执行流程

🔑文字描述

  1. 浏览器向服务器发起请求,交给前端控制器DispatcherServlet统一处理,DispatcherServlet对获取的请求路径进行解析,然后根据请求路径查找对应的请求映射(与@RequestMappingvalue值进行匹配)

  2. 如果匹配失败,即没有找到对应的请求映射,则DispatcherServlet将当前请求路径(或资源)交给服务器默认servletDefaultServlet处理,如果请求是一些静态资源(.css、.js等),则默认servlet能够处理,并成功发送给浏览器;如果请求是其他资源或路径,则默认servlet也无法处理,最终页面可能报404错误

  3. 如果匹配成功,此时DispatcherServlet会调用处理器映射器HandlerMapping对象进一步根据请求路径查找到对应的处理器Handler(即控制器方法),然后把与Handler相关的对象(包括控制器对象及其拦截器对象等)封装成一个HandlerExecutionChain对象(处理执行链,用于调用拦截器相关方法)并返回

  4. 在查找到请求路径对应的Handler(控制器方法)后,DispatcherServlet再根据Handler查找合适的处理器适配器HandlerAdapter来执行Handler

  5. 如果配置了拦截器,则在执行Handler前,会前执行拦截器的preHandle()方法,如果方法返回值为true,则继续执行Handler

  6. 处理器适配器HandlerAdapter调用handle()方法来间接执行Handler,并将Handler中所设置的模型数据和视图数据封装成一个ModelAndView对象返回。在这个过程中,除了完成请求的具体处理,Spring MVC还会对控制器方法中已有的配置(添加的形参、其他的注解)进行额外的处理

    ❓ 额外的处理

    • 报文信息转换(HttpMessageConveter):将请求报文信息(Json数据、xml等)转换成Java对象,将Java对象转换成响应报文信息
    • 数据类型转换:如果控制器方法中与请求参数对应的形参类型不是String,则Spring MVC会将String类型的请求参数转换成对应的形参类型
    • 数据格式化:对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等
    • 数据校验: 验证数据的有效性(长度、格式等)
  7. 如果配置了拦截器,则执行完Handler后会执行拦截器的postHandle()方法

  8. 执行完Handler后会获取到一个ModelAndView对象,DispatcherServlet会先判断此时是否出现异常,如果出现异常,会调用异常处理器改变此时的视图名,根据新的视图名更新ModelAndView对象

  9. 获取到最终的ModelAndView对象后,DispatcherServlet会将该对象传给processDispatchResult()方法,对模型数据和视图数据做进一步处理

  10. processDispatchResult()方法中调用render()方法,根据视图名采用对应的视图解析器,对视图进行解析和渲染,最后返回一个视图对象view

  11. 如果配置了拦截器,则在渲染视图后会执行拦截器的afterCompletion()方法

  12. 最后根据视图对象view将视图数据展示到页面上

🔑图解springmvc-execution-flow

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

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

相关文章

非零基础自学Golang 第10章 错误处理 10.1 错误处理的方式 10.2 自定义错误

非零基础自学Golang 文章目录非零基础自学Golang第10章 错误处理10.1 错误处理的方式10.2 自定义错误10.2.1 错误类型10.2.2 创建错误10.2.3 自定义错误格式第10章 错误处理 我们在编写程序时&#xff0c;为了加强程序的健壮性&#xff0c;往往会考虑到对程序中可能出现的错误…

大数据必学Java基础(一百一十三):监听器概念引入

文章目录 监听器概念引入 一、什么是监听器? 二、监听器怎么分类?

SQL - MySQL深分页

一、MySQL深分页问题 我们在日常开发中&#xff0c;查询数据量比较大的时候&#xff0c;后端基本都会通过前端&#xff0c;移动端传过来的页码&#xff0c;每页数据行数&#xff0c;通过SQL中的 limit 进行分页&#xff0c;如果查询页数比较小的时候&#xff0c;不会出现太大问…

【有营养的算法笔记】 二分+排序/堆 求解矩阵中战斗力最弱的 K 行

&#x1f451;作者主页&#xff1a;进击的安度因 &#x1f3e0;学习社区&#xff1a;进击的安度因&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;有营养的算法笔记 ✉️分类专栏&#xff1a;题解 文章目录一、题目描述二、思路及代码实现1. 二分 排序2.…

【学习笔记】JDK源码学习之Vector(附带面试题)

【学习笔记】JDK源码学习之Vector&#xff08;附带面试题&#xff09; 什么是 Vector &#xff1f;它的作用是什么&#xff1f;它的底层由什么组成&#xff1f;是否是线程安全的&#xff1f; 老样子&#xff0c;跟着上面的问题&#xff0c;我们层层深入了解 Vector 吧。 1、…

Linux——linux面试题

cat a.txt | cut -d "/" -f 3 | sort | uniq -c |sort -nrgrep ESTABLISHED | awk -F " " {print $5} |cut -d ":" -f 1 | sort |uniq -c | sort -nr找回mysql的root用户的密码 首先&#xff0c;进入到/etc/my.cnf&#xff0c;插入一句skip-gra…

Apache Hudi Timeline

Timeline | Apache Hudi Hudi维护了在不同时刻在表上执行的所有操作的时间线&#xff0c;这有助于提供表的即时视图&#xff0c;同时也有效地支持按到达顺序检索数据。Hudi的核心是维护表上在不同的即时时间&#xff08;instants&#xff09;执行的所有操作的时间轴&#xff08…

windows下配置chrome浏览器驱动的详细攻略

要想使用python去爬取互联网上的数据&#xff0c;尤其是要模拟登录操作。那么selenium包肯定是绕不过的。 selenium包本质上就是通过后台驱动的方式驱动浏览器去。以驱动chrome浏览器为例&#xff0c;搭建环境如下&#xff1a; 1、查看本机chrome浏览器的版本。 方式是&#x…

第三十二章 linux-模块的加载过程二

第三十二章 linux-模块的加载过程二 文章目录第三十二章 linux-模块的加载过程二HDR视图的第二次改写模块导出的符号HDR视图的第二次改写 在这次改写中&#xff0c;HDR视图中绝大多数的section会被搬移到新的内存空间中&#xff0c;之后会根据这些section新的内存地址再次改写…

[附源码]计算机毕业设计Python“小世界”私人空间(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

知到/智慧树——程序设计基础(C语言)进阶篇

目录 第一章测试 第二章测试 第三章测试 第四章测试 第五章测试 第一章测试 第1部分总题数: 10 1 【单选题】 (10分) 在C语言中&#xff0c;将属于不同类型的数据作为一个整体来处理时&#xff0c;常用&#xff08; &#xff09;。 A. 简单变量 B. 数组类型数据 C. 结…

论文投稿指南——中文核心期刊推荐(力学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

10.union all、N天连续登录

有日志如下&#xff0c;请写出代码求得所有用户和活跃用户的总数及平均年龄。&#xff08;活跃用户指连续两天都有访问记录的用户&#xff09; 数据准备 最后需完成的结果表 步骤1&#xff0c;所有用户的总数及平均年龄 (1). 将数据去重 with t1 as (select distinctuser_i…

如何使用交换机、路由器及防火墙进行组网以及他们之间的功能和区别

如何使用交换机、路由器及防火墙进行组网以及他们之间的功能和区别。 几乎大部分网络都有交换机、路由器和防火墙这三种基本设备,因此这三种设备对于网络而言非常重要,很多人对这三种设备的使用容易弄混。 一般网络部署: 或者抽象为这种部署模式: 几乎每个网络都有交换…

别再写jsp了,Thymeleaf它不香吗?

啥是 Thymeleaf在学 Thymeleaf 之前我们先看一下使用 jsp 开发遇到的主要问题&#xff1a;jsp 的痛点1.页面包含大量 java 代码&#xff0c;代码太混乱<% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head> &l…

webpack实现自动代码编译

前置 使用webpack构建开发的代码&#xff0c;为了运行需要有两个操作&#xff1a; 操作一&#xff1a;npm run build&#xff0c;编译相关的代码。操作二&#xff1a;通过live server或者直接通过浏览器&#xff0c;打开index.html代码&#xff0c;查看效果。为了完成自动编译&…

《图解TCP/IP》阅读笔记(第五章 5.7、5.8)—— IP隧道与其他IP相关技术

5.7 IP隧道 IP隧道技术顾名思义&#xff0c;是用于在两片网络区域间直接建立通信的通路&#xff0c;而绕过此间的其他网络的一种技术&#xff0c;如下图所示&#xff1a; 网络A与网络B使用IPv6技术&#xff0c;使用IP隧道技术&#xff0c;便可以绕过网络C。 那么其工作原理是…

机器学习 波士顿房价预测 Boston Housing

目录 一&#xff1a;前言 二&#xff1a;模型预测(KNN算法) 三&#xff1a;回归模型预测比对 一&#xff1a;前言 波士顿房价是机器学习中很常用的一个解决回归问题的数据集 数据统计于1978年&#xff0c;包括506个房价样本&#xff0c;每个样本包括波士顿不同郊区房屋的13种…

SQL - MySQL回表

一、回表概念&#xff1b;现象 回表&#xff0c;顾名思义就是回到表中&#xff0c;也就是先通过普通索引&#xff08;我们自己建的索引不管是单列索引还是联合索引&#xff0c;都称为普通索引&#xff09;扫描出数据所在的行&#xff0c;再通过行主键ID 取出索引中未包含的数据…

[附源码]计算机毕业设计Python创新创业管理系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…