SpringBoot+FastJson 优雅的过滤 Response Body

news2024/11/23 13:03:04

Spring 源码系列

1、Spring 学习之扩展点总结之后置处理器(一)
2、Spring 学习之扩展点总结之后置处理器(二)
3、Spring 学习之扩展点总结之自定义事件(三)
4、Spring 学习之扩展点总结之内置事件(四)
5、Spring 学习之扩展点总结之@Import(五)
6、Spring 学习之AOP总结之基础介绍(六)
7、Spring 学习之AOP总结之实现代理(七)
8、SpringBoot 学习之自动配置基本原理(八)
9、SpringBoot 学习之启动原理(九)
10、ElasticSearch学习随笔之SpringBoot Starter 操作
11、图数据库 Neo4j 学习之SpringBoot整合
12、SpringBoot 学习之常用 Filter / Advice 总结
13、SpringBoot+FastJson 优雅的过滤 Response Body

文章目录

  • Spring 源码系列
  • 前言
  • 一、思路简介
  • 二、FastJsonHttpMessageConverter 是什么?
  • 三、@*** 注解编写
    • 3.1 @ResponseJSON 注解
    • 3.2 @Ignore 注解
  • 四、JSONHttpMessageConverter 消息体处理实现
    • 4.1 JSONHttpMessageConverter 类及依赖
    • 4.2 writeInternal() 处理消息体
    • 4.3 toJSONString() 对象转换 JSON
    • 4.4 getSerializeFilter() 序列化Filter实现
    • 4.5 setApplicationContext() 设置上下文
  • 五、HandlerHolder 获取请求处理器 Handler 实现
  • 六、EntityClassPropertyFilter 序列化对象属性过滤器
  • 七、AppConfig 配置类让转换器生效
  • 八、测试结果
    • 8.1 测试接口
    • 8.2 请求测试
  • 八、小结

前言

还是那个问题,前两天在开发一个需求时遇到这么一个问题,就是对接口的返回体【Response Body】做一些处理,,猛然间居然还是手足无措,最后决定使用 ResponseBodyAdvice 通知来实现,所以总结了一下开发中常用的 Filter 和 Advice,也欢迎 码友 们指点一二,我也会在空闲时第一时间补充进去,博文见 《SpringBoot 学习之常用 Filter / Advice 总结》。
不过发现即便使用 Filter 或者 Advice 可以实现,但是不够优雅…
目前企业开发项目中基本上都是用 JSON 格式作为 API 响应体,我负责的项目亦是,并且使用的是 alibaba 的 fastjson,然后有前面大佬的杰作加上我的虚心学习之后,决定用 FastJson 扩展点【FastJsonHttpMessageConverter】来实现。

提示:只要按照思路简介的几步完成即可实现优雅的过滤消息体功能!

一、思路简介

在 Spring Boot 中,默认使用 Jackson 库来将返回体转换为 JSON 格式的数据。 Jackson 是一个流行的 JSON 处理库,Spring 框架中集成了它作为默认的 JSON 序列化和反序列化工具。
不过在我们的应用中也使用到了 FastJson 来对响应体或对象实体与 JSON 进行转换,既然使用到了了 FastJson,那我们就可以通过 FastJson 扩展来在转换 JSON 的过程中实现字段过滤,这样我觉得就优雅了许多。
FastJson 中有一个 FastJsonHttpMessageConverter 是 FastJson 中提供的消息【转换器】,我们就通过继承FastJsonHttpMessageConverter 并重写转换功能来实现返回体字段过滤。
具体有如下几点:

  1. 编写 @ResponseJSON@Ignore 注解,我们通过注解来配置每个接口返回的字段。
  2. 自定义转换器【JSONHttpMessageConverter】继承 FastJsonHttpMessageConverter 并且实现 ApplicationContextAware 接口(主要用于获取上下文)。
  3. 自定义HandlerHolder 类实现接口 HandlerInterceptor,主要用于获取到我们自己开发的请求处理器 Handler请求处理器)。
  4. 自定义 EntityClassPropertyFilter 过滤器实现 FastJson 提供的 PropertyPreFilter 过滤器并且 重写 apply(*) 方法 ,通过实现这个方法,可以自定义过滤规则,在序列化对象时,Fastjson 将会根据实现了 PropertyPreFilter 接口的对象的 apply 方法来判断哪些属性需要被序列化,哪些属性需要被过滤掉。
  5. 自定义 AppConfig 配置类让返回体转换器生效。

源码已提交到码云仓库,欢迎点击查看!!!

二、FastJsonHttpMessageConverter 是什么?

FastJsonHttpMessageConverter 是 FastJson 中提供的消息转换器,在 Spring Boot 中可以用来将对象转换为 JSON 格式的数据,用于处理接口返回体的数据,具体作用如下:

  1. JSON 转换,FastJsonHttpMessageConverter 实现了 Spring 框架中的 HttpMessageConverter 接口,能够将 JAVA 对象转换成 JSON 格式数据,以便通过 HTTP 返回给客户端。
  2. FastJson 配置,该转换器对 FastJson 进行配置,比如设置序列化特性、日期格式化等。
  3. 可以替代 Spring Boot 默认的 Jackson 转换器。

三、@*** 注解编写

按照思路简介 第 1 步,编写注解类,直接上代码。

3.1 @ResponseJSON 注解

package com.selftest.web.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseJSON {

    Ignore[] ignore() default {};

    boolean enable() default true;

}

3.2 @Ignore 注解

package com.selftest.web.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Ignore {

    Class<?> declaringClass();

    String[] propNames();

    boolean inverse() default false;

}

四、JSONHttpMessageConverter 消息体处理实现

按照思路简介第 2 步,编写 JSONHttpMessageConverter 类,代码中都有注释,直接上代码。
这个类是实现响应体的主要部分,主要是实现消息体转换和配置,代码比较多,分开一段一段看。

4.1 JSONHttpMessageConverter 类及依赖

package com.selftest.web.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.selftest.web.RequestHandlerHolder;
import com.selftest.web.annotation.Ignore;
import com.selftest.web.annotation.ResponseJSON;
import com.selftest.web.filter.EntityClassPropertyFilter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * JSON 数据转换,实现返回体字段过滤
 */
public class JSONHttpMessageConverter extends FastJsonHttpMessageConverter implements ApplicationContextAware {

    /**
     * 应用上下文
     */
    private ApplicationContext ctx;
	
	/**
     * 请求处理器 Handler 持有者 
     */
    @Resource
    private RequestHandlerHolder requestHandlerHolder;

    private FastJsonConfig fastJsonConfig = new FastJsonConfig();
	
	此处代码下面依次呈现
	3.2 writeInternal() 方法
	3.3 toJSONString() 方法
	3.4 getSerializeFilter() 方法
	3.5 setApplicationContext() 方法
}

4.2 writeInternal() 处理消息体

	/**
    * 返回体处理
    * @param obj the object to write to the output message
    * @param outputMessage the HTTP output message to write to
    * @throws IOException
    * @throws HttpMessageNotWritableException
    */
   @Override
   protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
       //获取到返回流
       OutputStream out = outputMessage.getBody();
       String jsonString = toJSONString(obj);
       out.write(jsonString.getBytes(StandardCharsets.UTF_8));
   }

4.3 toJSONString() 对象转换 JSON

/**
     * 将对象转换为JSON字符串
     * @return
     */
    private String toJSONString(Object obj){
        //获取到处理请求的 Handler
        if(Objects.isNull(requestHandlerHolder)){
            return JSON.toJSONString(obj);
        }
        Object handler = requestHandlerHolder.getHandler();
        //如果 handler 为空或者 handler 不为空但是返回类型不是 entity 的
        if(Objects.isNull(handler)
                || (Objects.nonNull(requestHandlerHolder.getHandlerMethod().getReturnType())
                    && requestHandlerHolder.getHandlerMethod().getReturnType().isAssignableFrom(ResponseEntity.class))){
            return JSON.toJSONString(obj);
        }

        //如果是处理方法,则获取到返回类型 ReturnType、annotation
        ResponseJSON annotation = null;
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            MethodParameter returnType = method.getReturnType();
            annotation = returnType.getMethodAnnotation(ResponseJSON.class);
            if (Objects.isNull(annotation)) {
                annotation = method.getMethodAnnotation(ResponseJSON.class);
            }
        }
        if(Objects.isNull(annotation) || (Objects.nonNull(annotation) && !annotation.enable())){
            return Objects.nonNull(obj) ? JSON.toJSONString(obj) : null;
        }
        // 获取到真正实现返回体过滤的序列化 filter
        SerializeFilter filter = getSerializeFilter(annotation);
        // 封装自定义 filter, 传入上面的 filter 和 自定义注解
        EntityClassPropertyFilter propertyFilter = new EntityClassPropertyFilter(filter, annotation);
        return JSON.toJSONString(obj, propertyFilter, this.fastJsonConfig.getSerializerFeatures());
    }

4.4 getSerializeFilter() 序列化Filter实现

/**
     * 获取序列化 filter
     * @param annotation
     * @return
     */
    private SerializeFilter getSerializeFilter(ResponseJSON annotation) {
        if(Objects.nonNull(annotation)){
            Ignore[] ignoreFields = annotation.ignore();
            if(ignoreFields.length == 0){
                return null;
            }
            Map<Class<?>, Map<Boolean, Set<String>>> ignoreMap = new HashMap<>();
            for (Ignore ignore : ignoreFields) {
                Class<?> declaringClass = ignore.declaringClass();
                Map<Boolean, Set<String>> propNameMap = ignoreMap.get(declaringClass);
                if(Objects.isNull(propNameMap)) {
                    propNameMap = new HashMap<>();
                    ignoreMap.put(declaringClass, propNameMap);
                }
                boolean inverse = ignore.inverse();
                Set<String> propNameSet = propNameMap.get(inverse);
                if(CollectionUtils.isEmpty(propNameSet)){
                    propNameSet = new HashSet<>();
                    propNameMap.put(inverse, propNameSet);
                }
                for (String propName : ignore.propNames()) {
                    propNameSet.add(propName);
                }
            }
			// 返回 属性预处理 Filter 实例,真正实现返回体字段过滤
            return (PropertyPreFilter) (jsonSerializer, object, name) -> {
                for (Map.Entry<Class<?>, Map<Boolean, Set<String>>> ignoreEntry : ignoreMap.entrySet()) {
                    if (ignoreEntry.getKey().isAssignableFrom(object.getClass())) {
                        Set<String> ignorePropNames = ignoreEntry.getValue().get(false);
                        if (Objects.nonNull(ignorePropNames) && ignorePropNames.contains(name)) {
                            return false;
                        }
                        ignorePropNames = ignoreEntry.getValue().get(true);
                        if (Objects.nonNull(ignorePropNames) && !ignorePropNames.contains(name)) {
                            return false;
                        }
                    }
                }
                return true;
            };
        }
        return null;
    }

4.5 setApplicationContext() 设置上下文

 /**
     * 获取应用上下文
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }

五、HandlerHolder 获取请求处理器 Handler 实现

按照思路简介 第 3 步,编写 HandlerHolder 类,代码中都有注释,直接上代码。
这个类主要是为了能在处理消息体处理的时候能获取到 Handler,因为我们的消息体处理是通过 Handler 方法上的 @ResponseJSON@Ignore 注解配置来实现的。

package com.selftest.web.interceptor;

import com.selftest.web.RequestHandlerHolder;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 请求处理拦截器,主要获取 Handler
 * 通过 ThreadLocal 获取
 */
public class HandlerHolder implements HandlerInterceptor, RequestHandlerHolder {

    /**
     * 通过 ThreadLocal 来暂存和获取 Handler
     */
    private final ThreadLocal<Object> HANDLERS = new ThreadLocal<>();

    /**
     * 在请求是获取到 Handler 并存入 ThreadLocal
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HANDLERS.set(handler);
        return true;
    }

    /**
     * 从 ThreadLocal 获取 Handler
     * @return
     * @param <T>
     */
    @Override
    public <T> T getHandler(){
        return (T) HANDLERS.get();
    }

    /**
     * 获取 Handler 的方法
     * @return
     */
    @Override
    public Method getHandlerMethod() {
        Object handler = getHandler();
        if (handler instanceof HandlerMethod) {
            return ((HandlerMethod) handler).getMethod();
        } else if (handler instanceof Method) {
            return (Method) handler;
        }
        return null;
    }
}

接口 RequestHandlerHolder 实现:

package com.selftest.web;

import java.lang.reflect.Method;

public interface RequestHandlerHolder {

    <T> T getHandler();

    Method getHandlerMethod();
}

六、EntityClassPropertyFilter 序列化对象属性过滤器

按照思路简介 第 4 步,编写 EntityClassPropertyFilter 类,代码中都有注释,直接上代码。

package com.selftest.web.filter;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.selftest.web.annotation.ResponseJSON;

import java.util.Objects;

/**
 * 实现对象属性序列化 filter
 */
public class EntityClassPropertyFilter implements PropertyPreFilter {

    private SerializeFilter filter;
    private ResponseJSON annotation;

    /**
     * 实例化
     * @param filter
     * @param annotation
     */
    public EntityClassPropertyFilter(SerializeFilter filter, ResponseJSON annotation) {
        this.filter = filter;
        this.annotation = annotation;
    }

    /**
     * 自定义过滤规则, 判断哪些属性需要被序列化,哪些属性需要被过滤掉
     * @param jsonSerializer
     * @param object
     * @param name
     * @return
     */
    @Override
    public boolean apply(JSONSerializer jsonSerializer, Object object, String name) {
        Class<?> elementType = object.getClass();
        if (Objects.nonNull(elementType)) {
            while (!elementType.equals(Object.class)) {
                if (Objects.nonNull(filter) && filter instanceof PropertyPreFilter) {
                    // 这里调用的是 JSONHttpMessageConverter 中 getSerializeFilter() 提供的 SerializeFilter
                    if (!((PropertyPreFilter)filter).apply(jsonSerializer, object, name)) {
                        return false;
                    }
                }
                elementType = elementType.getSuperclass();
            }
        }
        return true;
    }
}

七、AppConfig 配置类让转换器生效

按照思路简介 第 5 步,编写 HandlerHolder 类,代码中都有注释,直接上代码。

package com.selftest.config;

import com.selftest.web.http.JSONHttpMessageConverter;
import com.selftest.web.interceptor.HandlerHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 配置类
 */
@Configuration
public class AppConfig implements WebMvcConfigurer {

    /**
     * 实例化请求 handler
     * @return
     */
    @Bean(name = "requestHandlerHolder")
    public HandlerHolder requestHandlerHolder(){
        return new HandlerHolder();
    }

    /**
     * 返回体消息过滤 Bean
     * @return
     */
    @Bean
    public JSONHttpMessageConverter jsonHttpMessageConverter(){
        return new JSONHttpMessageConverter();
    }

    /**
     * 注册请求拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestHandlerHolder());
    }
}

八、测试结果

8.1 测试接口

	@ResponseJSON(ignore = {
            @Ignore(declaringClass = User.class, propNames = {"age"})
    })
    @GetMapping("users")
    public User getUser(){
        User user = new User();
        user.setId(1);
        user.setName("phen");
        user.setAge(30);
        return user;
    }

8.2 请求测试

成功过滤字段

八、小结

在 Spring Boot 中,默认使用 Jackson 库来将返回体转换为 JSON 格式的数据。 Jackson 是一个流行的 JSON 处理库,Spring 框架中集成了它作为默认的 JSON 序列化和反序列化工具。
那在 FastJson 中提供的 FastJsonHttpMessageConverter 消息转换器,我们则可以通过对此转换器的重写来实现对请求体字段的过滤,在 FastJsonHttpMessageConverter 中的 getSerializeFilter() 方法返回了 PropertyPreFilter 实体则真正的实现了返回体字段的过滤,在 自定义类 JSONHttpMessageConverter 中的 toJSONString() 方法中我们可以看到这几句代码:

SerializeFilter filter = getSerializeFilter(annotation);
EntityClassPropertyFilter propertyFilter = new EntityClassPropertyFilter(filter, annotation);
return JSON.toJSONString(obj, propertyFilter, this.fastJsonConfig.getSerializerFeatures()) 

第二个参数 propertyFilter 则是我们自己定义的 Filter,并且实现了 FastJson 提供的序列化过滤器 PropertyPreFilterEntityClassPropertyFilter 重写了 apply() 并且回调了 getSerializeFilter() 获取到的 filter,通过 JSON.toJSONString() 并且传入三个参数,第一个参数是我们自己实现的请求处理器返回的实体对象 User,第二个参数则是我们自己实现的序列化 Filter,第三个参数就是 FastJson 的默认的 SerializerFeature。

到这里,Spring Boot + FastJson 优雅的实现消息体字段的过滤就基本完成了,可以通过 debug 方式来看一下具体请求过滤是如何执行的,调用逻辑是什么。


江湖必有大佬藏,如有指点可别藏!
本文示例亲自手敲代码并且执行通过。
如有问题,还请指教。 评论区告诉我!!!一起学习一起进步!!!

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

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

相关文章

项目实战:自动驾驶之方向盘操纵

项目介绍 根据汽车前方摄像头捕捉的画面,控制汽车方向盘转动的方向和角度,这是自动驾驶要解决的核心问题。这个项目主要是通过使用深度神经网络解决一个回归问题。不同于分类、识别场景,回归问题中神经网络输出的是一个连续的值。 通过这个项目的学习,可以将神经网络用于通…

Flink系列之:大状态与 Checkpoint 调优

Flink系列之&#xff1a;大状态与 Checkpoint 调优 一、概述二、监控状态和 Checkpoints三、Checkpoint 调优四、RocksDB 调优五、增量 Checkpoint六、RocksDB 或 JVM 堆中的计时器七、RocksDB 内存调优八、容量规划九、压缩十、Task 本地恢复十一、主要&#xff08;分布式存储…

PADS9.5 : 原图绘图图纸尺寸下修改

原图绘图图纸尺寸下修改 图页边界线也要修改 如果二者选择不一致&#xff1a; 会出现下图所示情况&#xff1a;

Django和ECharts异步请求示例

前提条件 创建django项目&#xff0c;安装配置过程这里就不讲述了。 后端url http://127.0.0.1:8000/echarts/demo/ view视图函数 from django.http import HttpResponse import jsondef EchartsDemo(request):data {}categories ["衬衫","羊毛衫",&…

基于net6的zmq调试工具

0.前言 最近在做CS架构的上位机控制软件&#xff0c;服务端和客户端是通过zmq进行通讯的&#xff0c;网上现有的工具都是tcp、串口的调试工具&#xff0c;一直没有找到一个合适的zmq调试工具。就使用C#语言开发了这个简易的zmq调试工具&#xff0c;项目地址ZmqDebuggerTool。 …

这一篇就够了!全套SpringBoot教程02

SpringBoot运维实用篇 基础篇发布以后&#xff0c;看到了很多小伙伴在网上的留言&#xff0c;也帮助超过100位小伙伴解决了一些遇到的问题&#xff0c;并且已经发现了部分问题具有典型性&#xff0c;预计将有些问题在后面篇章的合适位置添加到本套课程中&#xff0c;作为解决方…

app分发平台哪个好点?手机app应用内测分发平台支持负载均衡的重要性

随着互联网的快速发展&#xff0c;内测分发平台扮演着越来越重要的角色。而在现代应用程序的开发和运营过程中&#xff0c;负载均衡技术是不可或缺的一部分。内测分发平台支持负载均衡对于提高系统的稳定性、可靠性和性能至关重要。那么什么是负载均衡又有哪些重要性。 图片来源…

FPGA设计时序约束十二、Set_Clock_Sense

目录 一、序言 二、Set Clock Sense 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 命令示例 三、工程示例 3.1 工程代码 3.2 无set_clock_sense 3.3 设置set_clock_sense 四、参考资料 一、序言 本章将介绍Set_Clock_Sense约束&#xff0c;在介绍约束之前&#xff0…

【上海大学数字逻辑实验报告】七、中规模元件及综合设计

一、实验目的 掌握中规模时序元件的测试。学会在Quartus II上设计序列发生器。 二、实验原理 74LS161是四位可预置数二进制加计数器&#xff0c;采用16引脚双列直插式封装的中规模集成电路&#xff0c;其外形如下图所示&#xff1a; 其各引脚功能为&#xff1a; 异步复位输…

cmd命令bat脚本隐藏执行窗口

家里一直都有远程开3389的需要&#xff0c;一直使用的是frp. 最近发现总是经常掉线。也不清楚原因&#xff0c;后调查出来原来是由于 我命令行窗口一般启动的比较多&#xff0c;有时候就会去点一下&#xff08;选择复制内容&#xff09;&#xff0c;如下&#xff1a; 有时候…

解决:Invalid bound statement (not found): com.XXXXX.UserMapper.countUser

问题&#xff1a;Invalid bound statement (not found): com.XXXXX.UserMapper.countUser 原因&#xff1a;mapper.java和mapper.xml映射不上 解决方法&#xff1a; 1、在application.properties全局配置文件中没有加上映射mapper文件的配置,mapper为resources下的文件&…

可以给网站任意位置添加4个区块源码

在网站里添加html区块把html里的代码复制进去&#xff0c;然后把3、4、5行的CSS和JS修改成网站对应目录就行了

十七、如何将MapReduce程序提交到YARN运行

1、启动某个节点的某一个用户 hadoopnode1:~$ jps 13025 Jps hadoopnode1:~$ yarn --daemon start resourcemanager hadoopnode1:~$ jps 13170 ResourceManager 13253 Jps hadoopnode1:~$ yarn --daemon start nodemanager hadoopnode1:~$ jps 13170 ResourceManager 15062 Jp…

MATLAB2022安装下载教程

安装包需从夸克网盘自取&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/373ffc9213a1 提取码&#xff1a;N7PW 1.将安装包解压 2.以管理员的身份运行文件夹中的setup文件 3.点击高级选项--->我有文件安装密钥 4. 选择【是】&#xff0c;进入下一步 5.输入密钥 0532…

汽车发动机市场调研:预计2029年将达到642亿美元

过去汽车发动机行业快速发展&#xff0c;很多产品都出现供不应求&#xff0c;甚至加价销售的状况&#xff0c;而随着产能过剩、需求下滑&#xff0c;未来汽车发动机行业的价格竞争将愈发激烈&#xff0c;形成新的供需矛盾。根据动力源类型&#xff0c;汽车可分类为传统燃油汽车…

819. 最常见的单词

819. 最常见的单词 Java&#xff1a;split() 过滤 class Solution {public String mostCommonWord(String paragraph, String[] banned) {String s paragraph.replaceAll("\\p{Punct}", " "); // 去除所有标点符号String arr[] s.split(" "…

C语言:求和1+1/2-1/3+1/4-1/5+……-1/99+1/100

#include<stdio.h> int main() {int i 0;double sum 0.0;int flag 1;for (i 1;i < 100;i){sum 1.0 / i * flag;flag -flag;}printf("sum%lf\n", sum);return 0; }

学习MS Dynamics AX 2012编程开发 2. X++语言

X是用于构建Dynamics AX功能的编程语言。X是一种与C类似的面向对象编程语言。 完成本章后&#xff0c;您将能够理解X语言&#xff1b;您将知道可用的数据类型是什么&#xff0c;如何创建各种循环&#xff0c;如何比较和操作变量&#xff0c;在哪里可以找到预定义的函数&#x…

OpenCV开发:MacOS源码编译opencv,生成支持java、python、c++各版本依赖库

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它为开发者提供了丰富的工具和函数&#xff0c;用于处理图像和视频数据&#xff0c;以及执行各种计算机视觉任务。 以下是 OpenCV 的一些主要特点和功能&#xff…

【JavaWeb学习笔记】11 - WEB工程路径专题

一、工程路径问题 1.引入该问题 通过这几个去访问很麻烦 二、工程路径解决方案 1.相对路径 1.说明:使用相对路径来解决&#xff0c;一 个非常重要的规则:页面所有的相对路径&#xff0c;在默认情况下&#xff0c;都会参考当前浏览器地址栏的路径http:/ /ip:port/工程名/来进…