Spring——Spring开发实战经验(4)

news2025/5/11 5:31:33

摘要

本文深入探讨了 Spring 应用中 Interceptor(拦截器)、Filter(过滤器)和 Aspect(切面)的执行顺序、职责及典型使用场景。Filter 是 Servlet 级别的机制,主要用于日志记录、权限验证等,它在请求到达 Spring MVC 的 DispatcherServlet 前执行,响应返回时按配置顺序反向执行。Interceptor 是 Spring 提供的机制,用于拦截 Spring MVC 请求,它在请求进入 Spring MVC 处理之前、Controller 方法执行之前和之后执行。Aspect(AOP)则用于处理横切关注点,如事务管理、日志记录等,它通过代理机制在目标方法执行前后插入额外逻辑。文中还提供了 WebMvcConfig 配置示例、拦截器与其他组件的对比以及拦截器与 AOP 的区别和联系等内容,帮助读者更好地理解和使用这些机制。

1. Interceptor/Filter/Aspect 的执行顺序

在 Spring 应用中,InterceptorFilterAspect 都是用来处理请求的不同机制。它们各自有不同的职责和执行顺序。理解它们的执行顺序对于调试和优化应用非常重要。

1.1. Filter(过滤器)

职责Filter是一种 Servlet 级别的机制,主要用于请求和响应的预处理和后处理。它通常用于日志记录、权限验证、请求修改等操作。

执行顺序Filter 在 Servlet 容器中非常早地被调用,并且它在请求到达 Spring MVC 的处理器之前执行。

执行顺序:

  1. 请求到达:Filter 在请求到达 Spring MVC 的 DispatcherServlet 前执行。
  2. Filter 执行:所有配置的 Filter 按照配置顺序依次执行。
  3. 请求交给 DispatcherServlet:Filter 在请求到达 DispatcherServlet 时,会允许请求继续向下传递。
  4. 响应返回:响应从 DispatcherServlet 返回时,Filter 会按配置顺序反向执行(从最后一个 Filter 到第一个 Filter)。

典型使用场景

  • 日志记录
  • 权限校验
  • 请求数据修改
  • 响应数据修改

1.2. Interceptor(拦截器)

  • 职责Interceptor 是 Spring 提供的机制,它用于拦截 Spring MVC 请求。与 Filter 不同的是,Interceptor 是基于 Spring 的控制器和 HandlerMapping 的,并且它只与 Spring MVC 控制器交互。
  • 执行顺序Interceptor 在请求进入 Spring MVC 处理之前、Controller 方法执行之前和之后执行。

执行顺序:

  1. 请求到达 DispatcherServlet:当请求到达 DispatcherServlet 时,Interceptor 会按配置顺序依次执行。
  2. 执行 Controller 方法Interceptor 执行完成后,DispatcherServlet 会调用 Controller 层的处理方法。
  3. 响应返回:当 Controller 方法返回结果后,Interceptor 会按配置顺序反向执行,直到最后一个 Interceptor

典型使用场景

  • 权限验证
  • 请求计时
  • 处理请求日志

3. Aspect (AOP)(切面)

  • 职责Aspect 是基于切面编程(AOP)机制的,用于在方法执行前后增加额外的行为(如日志记录、事务处理等)。它是通过 @Aspect 注解和切点(@Before@After@Around 等)来定义的。
  • 执行顺序Aspect 是 Spring AOP 的一部分,AOP 执行顺序通常是基于方法执行的前后,而不是请求/响应的生命周期。它通常是在 Controller 方法执行前后,或者 Service/DAO 层方法执行前后 进行拦截。

执行顺序:

  1. 请求到达 DispatcherServlet:在这个阶段,InterceptorFilter 会先执行。
  2. Controller 方法执行Aspect 会在方法执行前后执行,具体的顺序取决于通知的类型(例如 @Before@After@Around 等)。
    • @Before:在目标方法执行前执行。
    • @After:在目标方法执行后执行。
    • @Around:可以在方法执行前后都执行。
  1. 响应返回:响应返回时,Aspect 会根据 @After@AfterReturning 等通知继续执行。

典型使用场景

  • 日志记录
  • 事务管理
  • 安全校验

执行顺序总结:

阶段

Filter

Interceptor

Aspect

请求到达 DispatcherServlet

首先执行(Filter Chain)

最后执行(Spring 容器配置的顺序)

不影响请求进入 DispatcherServlet

Controller 方法执行前

不参与

执行前通知 (preHandle

)

执行前通知 (@Before

@Around

)

Controller 方法执行后

不参与

执行后通知 (postHandle

)

执行后通知 (@After

@Around

)

响应返回

反向执行(Filter Chain)

反向执行(Spring 容器配置的顺序)

执行后通知 (@AfterReturning

@After

)

执行顺序图解

  1. FilterInterceptorController 方法InterceptorFilter (请求方向)
  2. FilterInterceptorController 方法InterceptorFilter (响应方向)

实用场景示例:

假设有如下情形:

  • 你需要在每个请求的最前面进行身份验证,可以使用 Filter 来实现。
  • 你需要在控制器方法执行之前和之后记录日志或进行权限校验,可以使用 Interceptor 来实现。
  • 你需要在特定方法执行前后做日志记录、事务管理等操作,可以使用 Aspect 来实现。

补充说明

  • Filter 是 Java EE 标准的机制,直接作用于 Servlet 容器,独立于 Spring。
  • Interceptor 是 Spring 特有的功能,作用于 Spring MVC 处理的请求。
  • Aspect 是 Spring AOP 提供的功能,可以用来处理横切关注点,适用于方法级别的增强。

通过合理的使用 FilterInterceptorAspect,你可以实现非常灵活的请求处理、日志记录、安全校验等功能。

2. WebMvcConfig配置示例

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Resource
    private PermissionInterceptor permissionInterceptor;
    @Resource
    private CookieInterceptor cookieInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
        registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
    }

}

这是一个 Spring MVC 的配置类,WebMvcConfig 实现了 WebMvcConfigurer 接口,主要用于配置和定制 Spring MVC 的行为。以下是代码中的关键点:

  • @Configuration:标注该类为一个配置类,Spring 容器会将其识别为 Bean 定义的来源。
  • WebMvcConfigurer:这是一个 Spring 提供的接口,允许我们通过实现其方法来自定义 Spring MVC 的配置。
  • @Resource:用于注入 Spring 容器中的 Bean。这里注入了两个拦截器:
  • permissionInterceptor:权限拦截器,用于处理与用户权限相关的逻辑。
  • cookieInterceptor:Cookie 拦截器,用于处理与 Cookie 验证或操作相关的逻辑。
  • addInterceptors 方法:这个的是实现WebMvcConfigurer的方法。用来向 Spring MVC 的拦截器链中添加拦截器。
  • InterceptorRegistry:拦截器注册器,用于配置拦截器及其作用路径。
  • addInterceptor(permissionInterceptor).addPathPatterns("/**")
  • permissionInterceptor 注册到拦截器链。
  • addPathPatterns("/**") 表示拦截所有请求路径。
  • addInterceptor(cookieInterceptor).addPathPatterns("/**"):同样注册 cookieInterceptor 拦截所有请求路径。

拦截器执行顺序:拦截器会按照注册顺序依次执行(即先执行 permissionInterceptor,再执行 cookieInterceptor)。

package org.springframework.web.servlet.config.annotation;

import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;

public interface WebMvcConfigurer {
    default void configurePathMatch(PathMatchConfigurer configurer) {
    }

    default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    default void addFormatters(FormatterRegistry registry) {
    }

    default void addInterceptors(InterceptorRegistry registry) {
    }

    default void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    default void addCorsMappings(CorsRegistry registry) {
    }

    default void addViewControllers(ViewControllerRegistry registry) {
    }

    default void configureViewResolvers(ViewResolverRegistry registry) {
    }

    default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    }

    default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
    }

    default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    @Nullable
    default Validator getValidator() {
        return null;
    }

    @Nullable
    default MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

这段代码定义了 WebMvcConfigurer 接口,它是 Spring MVC 配置的核心接口之一。通过实现这个接口,开发者可以自定义 Spring MVC 的各种行为,包括路径匹配、内容协商、异步支持、默认 Servlet 处理、格式化器、拦截器、资源处理器、跨域映射、视图控制器、视图解析器、参数解析器、返回值处理器、消息转换器、异常处理器以及验证器和消息代码解析器。

3. Spring 中拦截器

Spring MVC的拦截器 (HandlerInterceptor) 是一种 AOP(面向切面编程) 的实现机制,允许在请求处理的不同阶段拦截 HTTP 请求并执行特定逻辑。以下是拦截器的主要作用:

3.1. 拦截器工作流程

  1. 触发时机:
    • 拦截器在请求到达控制器(@Controller@RestController)之前执行。
    • 响应生成后,在发送给客户端之前再次执行。
  1. 主要方法:
    • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      • 在请求到达控制器之前执行。
      • 返回 true 表示继续处理请求;返回 false 表示中止请求。
    • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
      • 在控制器处理完请求后,但尚未生成响应之前执行。
    • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      • 在视图渲染完成后执行,用于资源清理或记录日志。

3.2. 拦截器常见应用场景

  1. 权限校验(如 PermissionInterceptor):
    • 判断用户是否有权限访问某些接口。
    • 如果没有权限,直接返回错误响应(如 403 Forbidden)。
  1. 认证与登录验证
    • 验证用户是否已登录,检查 SessionToken
    • 如果未登录,跳转到登录页面或返回 401 Unauthorized。
  1. 请求日志记录
    • 记录请求的参数、响应结果、执行时间等信息,用于监控和分析。
  1. 参数校验与数据预处理
    • 检查请求中的参数是否合法。
    • 为请求添加必要的上下文数据(如用户信息、请求头补充)。
  1. 跨站请求伪造(CSRF)防护
    • 检查请求头中的 CSRF Token 是否有效。
  1. 请求追踪与调试
    • 生成唯一的请求 ID,用于追踪请求链路。

3.3. 拦截器与其他组件的对比

特性

拦截器 (Interceptor)

过滤器 (Filter)

切面 (AOP Aspect)

触发阶段

Spring MVC 的处理流程内

Servlet 请求的早期阶段

方法级别(如 @Controller

方法调用)

关注点

与请求处理相关(权限、认证等)

全局请求过滤(编码、跨域等)

与业务逻辑相关(如日志、事务管理)

实现接口

HandlerInterceptor

javax.servlet.Filter

@Aspect

(基于 Spring AOP)

应用场景

请求认证、权限校验、日志记录等

请求过滤、跨域、编码设置等

日志、事务处理、通用逻辑

4. 拦截器与AOP区别

拦截器(Interceptor)虽然与 AOP(面向切面编程) 有相似之处,但严格来说,拦截器并不是 AOP 的直接实现,而是一个独立的机制。二者有不同的设计目的和实现方式,但在某些场景下确实可以通过拦截器实现类似于 AOP 的功能。下面详细分析它们的区别和联系。

4.1. 拦截器与 AOP 的区别

4.1.1. 核心概念不同

  • AOP(Aspect-Oriented Programming)
    • 是一种面向切面编程的设计思想,用于在不改变核心业务逻辑的情况下,动态地为方法添加额外行为。
    • 通过 切面(Aspect)切入点(Pointcut) 的定义,精准定位到某些方法调用,并在方法执行的 前后或异常时 添加逻辑。
    • 主要基于 Spring AOP(代理模式) 或 AspectJ(字节码增强)。
  • 拦截器(Interceptor)
    • 是 Spring MVC 或其他框架提供的一种机制,用于对 HTTP 请求和响应 进行拦截和处理。
    • 通常应用在 Web 请求的处理链路 中,比如在请求到达控制器之前,或响应生成之后添加逻辑。

4.1.2. 工作范围不同

  • AOP
    • 应用于方法级别,主要是对业务方法(如 @Service@Controller)进行增强。
    • 可以在任何类的方法上进行增强,甚至独立于 Spring MVC。
  • 拦截器
    • 专注于处理 HTTP 请求和响应,属于 Spring MVC 流程 的一部分。
    • 作用范围是 Controller(控制器)方法之前和之后

4.1.3. 触发机制不同

  • AOP
    • 基于代理模式(JDK 动态代理或 CGLIB 动态代理)或字节码操作(如 AspectJ)。
    • 使用切面定义,依赖切入点表达式(如 execution())。
    • 仅对特定的方法调用生效,与 HTTP 请求无关。
  • 拦截器
    • 工作在 Spring MVC 的处理链中,由 DispatcherServlet 调度执行。
    • 对 HTTP 请求进行预处理(如认证、日志、跨域检查等)。

4.2. 拦截器是否可以实现 AOP 的功能?

在某些场景下,拦截器确实可以实现类似 AOP 的功能,例如:

  • 记录日志: 在拦截器的 preHandle 方法中记录请求的参数。
  • 权限校验: 在拦截器中判断是否有访问权限,阻止不合法请求。

但拦截器的能力有限:

  1. 它只能拦截基于 HTTP 的请求,无法对方法调用(非 HTTP 场景)进行增强。
  2. 它无法精准到某个类或方法,而是基于请求路径。

AOP 更灵活和强大,适合以下场景:

  • 精准增强特定方法(通过切入点)。
  • 跨服务的通用逻辑(如事务管理、性能监控)。

4.3. 拦截器与 AOP 的联系

  • 二者的功能在某些场景下重叠。例如,拦截器可以在请求进入 Controller 前后,记录日志或进行校验,这与 AOP 的切面功能相似。
  • 在 Spring 应用中,AOP 和拦截器经常配合使用
    • 拦截器处理全局的 HTTP 请求级别逻辑。
    • AOP 处理业务方法级别的切面逻辑。

4.4. 拦截器和 AOP 的对比表

特性

AOP

拦截器(Interceptor)

作用范围

方法级别(类、方法的调用)

请求级别(HTTP 请求前后)

依赖机制

动态代理(JDK Proxy 或 CGLIB)

Spring MVC 的 HandlerInterceptor

主要应用场景

日志、事务管理、性能监控、方法增强等

请求认证、权限校验、跨域、统一日志等

触发点

方法调用(如 @Service

方法)

HTTP 请求的处理过程

实现方式

@Aspect

(Spring AOP 或 AspectJ)

实现 HandlerInterceptor

接口

局限性

无法直接作用于 HTTP 请求

无法精确到特定方法,强依赖 Spring MVC

4.5. 示例对比

4.5.1. AOP 切面示例

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }
}
  • 作用:com.example.service 包中的所有方法执行之前记录日志。

4.5.2. 拦截器示例

public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("Before handling request: " + request.getRequestURI());
        return true;
    }
}
  • 作用: 在每次 HTTP 请求到达 Controller 之前记录请求路径。

4.6. 总结

  • 拦截器不是 AOP 的实现,但它们的功能在某些场景下有重叠。
  • 拦截器 更偏向于 HTTP 请求级别的拦截,而 AOP 更灵活,适合方法级增强。
  • 在复杂项目中,拦截器和 AOP 通常配合使用,实现从请求级别到方法级别的逻辑分离。

博文参考

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

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

相关文章

小白win10安装并配置yt-dlp

需要yt-dlp和ffmpeg 注意存放路径最好都是全英文 win10安装并配置yt-dlp 一、下载1.下载yt-dlp2. fffmpeg下载 二、配置环境三、cmd操作四、yt-dlp下视频操作 一、下载 1.下载yt-dlp yt-dlp地址 找到win的压缩包点下载&#xff0c;并解压 2. fffmpeg下载 ffmpeg官方下载 …

I²C简介

前言 IC&#xff08;Inter-Integrated Circuit, 内置集成电路&#xff09;总线是由Philips公司&#xff08;现属于恩智浦&#xff09;在上世纪80年代开发的两线式串行通信总线&#xff0c;用于连接微控制器及其外围设备&#xff0c;控制设备之间的通信。 IC总线的物理拓扑示意…

【Vue+python】Vue调用python-fastApi接口实现数据(数值、列表类型数据)渲染

前言&#xff1a;之前做的一直都是SpringBootVue的应用&#xff0c;但现在需要实现一个能将python实现的算法应用展示在前端的界面。想法是直接Vue调用python-fastApi接口实现数据渲染~ 文章目录 1. 变量定义2. axios调用python3. 跨域问题解决4. 数据渲染4.1 数值数据渲染4.2 …

构建高效智能对话前端:基于Ant Design X 的deepseek对话应用

文章目录 实现的效果前言Ant Design X添加欢迎组件创建对话气泡存储对话历史渲染对话气泡 输入组件WebSocket 连接总结 实现的效果 待机页面&#xff1a; 等待页面&#xff1a; 完成页面&#xff1a; 前言 随着人工智能技术的飞速发展&#xff0c;大模型对话系统已成为…

开源多商户商城源码最新版_适配微信小程序+H5+APP+PC多端

在数字化时代&#xff0c;电子商务已经成为各行业不可或缺的一部分&#xff0c;开源多商户商城源码为中小企业和个人开发者提供了快速搭建和定制电商平台的利器。分享一款最新版的开源多商户商城源码&#xff0c;它能够适配微信小程序、H5、APP和PC等多个端口&#xff0c;满足商…

第3章 .NETCore核心基础组件:3.1 .NET Core依赖注入

3.1.1 什么是控制反转、依赖注入 杨老师在书中进行了一系列的文字阐述&#xff0c;总结一下就是&#xff1a;软件设计模式中有一种叫做【控制反转】的设计模式&#xff0c;而依赖注入是实现这种设计模式的一个很重要的方式。也就是说学习依赖注入&#xff0c;是学习怎样实现控…

cesium基础设置

cesium官网下载&#xff1a;https://cesium.com/downloads/ 1.安装cesium 选择下载到本地使用&#xff0c;或者通过npm下载到项目中 2.代码书写 &#xff08;1&#xff09;创建容器 <div id"cesiumContainer" style"width: 100%; height: 100%"><…

Spring-GPT智谱清言AI项目(附源码)

一、项目介绍 本项目是Spring AI第三方调用整合智谱请言&#xff08;官网是&#xff1a;https://open.bigmodel.cn&#xff09;的案例&#xff0c;回答响应流式输出显示&#xff0c;这里使用的是免费模型&#xff0c;需要其他模型可以去 https://www.bigmodel.cn/pricing 切换…

文件夹上传到github分支最后github上面还是没有文件和文件夹

环境&#xff1a; github 问题描述&#xff1a; 文件夹上传到github分支最后github上面还是没有文件和文件夹, 和这样一样 解决方案&#xff1a; 从 git ls-tree -r HEAD 的输出中可以看到&#xff0c;metahuman-stream 文件夹显示为如下内容&#xff1a; 160000 commi…

【文献精读】AAAI24:FacetCRS:打破对话推荐系统中的“信息茧房”

标题FacetCRS: Multi-Faceted Preference Learning for Pricking Filter Bubbles in Conversational Recommender System期刊The Thirty-Eighth AAAI Conference on Artificial Intelligence (AAAI-24)年份2024关键词Conversational Recommender System (CRS), Filter Bubbles,…

网络安全推荐的视频教程 网络安全系列

第一章 网络安全概述 1.2.1 网络安全概念P4 网络安全是指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或恶意的原因而遭到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。 1.2.3 网络安全的种类P5 &#xff08;1…

基于Python的深度学习音乐推荐系统(有配套论文)

音乐推荐系统 提供实时音乐推荐功能&#xff0c;根据用户行为和偏好动态调整推荐内容 Python、Django、深度学习、卷积神经网络 、算法 数据库&#xff1a;MySQL 系统包含角色&#xff1a;管理员、用户 管理员功能&#xff1a;用户管理、系统设置、音乐管理、音乐推荐管理、系…

javacv将mp4视频切分为m3u8视频并播放

学习链接 ffmpeg-demo 当前对应的 gitee代码 Spring boot视频播放(解决MP4大文件无法播放)&#xff0c;整合ffmpeg,用m3u8切片播放。 springboot 通过javaCV 实现mp4转m3u8 上传oss 如何保护会员或付费视频&#xff1f;优酷是怎么做的&#xff1f; - HLS 流媒体加密 ffmpe…

MVTEC数据集笔记

前言 网上的博客只有从论文里摘出的介绍&#xff0c;没有数据集文件详细的样子&#xff0c;下载数据集之后&#xff0c;对数据集具体的构成做一个补充的笔记。 下载链接&#xff1a;https://ai-studio-online.bj.bcebos.com/v1/7d4a3cf558254bbaaf4778ea336cb14ed8bbb96a7f2a…

[数据结构]红黑树,详细图解插入

目录 一、红黑树的概念 二、红黑树的性质 三、红黑树节点的定义 四、红黑树的插入&#xff08;步骤&#xff09; 1.为什么新插入的节点必须给红色&#xff1f; 2、插入红色节点后&#xff0c;判定红黑树性质是否被破坏 五、插入出现连续红节点情况分析图解&#xff08;看…

国家地理信息公共服务平台的天地图

文章目录 一、国家地理信息公共服务平台的天地图二、地图转换1.GIS数据格式坐标转换&#xff08;地球坐标WGS84、GCJ-02、火星坐标、百度坐标BD-09、国家大地坐标系CGCS2000&#xff09;2.读入数据 总结 一、国家地理信息公共服务平台的天地图 三大地图付费后&#xff0c;仍可…

JavaScript中字符串的常用方法

JavaScript中字符串的常用方法 1.查询类2.拼接3.截取4.大小写5.去掉空格6.重复7.填充8.分隔9.模版匹配方法 可以通过查看String对象的原型来看有哪些方法: console.dir(String.prototype)1.查询类 charAt(index):返回指定位字符 console.log("abc".charAt(1));//b…

基于fastadmin快速搭建导航站和API接口站点系统源码

源码介绍 基于fastadmin快速搭建导航站和API接口站点系统源码 上传源码 设置运行目录为/public 导入 数据库.sql到数据库 设置配置文件application/database.php 后台admin.php 可以自己随意修改本文件名称为后台地址 推荐越复杂越好 账号admin 密码 123456 效果预览

【Vue3】Vue 3 中列表排序的优化技巧

本文将深入探讨 Vue 3 中列表排序的优化技巧&#xff0c;帮助提升应用的性能和响应速度。 1. 避免不必要的排序 按需排序 在实际应用中&#xff0c;并非每次数据更新都需要进行排序。例如&#xff0c;当列表数据仅在特定条件下需要排序时&#xff0c;可通过条件判断来避免不…

使用html css js 来实现一个服装行业的企业站源码-静态网站模板

最近在练习 前端基础&#xff0c;html css 和js 为了加强 代码的 熟悉程序&#xff0c;就使用 前端 写了一个个服装行业的企业站。把使用的技术 和 页面效果分享给大家。 应用场景 该制衣服装工厂官网前端静态网站模板主要用于前端练习和编程练习&#xff0c;适合初学者进行 HT…