SpringBoot 请求参数处理详解

news2025/1/12 13:14:21

目录

请求参数处理

0、请求映射

1、rest使用与原理

1、普通参数与基本注解

1.1、注解: 

1.2、Servlet API:

1.3、复杂参数:

1.4、自定义对象参数:

2、POJO封装过程

3、参数处理原理

1、HandlerAdapter

2、执行目标方法

3、参数解析器-HandlerMethodArgumentResolver

4、返回值处理器

5、如何确定目标方法每一个参数的值

额外:自定义 Converter


请求参数处理

0、请求映射

1、rest使用与原理

  • @xxxMapping;
  • Rest风格支持(使用HTTP请求方式动词来表示对资源的操作
    • 以前:/getUser   获取用户  /deleteUser 删除用户   /editUser  修改用户   /saveUser 保存用户
    • 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
//    @GetMapping("/user") 作用同下,下同
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    public String getUser(){
        return "GET-张三";
    }

    //    @PostMapping("/user")
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String saveUser(){
        return "POST-张三";
    }

    //    @PutMapping("/user")
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String putUser(){
        return "PUT-张三";
    }
    //    @DeleteMapping("/user")
    @RequestMapping(value = "/user",method = RequestMethod.DELETE)
    public String deleteUser(){
        return "DELETE-张三";
    }
    • 核心Filter;HiddenHttpMethodFilter
      • 用法: 表单只能发送get和post请求,那么怎么发送post和delete请求呢?表单发送方式method=post,带上一个隐藏域 _method=put

WebMvcAutoConfiguration中是否通过hiddenHttpMethodFilter来进行表单提交方式的验证默认是false不开启

手动开启页面表单的Rest功能 

 

  • 扩展:如何把_method 这个名字换成我们自己喜欢的。

WebMvcAutoConfiguration中因为我们没有HiddenHttpMethodFilter这个过滤器,所以为我们new了一个,而HiddenHttpMethodFilter内部的DEFAULT_METHOD_PARAM就是被设置为"_method"

 

 因此我们自己写一个HiddenHttpMethodFilter来修改这个参数

@Configuration(proxyBeanMethods = false)
public class WebConfig {

    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        hiddenHttpMethodFilter.setMethodParam("_m");
        return hiddenHttpMethodFilter;
    }
}

===================index.html=================
<form method="post" action="/user">
<!--    <input type="hidden" name="_method" value="DELETE"/>-->
    <input type="hidden" name="_m" value="DELETE"/>
    <input type="submit" value="post-保存用户"/>
</form>

Rest原理(表单提交要使用REST的时候)
●表单提交会带上_method=PUT
●请求过来被HiddenHttpMethodFilter拦截
○请求是否正常,并且是POST
        ■获取到_method的值。


        ■兼容以下请求;PUT、DELETE、PATCH

ALLOWED_METHODS.contains(method)代表是不是兼容的网页请求方式

        ■原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。


        ■过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。

Rest使用客户端工具
●如PostMan直接发送Put、delete等方式请求,无需Filter。

1、普通参数与基本注解

1.1、注解: 

 @PathVariable、@RequestHeader,点进这两个注解,都可以看到以下这段注释

意思是可以在参数中使用一个Map<String, String> 用对应的注解标记,那么它会帮将所有的参数放进去,比如PathVariable会将所有的路径变量放进对应的map,而RequestHeader则是将所有的headers信息全部放进map中

@RestController
public class ParameterTestController {

    @GetMapping("/car/{id}/user/{name}")
    public Map<String, Object> getCar(@PathVariable("id") Integer id,
                                      @PathVariable("name") String name,
                                      @PathVariable Map<String, String> pv,
                                      @RequestHeader("User-Agent") String useragent,
                                      @RequestHeader Map<String, String> headers) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("name", name);
        map.put("pv", pv);
        map.put("user-agent", useragent);
        map.put("headers", headers);

        return map;


    }
}

 @RequestParam

    @GetMapping("/like")
    public Map<String, Object> getCar(@RequestParam("age") Integer age,
                                      @RequestParam("hobby") List<String> hobby) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("age", age);
        map.put("hobby", hobby);
        return map;
    }

@RequestBody 

    @PostMapping("/save")
    public Map<String, Object> save(@RequestBody String content) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("content", content);
        return map;
    }

 @RequestAttribute 获取request域属性

@Controller
public class RequestAttributeTestController {

    @GetMapping("/goto")
    public String gotoPage(HttpServletRequest request) {
        request.setAttribute("msg","页面转发成功");
        return "forward:/success";
    }

    @ResponseBody
    @GetMapping("/success")
    public Map<String, Object> success(HttpServletRequest request,
                                    @RequestAttribute("msg") String msg) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("req",msg);
        String msg1 = (String) request.getAttribute("msg");
        map.put("anno", msg1);
        return map;
    }

}

 

@MatrixVariable  矩阵变量,SpringBoot默认关闭,需要手动开启。在WebMvcAutoConfiguration有一个方法configurePathMatch()设置了UrlPathHelper

在 UrlPathHelper有一个变量removeSemicolonContent控制着矩阵变量的开启,意思是移除分号内容,默认为true,所以为了开启,我们需要自定义

 可以在配置类中继承WebMvcConfigurer重载configurePathMatch方法,我们为其安上UrlPathHelper,也可以创建一个WebMvcConfigurer放入容器

@Configuration(proxyBeanMethods = false)
public class WebConfig /*implements WebMvcConfigurer*/ {

    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        hiddenHttpMethodFilter.setMethodParam("_m");
        return hiddenHttpMethodFilter;
    }

//    @Override
//    public void configurePathMatch(PathMatchConfigurer configurer) {
//        UrlPathHelper urlPathHelper = new UrlPathHelper();
//        urlPathHelper.setRemoveSemicolonContent(false);
//        configurer.setUrlPathHelper(urlPathHelper);
//    }
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }
        };
    }


}

    //1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
    //2、SpringBoot默认是禁用了矩阵变量的功能
    //      手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
    //              removeSemicolonContent(移除分号内容)支持矩阵变量的
    //3、矩阵变量必须有url路径变量才能被解析
    @GetMapping("/cars/{path}")
    public Map carsSell(@MatrixVariable("low") Integer low,
                        @MatrixVariable("brand") List<String> brand,
                        @PathVariable("path") String path){
        Map<String,Object> map = new HashMap<>();

        map.put("low",low);
        map.put("brand",brand);
        map.put("path",path);
        return map;
    }

    // 两个矩阵变量就使用pathvar
    // /boss/1;age=20/2;age=10

    @GetMapping("/boss/{bossId}/{empId}")
    public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
                    @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
        Map<String,Object> map = new HashMap<>();

        map.put("bossAge",bossAge);
        map.put("empAge",empAge);
        return map;

    }

矩阵变量的作用:

当cookie被禁用后,如何使用session的内容?

因为session.getAttribute实际上流程是

session.set(a,b)---> jsessionid ---> cookie ----> 每次发请求携带ur1重写:所以cookie禁用后无法找到session

解决方法:

/abc;jsesssionid=xxxx 把cookie的值使用矩阵变量的方式进行传递

1.2、Servlet API:

WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId

@Override
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType();
		return (WebRequest.class.isAssignableFrom(paramType) ||
				ServletRequest.class.isAssignableFrom(paramType) ||
				MultipartRequest.class.isAssignableFrom(paramType) ||
				HttpSession.class.isAssignableFrom(paramType) ||
				(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
				Principal.class.isAssignableFrom(paramType) ||
				InputStream.class.isAssignableFrom(paramType) ||
				Reader.class.isAssignableFrom(paramType) ||
				HttpMethod.class == paramType ||
				Locale.class == paramType ||
				TimeZone.class == paramType ||
				ZoneId.class == paramType);
	}

ServletRequestMethodArgumentResolver 以上的部分参数

 

1.3、复杂参数:

MapModel(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder

Map<String,Object> map,  Model model, HttpServletRequest request 都是可以给request域中放数据,
request.getAttribute();

 

Map、Model类型的参数,会返回 mavContainer.getModel();---> BindingAwareModelMap 是Model 也是Map

mavContainer.getModel(); 获取到值的

1.4、自定义对象参数:

可以自动类型转换与格式化,可以级联封装。

/**
 *     姓名: <input name="userName"/> <br/>
 *     年龄: <input name="age"/> <br/>
 *     生日: <input name="birth"/> <br/>
 *     宠物姓名:<input name="pet.name"/><br/>
 *     宠物年龄:<input name="pet.age"/>
 */
@Data
public class Person {
    
    private String userName;
    private Integer age;
    private Date birth;
    private Pet pet;
    
}

@Data
public class Pet {

    private String name;
    private String age;

}

result

 

2、POJO封装过程

  • ServletModelAttributeMethodProcessor

3、参数处理原理

我们首先在DispatcherServlet的doDispatch方法这打断点

  • HandlerMapping中找到能处理请求的Handler(Controller.method())
  • 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter
  • 适配器执行目标方法并确定方法参数的每一个值

1、HandlerAdapter


0 - 支持方法上标注@RequestMapping
1 - 支持函数式编程的
xxxxxx


2、执行目标方法

// Actually invoke the handler.
//DispatcherServlet -- doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法


//ServletInvocableHandlerMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

3、参数解析器-HandlerMethodArgumentResolver

确定将要执行的目标方法的每一个参数的值是什么;

SpringMVC目标方法能写多少种参数类型。取决于参数解析器。

 

  • 当前解析器是否支持解析这种参数
  • 支持就调用 resolveArgument

4、返回值处理器

5、如何确定目标方法每一个参数的值

============InvocableHandlerMethod==========================
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}

		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}

5.1、挨个判断所有参数解析器那个支持解析这个参数

	@Nullable
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

 5.2、解析这个参数的值

调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可

 

5.3、自定义类型参数 封装POJO

ServletModelAttributeMethodProcessor 这个参数处理器支持解析POJO类参数

是否为简单类型。

public static boolean isSimpleValueType(Class<?> type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}

 

@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

		String name = ModelFactory.getNameForParameter(parameter);
		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
		if (ann != null) {
			mavContainer.setBinding(name, ann.binding());
		}

		Object attribute = null;
		BindingResult bindingResult = null;

		if (mavContainer.containsAttribute(name)) {
			attribute = mavContainer.getModel().get(name);
		}
		else {
			// Create attribute instance
			try {
				attribute = createAttribute(name, parameter, binderFactory, webRequest);
			}
			catch (BindException ex) {
				if (isBindExceptionRequired(parameter)) {
					// No BindingResult parameter -> fail with BindException
					throw ex;
				}
				// Otherwise, expose null/empty value and associated BindingResult
				if (parameter.getParameterType() == Optional.class) {
					attribute = Optional.empty();
				}
				bindingResult = ex.getBindingResult();
			}
		}

		if (bindingResult == null) {
			// Bean property binding and validation;
			// skipped in case of binding failure on construction.
			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
			if (binder.getTarget() != null) {
				if (!mavContainer.isBindingDisabled(name)) {
					bindRequestParameters(binder, webRequest);
				}
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new BindException(binder.getBindingResult());
				}
			}
			// Value type adaptation, also covering java.util.Optional
			if (!parameter.getParameterType().isInstance(attribute)) {
				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
			}
			bindingResult = binder.getBindingResult();
		}

		// Add resolved attribute and BindingResult at the end of the model
		Map<String, Object> bindingResultModel = bindingResult.getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return attribute;
	}

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);

WebDataBinder :web数据绑定器,将请求参数的值绑定到指定的JavaBean里面

WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中

GenericConversionService:在设置每一个值的时候,找它里面的所有converter那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean -- Integer)

byte -- > file

@FunctionalInterface public interface Converter<S, T>

未来我们可以给WebDataBinder里面放自己的Converter;

private static final class StringToNumber<T extends Number> implements Converter<String, T>

额外:自定义 Converter

    //1、WebMvcConfigurer定制化SpringMVC的功能
    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                // 不移除;后面的内容。矩阵变量功能就可以生效
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }

            @Override
            public void addFormatters(FormatterRegistry registry) {
                registry.addConverter(new Converter<String, Pet>() {

                    @Override
                    public Pet convert(String source) {
                        // 啊猫,3
                        if(!StringUtils.isEmpty(source)){
                            Pet pet = new Pet();
                            String[] split = source.split(",");
                            pet.setName(split[0]);
                            pet.setAge(Integer.parseInt(split[1]));
                            return pet;
                        }
                        return null;
                    }
                });
            }
        };
    }

 

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

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

相关文章

maplab2.0安装

项目链接: GitHub - ethz-asl/maplab: An open visual-inertial mapping framework. 安装流程很简单.按照github流程安装就行,建议使用脚本自动安装, 安装指南: https://maplab.asl.ethz.ch/docs/master/pages/installation/A_Installation-Ubuntu.html 值得注意的点包括: 1…

【阶段二】Python数据分析数据可视化工具使用03篇:词云图与相关性热力图

本篇的思维导图: 词云图 词云图(word cloud chart)是通过使每个字的大小与其出现频率成正比,显示不同单词在给定文本中的出现频率,然后将所有的字词排在一起,形成云状图案,也可以任何格式排列:水平线、垂直列或其他形状,也可用于显示获分配元数据的单词。在词云…

2022 OpenMLDB 硕果累累,颁奖台上荣耀连连

岁末年初&#xff0c; 既是回望过去和规划未来的日子&#xff0c; 也是总结成长与收获成果的时间。 2022 年即将结束之际&#xff0c; OpenMLDB 在颁奖台上惊喜连连&#xff0c; 获得了 IT168 和 中国开源云联盟 的认可。 技术改变世界&#xff0c;创新引领未来。业界知名 IT…

Redis缓存穿透、缓存击穿、缓存雪崩详解

缓存处理流程接收到查询数据请求时&#xff0c;优先从缓存中查询&#xff0c;若缓存中有数据&#xff0c;则直接返回&#xff0c;若缓存中查不到则从DB中查询&#xff0c;将查询的结果更新到缓存中&#xff0c;并返回查询结果&#xff0c;若DB中查不到&#xff0c;则返回空数据…

PSR规范

PSR规范 PSR 不是PHP官方标准&#xff0c;而是从如Zend、Symfony2等知名PHP项目中提炼出来的一系列标准&#xff0c;目前有越来越多的社区项目加入并遵循该标准。 PSR-0 自动加载 X已废弃 PSR-1 基本代码规范 PSR-2 代码样式 PSR-3 日志接口 PSR-4 如何指定文件路径从而自动加载…

怎么搭建自己的网站赚钱,个人网站怎么操作

大家好&#xff0c;我是蝶衣王的小编接触过互联网的应该很多都想过能不能搭建自己的网站赚钱&#xff0c;无论是用来带货&#xff0c;引流&#xff0c;还是做广告都会是一笔不错的收入&#xff0c;而且网站做好之后打理起来简单&#xff0c;后期工作量也是比较小的&#xff0c;…

【论文简述】Vis-MVSNet: Visibility-Aware Multi-view Stereo Network(IJCV 2022)

一、论文简述 1. 第一作者&#xff1a;Jingyang Zhang 2. 发表年份&#xff1a;2022 3. 发表期刊&#xff1a;IJCV、BMVC 4. 关键词&#xff1a;MVS、可见性、MVSNet 5. 探索动机&#xff1a;MVS的可见性 One critical factor in MVS is the pixel-wise visibility: whet…

Clion配置导致中文乱码问题 char长度限制导致中文乱码问题

&#x1f370; 个人主页:__Aurora__ &#x1f35e;如果文章有什么需要改进的地方还请各位大佬指正。 &#x1f349;如果我的文章对你有帮助➡️ 关注&#x1f64f;&#x1f3fb; 点赞&#x1f44d; 收藏⭐️ 问题1&#xff1a;中文乱码问题&#xff08;配置原因&#xff09; #…

【Linux】复制进程、了解逻辑地址以及写实拷贝

目录 fork()方法原型 父子进程 父子进程的pid 物理地址和逻辑地址 写实拷贝 fork()方法原型 pid_t fork(void); pid_t是int类型代表进程的pid号 Linux内核2.4.0定义&#xff1a; typedef int __kernel_pid_t; typedef __kernel_pid_t pid_t; 每一个进程的pid都是唯一…

MySQL多实例管理(mysqld_multi)

定义&#xff1a;就是在一台mysql机器上开启多个不同的服务端口&#xff08;如&#xff1a;3306,3307&#xff09;&#xff0c;运行多个MySQL服务进程&#xff0c;通过不同的socket监听不同的服务端口来提供各自的服务 1.MySQL多实例介绍 1.1.什么是MySQL多实例 MySQL多实例就…

移动智能终端安全技术要求及测试评价方法

声明 本文是学习移动智能终端安全技术要求及测试评价方法. 下载地址 http://github5.com/view/627而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 移动智能终端测试评价方法 硬件安全 硬件安全的测试方法、预期结果和结果判定如下&#xff1a; a&am…

版本控制 | 一文了解虚拟制作,进入影视制作新赛道

作为一种能够引领未来趋势&#xff0c;颠覆影视制作流程的全新技术&#xff0c;虚拟制作已经慢慢普及到影视制作领域。嗅觉灵敏的资本和目光前瞻的大厂纷纷布局虚拟制作赛道。阅读本篇文章&#xff0c;您将了解到什么是虚拟制作&#xff0c;它的优势所在、如何开展虚拟制作以及…

SpreadJS 16.0.1 中英版 SpreadJS-EN-CN

SpreadJS具有 500 多个 Excel 函数的完整 Angular 电子表格解决方案 快速提供真正类似 Excel 的电子表格体验 - 对 Excel 零依赖。创建财务报告和仪表板,预算和预测模型&#xff0c;科学&#xff0c;工程&#xff0c;卫生保健,教育,科学实验室和更多。 Ω578867473创建自定义电…

【MySQL数据库入门】:库的操作

文章目录库的操作1 创建数据库2 创建数据库案例3 字符集和校验规则3.1 查看系统默认字符集以及校验规则3.2 查看数据库支持的字符集3.3 查看数据库支持的字符集校验规则3.4 校验规则对数据库的影响4 操纵数据库4.1 查看数据库4.2 显示创建语句4.3 修改数据库4.4 数据库删除4.5 …

时序预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测 目录时序预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现SSA-CNN-GRU麻雀算法优化卷…

js写的一个简单的时间范围日历

该日历主要是提供一个思路&#xff0c;用以抛砖引玉 该日历从移动端更改而来&#xff0c;所以看着会比较小 日历中基于flex布局&#xff0c;全部使用div模拟 table 来实现&#xff0c;没有用 table 来布局 日历的周次列是固定的&#xff0c;这是基于自己需求来设定的&#x…

平台统一监控的介绍和调研

背景 目前平台缺少强有力的监控工具&#xff0c;单独依靠Spring Boot Admin 还太欠缺&#xff0c;没有大屏、没有分布式链路追踪、自定义告警繁琐&#xff0c;在我的《Spring Boot Admin2》专栏中自定义过JVM监控和异常监控&#xff0c;都需要自己编码定义监控规则和告警&…

OSPF综合实验

1.首先把IP跟环回配上 [R4]int g 0/0/0 [R4-GigabitEthernet0/0/0]ip add 12.1.1.2 24 [R4-GigabitEthernet0/0/0]int g 0/0/2 [R4-GigabitEthernet0/0/2]ip add 32.1.1.2 24 [R4-GigabitEthernet0/0/2]int g 0/0/1 [R4-GigabitEthernet0/0/1]ip add 22.1.1.2 24 [R4-GigabitE…

SRM系统如何应对数字化浪潮,打造万商互联

近几年&#xff0c;大量的大中型企业开始了数字化的采购管理&#xff0c;这意味着从传统的采购方式转向了数字化的采购&#xff0c;从根本上改变了传统的采购方式&#xff0c;实现了对采购系统的优化重组&#xff0c;是战略和战术体系的系统化变革&#xff0c;也为采购数智化、…

STM32 DMA编程时的一个应用小提醒

有人使用STM32H7芯片做些事情&#xff0c;发现基于ST公司的HAL库开发UART1的DMA收发时可以轻松实现&#xff0c;而当使用ST的LL库组织代码时&#xff0c;却没法实现UART的DMA传输。感觉上就是使用HAL库编写代码功能正常而基于LL库则不行。真是这样吗&#xff1f;使用STM32CubeM…