SpringBoot参数请求处理

news2024/12/27 3:59:14

一、请求映射

  1. 请求映射原理

  2. DispatcherServlet 继承了 FrameworkServlet(抽象类,继承了 HttpServletBean,实现了 ApplicationContextAware 接口),重写了 doService() 方法
    在这里插入图片描述

  3. 在 doService() 方法里定义了 doDispatch() 方法;doDispatch() 方法最主要做了如下 2 件事

    2.1 通过 getHandler() 方法找出请求对应的 handler,该方法会遍历 handlerMappings(List) 从 5 个 HandlerMapping 中依次匹配请求对应的 handler
    在这里插入图片描述
    从第一个 RequestMapping 中可以看到我们的路由和对应的处理方法信息
    在这里插入图片描述
    2.2 通过找到的 mappedHandler 找出 HandlerAdapter 并执行 handle() 方法完成对应业务逻辑调用

  4. Rest 风格支持
    使用 Http 请求方式动词表示对资源的操作
    在这里插入图片描述

  5. Rest 核心 Filter
    HiddenHttpMethodFilter;用法:表单的 method = post,隐藏域 _method = put;

  6. Rest 基本原理
    前端在提交表单的时候,另外多提交了一个参数 _method = DELETE/PUT/PATCH,在 HiddenHttpMethodFilter 中可以看到 _method 是默认的参数值

public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    private static final List<String> ALLOWED_METHODS;
    // 默认参数值
    public static final String DEFAULT_METHOD_PARAM = "_method";
    private String methodParam = "_method";
    ... ...
}

在 WebMvcAutoConfiguration.class(web 所有自动配置类)下可以看到已默认配置了一个 HiddenHttpMethodFilter


(HiddenHttpMethodFilter.class)
(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
    return new OrderedHiddenHttpMethodFilter();
}

从 @ConditionalOnProperty 注解中发现要添加如下配置才能打开 Rest 风格支持

# 打开 Rest 风格支持, 默认值 false
spring.mvc.hiddenmethod.filter.enabled = true
  1. Rest 流程分析

  2. 表单提交的时候带参数 _method = PUT/DELETE/PATCH

  3. 请求被 HiddenHttpMethodFilter 拦截,只拦截 POST 类型和 _method = PUT/DELETE/PATCH 的请求

  4. 原生的 request(post) 被包装模式 requestWrapper 重写了 getMethod() 方法并返回

  5. 过滤器链放行的时候用 wrapper,以后的方法调用 getMethod() 方法变为调用 requestWrapper 的方法

  6. Rest 修改默认参数 _method
    在配置类中定义 HiddenHttpMethodFilter Bean 对象,并对默认参数值覆盖即可

(proxyBeanMethods = false)
public class WebMvcConfig {
    
    public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        // 修改默认参数
        methodFilter.setMethodParam("_myMethod");
        return methodFilter;
    }
}

二、普通参数和注解

在参数传递过程中,和参数绑定使用常见注解有:

@PathVariable:路径变量;适用于 rest 风格传参;如果写成 @PathVariable Map<String, Object> params 可获取前端传递的所有参数

/**
 * 根据用户主键查询用户
 */
("/user/{id}")
public String getUserById(("id") String id) {
	... ...
}

@RequestParam:获取请求参数;required 属性默认 true,如果前端没有传递 name 参数,就会报错;如果写成 @RequestParam Map<String, Object> params 可获取前端传递的所有参数

@GetMapping("/user/users")
public String getUserById(@RequestParam(value = "name", required = false) String userName) {
	return userName;
}

@RequestHeader:获取请求头信息,如果设置了 value 值(不区分大小写)就只取指定的请求头;如果写成 @RequestHeader Map<String, String> headers 可获取所有的请求头;注意:取出的请求头名称全小写

@GetMapping("/user/users")
public void getUserById(@RequestHeader("User-Agent") String userAgent, @RequestHeader Map<String, String> requestHeaders) {
	System.out.println("请求头 User-Agent 为:" + userAgent);
	requestHeaders.forEach((headerName, headerValue) -> System.out.println("header name: " 
	    + headerName + ", header value: " + headerValue));
}

@MatrixVariable:矩阵变量;例如:我们要查询用户名为 dufu,年龄为 18,31 岁的用户,一般的参数传递是:http://localhost:8080/user?name=dufu&age1=18&age2=31;对于年龄 age 这个参数,传值就不大方便;如果使用矩阵变量的方式传值,则可以写为:

  1. http://localhost:8080/user/xxx;name=dufu;age=18,31

  2. http://localhost:8080/user/xxx;name=dufu;age=18;age=31

@GetMapping("/user/{path}")
public void getUsers(@MatrixVariable("name") String name, @MatrixVariable("age") List<String> ages) {
	System.out.println(name);
	ages.forEach(age -> System.out.println(age));
}

注意

  1. 后端设置的请求路径包含动态路径才行,否则访问会报 404 异常

  2. 矩阵变量在 SpringBoot 中默认被禁用了;需要我们手动打开配置

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        // 不要移除请求路径中分号后面的内容;开启矩阵变量的功能
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

@CookieValue:获取请求的 cookie,可以使用 String 类型或 Cookie 对象接收

@GetMapping("/user/users")
public void getUserById(@CookieValue("_ga") String cookieValue, @CookieValue("_ga") Cookie cookie) {
    ... ...
}

@RequestBody:获取请求体,主要是 POST 类型的请求 JSON 格式参数获取

@PostMapping("/user/add")
public void getUserById(@RequestBody User user) {
    ... ...
}

@RequestAttribute:获取 request.setAttribute() 方法传递的值

@Controller
public class RequestController {
    @GetMapping("/test")
    public String test(HttpServletRequest request) {
        request.setAttribute("msg", "测试一下");
        request.setAttribute("code", 1);
        return "forward:/success";
    }

    @GetMapping("/success")
    @ResponseBody
    public void success(@RequestAttribute("msg") String msg, @RequestAttribute("code") Integer code, 
        HttpServletRequest request) {
        System.out.println("msg: " + msg);
        System.out.println("code: " + code);
        System.out.println(request.getAttribute("msg"));
        System.out.println(request.getAttribute("code"));
    }
}

三、Servlet API

我们可以在方法中直接添加 Servlet API 参数并直接使用;常用的 API 有:WebRequst、ServletRequest、MultipartRequest、HttpSession、javax.servlethttp.pushBuilder、Principal、InputStream、HttpMethod、Locale、TimeZone、ZoneId

四、复杂参数

在请求方法中同样可以直接添加这些复杂参数并使用:Map、Errors/BindingResult、Model、RedirectAttributes、ServletResponse、SessionStatus、UrlComponentsBuilder、ServletComponentsBuilder

Map、Model 里面的数据会被放在 request 的请求域中(相当于 request.setAttribute(xxx, xxx))

RedirectAttributes 是重定向携带数据的时候使用

测试代码如下

@Controller
public class RequestController {
    @GetMapping("/test")
    public String test(Map<String, Object> map, Model model, HttpServletRequest request, 
        HttpServletResponse response) {
        map.put("msg1", "a message from map");
        model.addAttribute("msg2", "a message from model");
        request.setAttribute("msg3", "a message from request");
        // 向客户端添加 cookie
        Cookie cookie = new Cookie("cookie", "cookie");
        response.addCookie(cookie);
        return "forward:/success";
    }

    @GetMapping("/success")
    @ResponseBody
    public Map<String, Object> success(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        result.put("msg1", request.getAttribute("msg1"));
        result.put("msg2", request.getAttribute("msg2"));
        result.put("msg3", request.getAttribute("msg3"));
        return result;
    }
}

最终效果如下
在这里插入图片描述

五、参数类型转换器(Convert)

在 SpringBoot 中已经存在很多的参数类型转换器,例如:NumberToCharacterConverter(数字子类型到 Character 转换);当然我们可以给 WebDataBinder(数据绑定器)里面放自己的 Converter(转换器),实现参数类型转换;

需求:User 对象(String name, Integer age),将前端参数传递的 “name,age” 类型的字符串转化为 User 对象

  1. 在配置类中注册自定义类型转换器
@Configuration
public class AppConfig implements WebMvcConfigurer {
    /**
     * 自定义类型转换器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 把 "dufu,30" 这种格式字符串转化为 User 对象(name, age)
        Converter<String, User> userConverter = new Converter<String, User>() {
            @Override
            public User convert(String source) {
                if(!StringUtils.isEmpty(source)) {
                    String[] sourceArr = source.split(",");
                    User user = new User();
                    user.setName(sourceArr[0]);
                    user.setAge(Integer.parseInt(sourceArr[1]));
                    return user;
                }
                return null;
            }
        };
        registry.addConverter(userConverter);
    }
}
  1. 在 UserController.class 下的 saveUser() 方法中接收字符串参数并转化为 User 对象
@RestController
public class UserController {
    @GetMapping("/user/save")
    public User saveUser(User user) {
        return user;
    }
}

这里是 GET 请求,前端传递的实际上是字符串,通过类型转换器转化为对象后,返回给前端

  1. 测试一下,在浏览器访问:http://localhost:8080/user/save?user=dufu,30,得的返回值为 User 对象
    在这里插入图片描述

六、响应处理

  1. HttpMessageConverter 返回值类型转换器
    主要是将返回值转化为浏览器能接受处理的类型(MediaType);例如:将返回值 User 对象转化为 JSON 格式;默认的转换器有 10 个,当处理完业务逻辑返回处理结果给前端页面的时候,后端会从下面这 10 个转换器中遍历找出合适的转换器处理返回值

在这里插入图片描述
1.1 返回值为 XML 格式
在默认情况下,SpringBoot 会对所有添加了 @ResponseBody(或 @RestController) 注解的方法的返回值转化为 JSON 格式返回(转换器为上图的 MappingJackson2HttpMessageConverter);如果要把返回值设置为 XML 格式可按照如下步骤实现

1)在配置文件中引入支持 jackson-dataformat-xml 依赖

<dependency>
	<groupId>com.fasterxml.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2)在配置类中覆盖 MappingJackson2XmlHttpMessageConverter 转换器,因为 xml 格式返回值需要添加 xml 版本和字符集的声明

@Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter() {
	XmlMapper xmlMapper = new XmlMapper();
	XmlMapper.Builder builder = new XmlMapper.Builder(xmlMapper);
	// WRITE_XML_DECLARATION:<?xml version='1.0' encoding='UTF-8'?>
	// WRITE_XML_1_1:<?xml version='1.1' encoding='UTF-8'?>
	builder.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
			.defaultUseWrapper(false);
	return new MappingJackson2XmlHttpMessageConverter(builder.build());
}

3) 在 UserController.class 添加如下代码即可

@GetMapping(value = "/user", produces = MediaType.APPLICATION_XML_VALUE)
public User getUser() {
	User user = new User();
	user.setName("dufu");
	user.setAge(30);
	return user;
}

4) 测试最终效果如下
在这里插入图片描述
在浏览器中访问的时候,可以从请求头中看到 Accept 的值为下图所示
在这里插入图片描述
对于 application/xml 这种类型优先级更高,所以去掉 @GetMapping 注解的 produces = MediaType.APPLICATION_XML_VALUE 选项,浏览器端依然能拿到 XML 格式的返回值

如果实体类属性值和要求返回值属性不一致,可以通过在实体类属性上添加 @JacksonXmlProperty 注解指定返回值属性;例如:User 的属性 name,指定返回 XML 中属性为 userName;集合类型的返回值外层再嵌套一层父节点可使用 @JacksonXmlElementWrapper 注解

@Data
@JacksonXmlRootElement(localName = "response")
public class User {
    @JacksonXmlProperty(localName = "userName")
    private String name;
    private Integer age;
    @JacksonXmlElementWrapper(localName = "list")
    private List<String> appIds;
}

返回值如下
在这里插入图片描述

扩展

  1. 如何在返回 XML 头中追加 DTD 信息?

1)新建 DtdXMLSerializerProvider.class 继承 XmlSerializerProvider.class 并重写如下方法

public class DtdXMLSerializerProvider extends XmlSerializerProvider {
    private String dtd;

    public DtdXMLSerializerProvider(XmlSerializerProvider src, SerializationConfig config, SerializerFactory f, 
        String dtd) {
        super(src, config, f);
        this.dtd = dtd;
    }

    @Override
    protected void _initWithRootName(ToXmlGenerator xgen, QName rootName) throws IOException {
        super._initWithRootName(xgen, rootName);
        try {
            xgen.getStaxWriter().writeDTD(dtd);
        } catch (XMLStreamException e) {
            e.printStackTrace();
        }
    }

    @Override
    public DefaultSerializerProvider createInstance(SerializationConfig config, SerializerFactory jsf) {
        return new DtdXMLSerializerProvider(this, config, jsf, dtd);
    }
}

2)在配置类中设置 XML 序列化提供器支持

@Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter() {
	XmlMapper xmlMapper = new XmlMapper();
	// 追加 DTD 信息
	String dtd = "<!DOCTYPE gsafeed PUBLIC \"-//Google//DTD GSA Feeds//EN\" \"\">";
	DtdXMLSerializerProvider provider = new DtdXMLSerializerProvider(
			(XmlSerializerProvider) xmlMapper.getSerializerProvider(),
			xmlMapper.getSerializationConfig(),
			xmlMapper.getSerializerFactory(),
			dtd);
	xmlMapper.setSerializerProvider(provider);
	XmlMapper.Builder builder = new XmlMapper.Builder(xmlMapper);
	// WRITE_XML_DECLARATION:<?xml version='1.0' encoding='UTF-8'?>
	// WRITE_XML_1_1:<?xml version='1.1' encoding='UTF-8'?>
	builder.enable(ToXmlGenerator.Feature.WRITE_XML_1_1)
			.defaultUseWrapper(false);
	return new MappingJackson2XmlHttpMessageConverter(builder.build());
}

3)最终效果如下
在这里插入图片描述
2. 如何实现动态修改请求头返回不同格式数据?

如果不是通过 ajax 请求的方式(设置 content-type),直接在浏览器访问的 GET 请求无法设置请求头类型,那么可通过携带 format 参数的形式实现动态请求头功能;这个 format 参数是 ParameterContentNegotiationStrategy.class 中的属性

1)在 application.properties 配置文件中打开根据请求参数选择请求头的属性配置

# 开启请求参数内容协商机制(请求后带 format 参数的形式)
spring.mvc.contentnegotiation.favor-parameter = true

2)请求地址后添加参数 ?format=json 返回 json 格式返回值
在这里插入图片描述

3)请求地址后添加参数 ?format=xml 返回 XML 格式返回值
在这里插入图片描述
3. 自定义 MessageConverter
1)添加自定义返回值转换器 MyMessageConverter.class ,实现对 User 类型返回值的输出格式转换

public class MyMessageConverter implements HttpMessageConverter<Object> {
    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        return true;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return MediaType.parseMediaTypes("application/dufu");
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, 
        HttpMessageNotReadableException {
        // 此处可定义怎么读取返回值
        return null;
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, 
        HttpMessageNotWritableException {
        OutputStream body = outputMessage.getBody();
        if(o instanceof User) {
            User user = (User)o;
            StringBuilder strUser = new StringBuilder();
            strUser.append("name=")
                    .append(user.getName())
                    .append(";")
                    .append("age=")
                    .append(user.getAge())
                    .append(";")
                    .append("appIds=")
                    .append(StringUtils.join(user.getAppIds(), '/'));
            body.write(strUser.toString().getBytes());
        } else {
            body.write(o.toString().getBytes());
        }
    }
}

2)配置类 AppConfig.class 中注册转换器和指定内容协商策略

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MyMessageConverter());
    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        Map<String, MediaType> mediaTypes = new Hashtable<>();
        mediaTypes.put("json", MediaType.APPLICATION_JSON);
        mediaTypes.put("xml", MediaType.APPLICATION_XML);
        // 自定义的
        mediaTypes.put("dufu", MediaType.parseMediaType("application/dufu"));
        // 基于参数的内容协商策略
        ParameterContentNegotiationStrategy parameterContentNegotiationStrategy = 
            new ParameterContentNegotiationStrategy(mediaTypes);
        // 基于请求头的内容协商策略
        HeaderContentNegotiationStrategy headerContentNegotiationStrategy = 
            new HeaderContentNegotiationStrategy();
        // 把这两种策略都添加进去
        configurer.strategies(Arrays.asList(parameterContentNegotiationStrategy, headerContentNegotiationStrategy));
        WebMvcConfigurer.super.configureContentNegotiation(configurer);
    }
}

3)我们可以通过在 UserController.class 中指定请求头让此方法的返回值通过我们自定义的转换器转换返回

@RestController
public class UserController {
    @GetMapping(value = "/user", produces = "application/dufu")
    public User getUser() {
        User user = new User();
        user.setName("dufu");
        user.setAge(30);
        user.setAppIds(Arrays.asList("A", "B", "C"));
        return user;
    }
}

如果在 application.properties 配置文件中开启了请求参数内容协商机制,可以在请求地址后通过参数 ?format=dufu 的形式访问(但 @GetMapping 注解的 produces 属性要去掉)

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

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

相关文章

概论_第7章_参数估计_真题__求置信区间

真题 2014.10 第30题 测量某物体的质量9次&#xff0c; 测得平均值 x‾15.4\overline x 15.4x15.4 g, 已知测量数据 XXX ~ N(μ,0.09)N(\mu, 0.09)N(μ,0.09) (1) 求该物体质量的置信度为0.95 的置信区间&#xff1b; &#xff08;2&#xff09;为了使置信度为0.95 的置信区间…

20 堆排序

文章目录1 堆排序的概念2 堆排序基本思想3 堆排序步骤图解说明4 堆排序的代码实现1 堆排序的概念 1) 堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为 O(nlogn)&#xf…

Spring中BeanPostProcessor与循环依赖的问题

Spring中后置处理器与循环依赖的问题 在Spring的bean生命周期中, 我们可以通过实现BeanPostProcessor来对bean初始化前后做操作, 在网上的许多帖子博客中, 不乏可以看见说Spring的AOP是在后置处理器中实现的, 这个理解显然有失偏颇, 很容易误导一般人在后置处理器中对原先的be…

Android 一帧绘制流程分析笔记

和你一起终身学习&#xff0c;这里是程序员Android经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点:一、显示一帧流程概览二、生产者&#xff0c;消费者 BufferQueue 流转图三、App &#xff0c;SF Buffer 交互图四、SF 跟 HWC 交互图一、显示一帧流程概览…

16.CSS中使用颜色

使用颜色 在计算机中&#xff0c;传统的模型之一为RGB模型&#xff0c;所有颜色都是通过红色、蓝色、绿色三种颜色进行组合&#xff1b;我们通过数值去表示 例如&#xff1a; 红色&#xff08;255.0.0&#xff09;、蓝色&#xff08;0.0.255&#xff09;、绿色&#xff08;0.…

在IDEA中配置jeesite-(文章链接汇总)

建议按照文章顺序操作 原文里可以下载geesite项目 jeesite-github原文链接 jeesite-gitee原文链接–国内推荐 可 直 接 跳 到 此 步 骤 环境准备&#xff1a;JDK 1.8 or 11、17、Maven 3.6、使用 MySQL 5.7 or 8.0 数据库 1-Maven的下载安装配置教程&#xff08;详细图文&am…

Vue3之循环渲染

1.何为循环渲染 在Vue3中&#xff0c;当我们需要渲染一个数组中的数据到dom元素上时&#xff0c;就需要使用循环渲染。循环渲染可以节约我们大量重复冗余的工作&#xff0c;比如我们去渲染一个下拉菜单的时候&#xff0c;如果不使用循环渲染&#xff0c;那么我们需要手动一项一…

2023美赛C代码思路结果【全部更新完毕】注释详尽

C题已完成全部代码&#xff0c;注释详尽&#xff0c;并增加扰动项&#xff0c;保证大家的结果不会撞 需要全部问题的可以点击&#xff1a;https://www.jdmm.cc/file/2708697/ 下面贴出核心代码&#xff1a; -- coding: utf-8 -- TODO: 入口函数 import numpy as np from…

Mr. Cappuccino的第43杯咖啡——Kubernetes之Pod控制器(二)

Kubernetes之Pod控制器Horizontal Pod Autoscaler&#xff08;HPA&#xff09;安装metrics-server创建Pod创建HPA压力测试JobCronJobHorizontal Pod Autoscaler&#xff08;HPA&#xff09; 上篇文章中所说的ReplicaSet和Deployment&#xff0c;我们已经可以通过手动执行kubec…

Shiro1.9学习笔记

文章目录一、Shiro概述1、Shiro简介1.1 介绍1.2 Shiro特点2、Shiro与SpringSecurity的对比3、Shiro基本功能4、Shiro原理4.1 Shiro 架构(外部)4.2 shiro架构(内部)二、Shiro基本使用1、环境准备2、登录认证2.1 登录认证概念2.2 登录认证基本流程2.3 登录认证实例2.4 身份认证源…

WordPress网站伪静态及固定链接设置教程

WordPress网站伪静态及固定链接设置教程-解决404错误问题!搭建好WordPress网站之后我个人建议首先要做的就是设置好固定链接&#xff0c;WordPress的固定链接也就是网站各个页面的链接格式&#xff0c;默认的方式不太符合现代化网站&#xff0c;推荐使用自定义的方案。既然涉及…

良许翻天覆地的2022年

大家好&#xff0c;我是良许&#xff0c;新年快乐呀~ 在我女室友坚持不懈的努力之下&#xff0c;2022年的最后一天我终于被她传染了&#xff0c;阳了~ 此时的我&#xff0c;正顶着37多度的低烧写下这篇年终总结。 2022年&#xff0c;对于大多数人而言&#xff0c;封控是主旋…

Git使用小乌龟克隆与推送代码Gitee--零命令行(组员版本)

目录 上一篇文章&#xff08;必读&#xff01;&#xff01;&#xff01;&#xff09; 概述 分支概念&#xff08;权限分配&#xff09;&#xff1a; 总体操作思想&#xff1a; 操作步骤 一、组员第一天上班&#xff08;云端仓库代码克隆到本地仓库进行代码编写&#xff…

网日志处理中的应用架构-《大数据时代的IT架构设计》

用户的上网行为中蕴含着大量的客户特征和客户需求信息&#xff0c;这些信息至关重要,这就要求用户的上网日志记录必须被保存&#xff0c;而且还需要进行数据分析挖掘处理&#xff0c;然后根据处理结果定义用户的行为习惯&#xff0c;为电信运营商实现精细化运营提供重要的营销依…

【数据库】Clickhouse 实践之路

文章目录背景Clickhouse简介为什么选择ClickhouseClickhouse特性Clickhouse建设整体架构数据接入层数据存储层数据服务层数据应用层Clickhouse运维管理平台配置文件结构元数据管理自动化运维用户管理集群操作监控与报警Clickhouse应用BI查询引擎核心诉求选型对比集群构建问题及…

基于jeecgboot的flowable流程设计器的几个bug修复

因为今天在用任务监听器的时候&#xff0c;出现几个bug&#xff0c;所以一并修复与处理。 一、建立任务监听器后&#xff0c;删除不了 主要有两个原因&#xff0c;一个是点击删除没反应&#xff0c;实际上是弹出框跑到后面去了&#xff0c;说明还是z-index问题&#xff0c;调整…

.Net Core中使用NEST简单操作Elasticsearch

C#中访问Elasticsearch主要通过两个包NEST和Elasticsearch.Net&#xff0c;NEST用高级语法糖封装了Elasticsearch.Net可以通过类Linq的方式进行操作&#xff0c;而Elasticsearch.Net相比之下更为原始直接非常自由。注意&#xff1a;ES的8.X以上的版本有新的包Elastic.Clients.E…

二极管的“几种”应用

不知大家平时有没有留意&#xff0c;二极管的应用范围是非常广的&#xff0c;下面我们来看看我想到几种应用&#xff0c;也可以加深对电路设计的认识&#xff1a; A&#xff0c;特性应用&#xff1a; 由于二极管的种类非常之多&#xff0c;这里这个大类简单罗列下&#xff1a…

SpringCloud Alibaba集成Dubbo实现远程服务间调用

SpringCloud Alibaba集成Dubbo实现远程服务间调用 工程创建 一、创建springBoot分模块项目&#xff0c;父工程&#xff1a;springcloud-alibaba以及子模块product-dubbo-provider、order-dubbo-consumer等 项目基本结构图如下所示&#xff1a; 二、依赖引入 在以上两个子模块…

数值方法笔记1:数字表示与误差分析

1 有意义数位概念与有意义数位损失1.1 怎么分析误差2 逼近阶 与渐近记法3 误差传播与稳定性1 有意义数位概念与有意义数位损失 整数的二进制表示使用短除法&#xff0c;网上有很多文章&#xff0c;这里就不再过多赘述了。 提一嘴小数的二进制表示。下面列举了一个例子。 在表…