手写Spring-MVC之前后置处理器与异常处理、数据库框架
Day48
手写Spring-MVC之前后置处理器与异常处理
前后置处理器
概念:从服务器获取的JSON数据可能是加密后的,因此服务端获取的时候需要进行解密(前置处理器)。
而从服务器传出的JSON数据可能需要加密,因此需要在处理返回值的时候进行加密(后置处理器)。
思路:
首先搭建前后置处理器的框架:
和是否处理JSON格式的数据类似,需要根据注解判断controller层中的方法是否需要对JSON格式的数据进行解密或者返回数据进行加密,因此要添加两个注解@BeforeAdviser和@AfterAdviser
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface BeforeAdviser { }@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AfterAdviser { }
controller层的方法需要添加相应的注解标识
/*** 使用postman发送请求* url:http://localhost:8080/user/test12.action* json:{"username":"zs","password":"123123"}* 传递JSON参数和返回JSON*/@RequestMapping("/test12.action")@ResponseBody@AfterAdviserpublic User test12(@RequestBody @BeforeAdviser User user){System.out.println("user对象:"+ user);return user;
同时需要在参数描述类中和方法描述类中添加是否有相应注解的属性:
/*** 参数描述类 */ @NoArgsConstructor @AllArgsConstructor @Data public class ParameterDefinition {private String name;//参数名private Class<?> clazz;//参数类型private int index;//参数下标private Type[] actualTypeArguments;//参数泛型的数组private boolean requestBodyHasOrNot;//参数上是否有@RequestBody注解private boolean beforeAdviserHasOrNot;//参数上是否有@BeforeAdviser注解}/*** 方法描述类 */ @NoArgsConstructor @AllArgsConstructor @Data public class MethodDefinition {private String requestMappingPath;//子级URiprivate String name;//方法名private Method method;//方法对象private Class<?> returnClazz;//返回值类型private List<ParameterDefinition> parameterDefinitions;//参数描述类对象的集合private boolean responseBodyHasOrNot;//方法上是否有@ResponseBody注解private boolean afterAdviserHasOrNot;//方法上是否有@AfterAdviser注解 }
添加后监听器中封装部分也要进行相应修改:
//获取参数上是否有@BeforeAdviser注解 boolean beforeAdviserHasOrNot = false; BeforeAdviser beforeAdviser = parameters[i].getAnnotation(BeforeAdviser.class); if(beforeAdviser!=null){beforeAdviserHasOrNot = true; }ParameterDefinition parameterDefinition = new ParameterDefinition(parameterName, parameterType, index,actualTypeArguments,requestBodyHasOrNot,beforeAdviserHasOrNot);//封装参数描述类对象 parameterList.add(parameterDefinition);
//获取方法上是否有@AfterAdviser注解 boolean afterAdviserHasOrNot = false; AfterAdviser afterAdviser = method.getAnnotation(AfterAdviser.class); if(afterAdviser!=null){afterAdviserHasOrNot = true; } MethodDefinition methodDefinition = new MethodDefinition(sonUri, methodName, method, returnType, parameterList,responseBodyHasOrNot,afterAdviserHasOrNot);//封装方法描述类对象
至此,监听器就能把信息记录下来,调度的DispatcherServlet进行工作的时候就可以获取到相应的注解信息。
前置处理器的使用是在获取参数类型的时候会判断是否有@BeforeAdviser注解,如果有则代表需要进行解密操作:
//解密 if(parameterDefinition.isBeforeAdviserHasOrNot()){//在这里进行具体的解密操作吗? }
在处理返回值的时候会判断方法是否有@AfterAdviser注解,如果有则代表需要进行加密操作:
//加密 if(methodDefinition.isAfterAdviserHasOrNot()){//在这里进行加密操作吗? }
进行具体的解密和加密操作:
前后置处理器的框架搭建好之后,会发现一个问题,如果在DispatcherServlet中进行具体的解密加密的话,那么在用户使用该框架的时候,就只能使用框架所规定的解密加密,这显然不具有灵活性。不同的用户解密、加密逻辑不同,所以这里的思路是在框架中只写抽象类,在DispatcherServlet中利用多态创建抽象类的继承类对象,调用继承类对象中的解密加密方法。而在web模块中用户可以自己重写一个解密加密抽象方法,这样调用的就是用户自定义的逻辑方法了。
抽象方法:
public abstract class HanderAdviserResolver {public abstract String beforeRequestBody(String reqData);public abstract String afterResponseBody(String respData);public String before(String reqData){return beforeRequestBody(reqData);}public String after(String respData){return afterResponseBody(respData);} }
注意:这里的抽象方法是交给用户重写的,而自己的成员方法则直接调用抽象方法,通过这种方式实现在DispatcherServlet中调用用户重写方法的逻辑。
用户自定义前后置处理器:
public class BeforeAndAfterAdviser extends HanderAdviserResolver {@Overridepublic String beforeRequestBody(String reqData) {System.out.println("解密:"+reqData);return reqData;}@Overridepublic String afterResponseBody(String respData) {System.out.println("加密:"+respData);return respData;} }
又一个问题来了,框架中怎样拿到用户自定义的类对象呢?思路和监听器拿到controller层类对象相似,通过配置文件拿到注解类,注解类通过一个注解注明用户自定义的前后置处理器路径。这样的注解叫做使能注解,它的功能就是使得DispatcherServlet能够拿到用户自定义类。然后在DispatcherServlet中重写init()方法,在方法中获取配置文件信息,进而拿到注解类,通过注解类的注解信息拿到自定义前后置处理器类对象,调用其重写的解密加密处理方法。
使能注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EnableAdviser {String adviserPackage(); }
注解类:
@EnableAdviser(adviserPackage= "com.qf.shop.web.adviser.BeforeAndAfterAdviser")
DispatcherServlet中:
private HanderAdviserResolver adviserResolver;public HanderAdviserResolver getAdviserResolver(String config){try {Class<?> clazz = Class.forName(config);EnableAdviser enableAdviserAnnotation = clazz.getAnnotation(EnableAdviser.class);String adviserPackage = enableAdviserAnnotation.adviserPackage();if(adviserPackage!=null){Class<?> adviserClass = Class.forName(adviserPackage);adviserResolver = (HanderAdviserResolver) adviserClass.newInstance();}return adviserResolver;} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}}@Overridepublic void init() throws ServletException {ServletContext servletContext = this.getServletContext();String config = servletContext.getInitParameter("config");adviserResolver = getAdviserResolver(config);}
//加密 if(methodDefinition.isAfterAdviserHasOrNot()){jsonString = adviserResolver.after(jsonString); }
//解密 if(parameterDefinition.isBeforeAdviserHasOrNot()){jsonStr = adviserResolver.before(jsonStr); }
异常
概念:DispatcherServlet中对于全局的异常需要进行处理,而具体如何处理也是由业务决定的,换言之是用户进行定义而非框架中写死。但是框架中又需要调用处理异常的方法,如何处理?-和前后置处理器一样,通过多态,servlet调用的是用户继承框架中抽象类的类重写的方法。
抽象类:
public abstract class HanderGlobalException {public abstract void handlerException(Exception err, HttpServletRequest request, HttpServletResponse response);public void hander(Exception err, HttpServletRequest request, HttpServletResponse response){handlerException(err,request,response);} }
用户继承类:
public class GlobalException extends HanderGlobalException {@Overridepublic void handlerException(Exception err, HttpServletRequest request, HttpServletResponse response) {System.out.println("处理全局异常......");try {request.getRequestDispatcher("/err.jsp").forward(request,response);} catch (ServletException | IOException e) {throw new RuntimeException(e);}} }
那么框架如何拿到用户自己写的处理异常类和方法呢?思路和前后置处理器一样,DispactherServlet在重写的init()方法中通过配置文件拿到配置类,配置类通过框架中写的使能注解将用户自定义的异常处理类路径告诉servlet。
使能注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EnableException {String exceptionPackage(); }
配置类:
/*** 当前项目的配置类 */ @Configuration("com.qf.shop.web.controller") @EnableAdviser(adviserPackage= "com.qf.shop.web.adviser.BeforeAndAfterAdviser") @EnableException(exceptionPackage = "com.qf.shop.web.globalException.GlobalException") public class AppConfig { }
DispatcherServlet:
private HanderGlobalException globalException;public HanderGlobalException getGlobalException(String config){try {Class<?> clazz = Class.forName(config);EnableException enableExceptionAnnotation = clazz.getAnnotation(EnableException.class);String exceptionPackage = enableExceptionAnnotation.exceptionPackage();if(exceptionPackage!=null){Class<?> exceptionClass = Class.forName(exceptionPackage);globalException = (HanderGlobalException) exceptionClass.newInstance();}return globalException;} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);} }@Overridepublic void init() throws ServletException {ServletContext servletContext = this.getServletContext();String config = servletContext.getInitParameter("config");adviserResolver = getAdviserResolver(config);globalException = getGlobalException(config);}
try{//调用Controller层里的某个方法Object returnVal = method.invoke(t, args);if(returnVal!=null){//处理返回值handlerReturnVal(methodDefinition,returnVal,request,response,model);} }catch (Exception e){globalException.hander(e,request,response);//处理全局异常 }
数据库模块
功能:该模块不是Spring-MVC中的一部分,是用来和数据库交互的框架。
思路:分包逐步实现JDBC。
base包:根据获得的结果集实现封装功能的接口,包含结果集处理器接口和行处理器接口
/** * 结果集处理器的接口 *实现类:BeanHandler(获取单个对象)、BeanListHandler(获取对象集合) */ public interface ResultSetHandler<T> {public T handler(ResultSet resultSet)throws SQLException,IllegalAccessException,InstantiationException, InvocationTargetException; }
/** * 行处理器的接口 * @param <T> */ public interface RowProcessor<T> {public T toArray(ResultSet resultSet) throws SQLException; }
handler包:实现接口:
/** * 结果集处理接口的实现类 * 操作结果集并封装实体类 * @param <T> */ public class BeanHandler<T> implements ResultSetHandler<T> {private Class beanClass;public BeanHandler(Class beanClass) {this.beanClass = beanClass;}@Overridepublic T handler(ResultSet resultSet) throws SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();if(resultSet.next()){T t = (T) beanClass.newInstance();for (int i = 0; i < columnCount; i++) {String columnName = metaData.getColumnName(i + 1);Object columnValue = resultSet.getObject(columnName);BeanUtils.copyProperty(t,columnName,columnValue);}return t;}return null;} }
/** * 结果集处理接口的实现类 * 处理结果集并封装为集合 * @param <T> */ public class BeanListHandler<T> implements ResultSetHandler<List<T>> {private Class beanListClass;public BeanListHandler(Class beanListClass) {this.beanListClass = beanListClass;}@Overridepublic List<T> handler(ResultSet resultSet) throws SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {List<T> list = new ArrayList<>();ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();while(resultSet.next()){T t = (T) beanListClass.newInstance();for (int i = 0; i < columnCount; i++) {String columnName = metaData.getColumnName(i + 1);T columnValue = (T) resultSet.getObject(columnName);BeanUtils.copyProperty(t,columnName,columnValue);list.add(t);}}return list;} }
/** * 结果集处理接口的实现类 * 操作结果集并封装数组对象 * * @param <T> */ public class ArrayHandler<T> implements ResultSetHandler<T> {//行处理器private RowProcessor<T> rowProcessor;public ArrayHandler(RowProcessor<T> rowProcessor) {this.rowProcessor = rowProcessor;}@Overridepublic T handler(ResultSet resultSet) throws SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {return rowProcessor.toArray(resultSet);} }
其中,行处理的逻辑是拿到结果集后交给自定义的行处理接口实现类方法处理,这样做的目的是统一代码的格式(见后续web项目中的使用)。
processor包(处理行):
/** * 行处理器的实现类,将结果集中的数据获取并封装成数组 * @param <T> */ public class BaskRowProcessor<T> implements RowProcessor<T[]> {private Class arrayTClass;public BaskRowProcessor(Class arrayTClass) {this.arrayTClass = arrayTClass;}@Overridepublic T[] toArray(ResultSet resultSet) throws SQLException {//创建数据容器List<T> list = new ArrayList<>();//遍历结果集while(resultSet.next()){T t = (T) resultSet.getObject(1);list.add(t);}if(list.size()==0||resultSet==null){throw new RuntimeException("参数异常无法获取泛型数组");}else {//创建数组T[] ts = (T[]) Array.newInstance(arrayTClass, list.size());//添加数据for (int i = 0; i < list.size(); i++) {ts[i] = list.get(i);}return ts;}} }
通过结果集返回封装好的对象、列表、数组的功能已实现,接下类实现操作数据库返回结果集的功能:
core包:
public class QueryRunner {private DruidDataSource dataSource;private ThreadLocal<Connection> local = new ThreadLocal<>();public QueryRunner(DruidDataSource dataSource) {this.dataSource = dataSource;}//获取连接private Connection getConnection() throws SQLException {Connection connection = local.get();if(connection==null){connection = dataSource.getConnection();local.set(connection);}return connection;}//配置参数private PreparedStatement getPreparedStatement(Connection connection,String sql,Object... args) throws SQLException {PreparedStatement statement = connection.prepareStatement(sql);for (int i = 0; i < args.length; i++) {statement.setObject(i+1,args[i]);}return statement;}//更新操作public int update(String sql,Object... args) throws SQLException {Connection connection = getConnection();PreparedStatement statement = getPreparedStatement(connection, sql, args);int i = statement.executeUpdate();return i;}//查询操作public <T> T query(ResultSetHandler<T> handler,String sql,Object... args) throws SQLException, InvocationTargetException, IllegalAccessException, InstantiationException {Connection connection = getConnection();PreparedStatement statement = getPreparedStatement(connection, sql, args);ResultSet resultSet = statement.executeQuery();T t = handler.handler(resultSet);return t;}}
至此,框架搭建完毕,接下来以用户创建的web项目举例:
数据库工具类:
public class JDBCUtils {//德鲁伊连接池引用private static DruidDataSource dataSource;static{//创建德鲁伊连接池dataSource = new DruidDataSource();//获取配置信息Properties properties = new Properties();try {properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("DBConfig.properties"));String username = properties.getProperty("username");String password = properties.getProperty("password");String url = properties.getProperty("url");String driverName = properties.getProperty("driverName");dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setDriverClassName(driverName);} catch (IOException e) {throw new RuntimeException(e);}}public static QueryRunner getQueryRunner(){return new QueryRunner(dataSource);} }
controller层中对数据库进行操作:
//---操作数据库--------------------------------------------------------------------------------------- @RequestMapping("/test13.action") public void test13() throws SQLException {//操作更新语句JDBCUtils.getQueryRunner().update("update user set password = ? where username = ?","123456","zs"); } @RequestMapping("/test14.action") public void test14() throws SQLException, InvocationTargetException, IllegalAccessException, InstantiationException {//查询对象User zs = JDBCUtils.getQueryRunner().query(new BeanHandler<>(User.class), "select * from user where username = ?", "zs");System.out.println(zs); } @RequestMapping("/test15.action") public void test15() throws SQLException, InvocationTargetException, IllegalAccessException, InstantiationException {//查询对象列表List<User> users = JDBCUtils.getQueryRunner().query(new BeanListHandler<>(User.class), "select * from user");for (User user : users) {System.out.println("列表中的对象:"+user);} } @RequestMapping("/test16.action") public void test16() throws SQLException, InvocationTargetException, IllegalAccessException, InstantiationException {//查询所有的usernameString[] usernames = JDBCUtils.getQueryRunner().query(new ArrayHandler<>(new BaskRowProcessor<>(String.class)),"select username from user");System.out.println(usernames); }
遇到的问题:
1.无法找到数据库连接的配置文件DBCfig.properties
解决方案:将配置文件放到src/main/resources文件夹中去,这样 资源文件才会被复制到target/classes 目录下。
相关文章:
手写Spring-MVC之前后置处理器与异常处理、数据库框架
Day48 手写Spring-MVC之前后置处理器与异常处理 前后置处理器 概念:从服务器获取的JSON数据可能是加密后的,因此服务端获取的时候需要进行解密(前置处理器)。 而从服务器传出的JSON数据可能需要加密,因此需要在处理返…...
学习笔记(linux高级编程)11
进程间通信 》信号通信 应用:异步通信。 中断,, 1~64;32应用编程。 如何响应: Term Default action is to terminate the process. Ign Default action is to ignore the signal. wait Core Default action is …...
vite+vue3+nginx配置统一公共前缀
方案1:重定向 server {listen 80;server_name localhost;location / {root /usr/share/nginx/html;index index.html;}location /music/ {proxy_pass http://127.0.0.1:80/;} }方案2:vitenginx双重配置 在方案1中,我们虽然能够实现 通过 …...
android 国内下载Gradle源
在中国使用 Gradle 时,可以配置使用一些国内的镜像源,以提高下载速度和稳定性。以下是几个常用的 Gradle 镜像源地址: 配置 gradle-wrapper.properties 文件: 阿里云: distributionUrlhttps\://services.gradle.org/distributions/gradle-7.…...
mysql8一键安装脚本(linux) 拿走即用
创建一个shell文件,将下面的代码放里面去,然后放到linux服务器上运行就可以了 #!/bin/bash#---------------------* # * # 2021-10-08 * # install mysql-8 * # * #---------------------*route=/usr #包存放路径 mys…...
C# 开发Winform DataGridView的增删改查实战
在C# WinForms应用程序中,DataGridView控件是一个非常强大的工具,用于显示和编辑表格数据。下面我将详细介绍如何在WinForm应用程序中使用DataGridView实现基本的数据库操作:增加、删除、修改和查询(CRUD)。 第一步&a…...
CentOS 7镜像列表服务下线,还想继续使用该怎么办?
目录 问题和解决方法 mirrorlist.centos.org 作用 vault.centos.org 作用 CentOS 7的生命周期已经在2024年6月30日终止(End of Life,EOL),官方将不再对该版本进行问题修复、功能更新以及其他形式的维护支持。这意味着使用 Cent…...
代码随想录训练营第二十八天 122买卖股票的最佳时间II 55跳跃游戏 45跳跃游戏II 1005K次取反后最大化的数组和
第一题: 原题链接:122. 买卖股票的最佳时机 II - 力扣(LeetCode) 思路: 这题十分简单,就是把相邻天数的金额相减,如果发现大于0就加到res中,返回res即可 代码如下: …...
在node环境使用MySQL
什么是Sequelize? Sequelize是一个基于Promise的NodeJS ORM模块 什么是ORM? ORM(Object-Relational-Mapping)是对象关系映射 对象关系映射可以把JS中的类和对象,和数据库中的表和数据进行关系映射。映射之后我们就可以直接通过类和对象来操作数据表和数据了, 就…...
spdlog一个非常好用的C++日志库(四): 源码分析之logger类
目录 1.简介 2.类图关系 3.logger数据成员 4.logger函数成员 4.1.构造与析构 4.1.1.构造函数 4.1.2.拷贝构造、移动构造 4.2.交换操作 4.3.log()记录日志消息 4.3.1.格式串 4.3.2.普通字符串 4.3.3.日志级别 4.3.4.宽字符支持 4.4.sink_it_:将log消息…...
逻辑这回事(七)---- 器件基础
Xilinx FPGA创建了先进的硅模块(ASMBL)架构,以实现FPGA具有针对不同应用程序领域优化的各种功能组合的平台。通过这一创新,Xilinx提供了更多的设备选择,使客户能够为其特定设计选择具有正确的功能和功能组合的FPGA。ASMBL体系结构通过以下方式突破了传统的设计障碍:消除几…...
中俄汽车产业链合作前景广阔,东方经济论坛助力双边合作与创新
随着中国汽车零部件企业的竞争力和创新能力不断增强,中国汽车及零部件行业在俄罗斯的市场份额和品牌影响力显著提升,中俄两国在汽车产业链上的合作展现出巨大的潜力和广阔的前景。2024年5月,俄罗斯乘用车新车销量达到12.8万辆,同比…...
第六篇:精通Docker Compose:打造高效的多容器应用环境
精通Docker Compose:打造高效的多容器应用环境 1. 引言 1.1 目的与重要性 在现代软件开发中,随着应用程序的复杂性不断增加,传统的单一容器部署方式已无法满足需求。Docker Compose作为一种强大的工具,专门用于定义和运行多容器…...
C++视觉开发 一.OpenCV环境配置
一.OpenCV安装环境配置 1.OpenCV安装 (1)下载 官方下载链接:http://opencv.org/releases 这边选择需要的版本,我是在windows下的4.9.0。(科学上网下载很快,否则可能会有点慢) (2)安装 双击下…...
大数据面试题之Kafka(3)
目录 Kafka支持什么语义,怎么实现ExactlyOnce? Kafka的消费者和消费者组有什么区别?为什么需要消费者组? Kafka producer的写入数据过程? Kafka producer的ack设署 Kafka的ack机制,解决了什么问题? Kafka读取消息是推还是拉的模式?有什…...
视频监控平台web客户端的免密查看视频页:在PC浏览器上如何调试手机上的前端网页(PC上的手机浏览器的开发者工具)
目录 一、手机上做前端页面开发调试 1、背景 2、视频监控平台AS-V1000的视频分享页 3、调试手机前端页面代码的条件 二、手机端的准备工作 1、手机准备 2、手机的开发者模式 3、PC和手机的连接 (1)进入调试模式 (2)选择…...
力扣2488.统计中位数为 K 的子数组
力扣2488.统计中位数为 K 的子数组 等价转换 子数组为奇数 : 左小 右小 左大 右大 左小 – 左大 右大 – 右小 子数组为偶数 : 左小 右小 左大 右大 – 1 左小 – 左大 右大 – 右小 - 1提示中说明k为两数中左边那个 先从k的下标pos开始往左逆序…...
Zabbix对接Elasticsearch(ES)数据库(未成功)
0.需求分析 不管zabbix的后端数据库是oracle还是mysql,当zabbix监控的量级达到了一定程度后,那么对数据库的性能是一个非常严峻的挑战。特别是对历史数据的查询,将会变得非常非常的慢,别告诉我可以建索引优化,当量级达…...
【unity实战】使用Unity实现动作游戏的攻击 连击 轻重攻击和打击感
最终效果 文章目录 最终效果前言素材下载:玩家移动跳跃控制攻击动画配置轻攻击重攻击 攻击时禁止移动和攻击移动补偿敌人击退和播放受击动画受击特效攻击停顿和屏幕震动局部顿帧(补充)参考源码完结 前言 注意本文为自己的学习记录笔记&#…...
ELK 企业实战7
ELKkafkafilebeat企业内部日志分析系统 1、组件介绍 1、Elasticsearch: 是一个基于Lucene的搜索服务器。提供搜集、分析、存储数据三大功能。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的ÿ…...
linux 下neo4j的安装
一、neo4j简介 Neo4j 是一个高性能的 NoSQL 图形数据库,它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j 也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。 neo4j与jdk版本对应 neo4j的版本需要与jdk版本相适配,否则容易出现安装失…...
Flink ProcessFunction不同流异同及应用场景
ProcessFunction系列对比概览 函数类别关键特性应用场景示例ProcessFunction基础类,处理单个事件,支持事件时间、水位线、状态管理、定时器。单独处理每个事件,执行复杂逻辑,如基于事件内容动态响应。KeyedProcessFunction基于键…...
Matplotlib 文本
可以使用 xlabel、ylabel、text向图中添加文本 mu, sigma 100, 15 x mu sigma * np.random.randn(10000)# the histogram of the data n, bins, patches plt.hist(x, 50, densityTrue, facecolorg, alpha0.75)plt.xlabel(Smarts) plt.ylabel(Probability) plt.title(Histo…...
信创产业政策,信创测试方面
信创产业的政策支持主要体现在多个方面,这些政策旨在推动产业的快速发展,加强自主创新能力,保障国家信息安全,以及促进产业结构的优化升级。 首先,政府通过财政支持、税收优惠等方式,加大对信创产业的资金…...
微信云数据库迁移到unicloud云数据库
背景 早期只有一个微信小程序,后来了解到uniapp的跨端解决方案,开始从小程序代码迁移到uniapp。对于后端采用的微信云开发方案,迁移的时候主要要解决从openid的用户体系转移到unicloud提供的uni-id体系(使用uid)。 方案 利用微信云数据库的…...
快速上手文心一言指令
“文心一言”指的是百度公司开发的自然语言处理与生成技术,它类似于ChatGPT,是一种基于大规模语言模型的AI对话系统,能够理解和生成自然语言文本,进行问答、创作等多种任务。由于“文心一言”是一个复杂的系统,其内部指…...
零基础STM32单片机编程入门(五)FreeRTOS实时操作系统详解及实战含源码视频
文章目录 一.概要二.什么是实时操作系统三.FreeRTOS的特性四.FreeRTOS的任务详解1.任务函数定义2.任务的创建3.任务的调度原理 五.CubeMX配置一个FreeRTOS例程1.硬件准备2.创建工程3.调试FreeRTOS任务调度 六.CubeMX工程源代码下载七.讲解视频链接地址八.小结 一.概要 FreeRTO…...
leetCode.96. 不同的二叉搜索树
leetCode.96. 不同的二叉搜索树 题目思路 代码 // 方法一:直接用卡特兰数就行 // 方法二:递归方法 class Solution { public:int numTrees(int n) {// 这里把 i当成整个结点,j当成左子树最左侧结点,并一次当根节点尝试// f[ i ] f[ j - 1…...
PyAutoGUI 使用详解
文章目录 简介PyAutoGUI 的原理安装 PyAutoGUI基本使用示例鼠标控制键盘控制截屏图像识别消息框 高级功能防止误操作多屏幕支持鼠标平滑移动 结论 简介 PyAutoGUI 是一个用于自动化控制鼠标和键盘的 Python 库。它可以帮助开发者编写脚本,以模拟用户在计算机上的操…...
MySQL——备份
为什么要备份? 保证重要的数据不丢失 方便数据转移 MySQL数据库备份方式: 1. 直接拷贝物理文件 2. 在可视化工具中手动导出 —— 在想要导出的表或者库中,右键选择备份或导出 3. 使用命令行导出 mysqldump ——cmd打开命令行 —…...
科东软件精彩亮相华南工博会,展现未来工业前沿技术
近日,华南国际工业博览会在深圳成功举办。科东软件携众多前沿技术、解决方案及最新应用案例精彩亮相,为参展观众带来了一场工业智能的科技盛宴。 鸿道操作系统(Intewell) 科东软件重点展示了鸿道操作系统(Intewell&…...
详解flink sql, calcite logical转flink logical
文章目录 背景示例FlinkLogicalCalcConverterBatchPhysicalCalcRuleStreamPhysicalCalcRule其它算子FlinkLogicalAggregateFlinkLogicalCorrelateFlinkLogicalDataStreamTableScanFlinkLogicalDistributionFlinkLogicalExpandFlinkLogicalIntermediateTableScanFlinkLogicalInt…...
PostgreSQL的系统视图pg_statio_all_indexes
PostgreSQL的系统视图pg_statio_all_indexes 在 PostgreSQL 数据库中,pg_statio_all_indexes 视图提供了有关所有索引的 I/O 活动的统计信息。这些统计信息对于了解索引的使用情况和性能调优非常有帮助。 pg_statio_all_indexes 视图的结构 以下是 pg_statio_all…...
【C++ Primer Plus学习记录】函数和C-风格字符串
将字符串作为参数时意味着传递的是地址,但可以使用const来禁止对字符串参数进行修改。 假设要将字符串作为参数传递给函数,则表示字符串的方式有三种: (1)char数组 (2)用引号括起来的字符串常…...
力扣双指针算法题目:移动零
1.题目 . - 力扣(LeetCode) 2.思路解析 这个题目的思路和“使用递归排序快速排序解决数组的排序问题”相同 class solution { public:void QuickSort(vector<int>& nums, int left, int right){if (left > right) return;int key left…...
day60---面试专题(微服务面试题-参考回答)
微服务面试题 **面试官:**Spring Cloud 5大组件有哪些? 候选人: 早期我们一般认为的Spring Cloud五大组件是 Eureka : 注册中心Ribbon : 负载均衡Feign : 远程调用Hystrix : 服务熔断Zuul/Gateway : 网关 随着SpringCloudAlibba在国内兴起 , …...
laravel+phpoffice+easyexcel实现导入
资源包下载地址 https://download.csdn.net/download/QiZong__BK/89503486 easy-excel下载: "dcat/easy-excel": "^1.0", 命令行: composer require dcat/easy-excel 前端代码 <!doctype html> <html lang"en&…...
Spring Boot集成多数据源的最佳实践
Spring Boot集成多数据源的最佳实践 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 为什么需要多数据源? 在实际的应用开发中,有时候…...
Java项目:基于SSM框架实现的班主任助理管理系统【ssm+B/S架构+源码+数据库+开题报告+毕业论文】
一、项目简介 本项目是一套基于SSM框架实现的班主任助理管理系统 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观、操作简单、功…...
数据在内存中的存储方式
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C语言 目录 前言 一、整数的存储 二、大小端字节序及其判断 1.什么是大小端 2.为什么有大小端 3.用c语言编写程序判断大小端 三、浮点数的存储 1.浮点数…...
Selenium 监视数据收发
实际上,在我提供的示例中,确实使用了浏览器实例。webdriver.Chrome()这行代码正是创建了一个Chrome浏览器的WebDriver实例。Selenium Wire扩展了标准的Selenium WebDriver,允许你通过这个浏览器实例来监听网络请求。 当你运行类似这样的代码…...
基于 STM32 的智能睡眠呼吸监测系统设计
本设计的硬件构成: STM32F103C8T6单片机最小系统板(包含3.3V稳压电路时钟晶振电路复位电路(上电自复位,手动复位)),心率传感器、气压传感器、液晶显示、按键、蜂鸣器、LED灯、蓝牙模块组合而成…...
Spring的事务管理、AOP实现底层
目录 spring的事务管理是如何实现的? Spring的AOP的底层实现原理 spring的事务管理是如何实现的? 首先,spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑ÿ…...
基于SpringBoot的篮球竞赛预约平台
你好,我是计算机学姐码农小野!如果你对篮球竞赛预约平台感兴趣或有相关需求,欢迎私信联系我。 开发语言: Java 数据库: MySQL 技术: SpringBootMySql 工具: MyEclipse、Tomcat 系统展示…...
学生用小台灯什么牌子的好?列举出几款学生用台灯推荐
眼睛是我们感知世界的窗口,但近年来,儿童青少年的视力健康却受到了严重困扰。数据显示,近视问题在儿童群体中呈现出明显的增长趋势,这给他们的学习和生活带来了诸多不便。虽然现代科技的快速发展使得电子产品成为了我们生活中不可…...
软件测试面试题:项目中的MQ是如何测试的?
通常,咱们会从两个方面来考虑:正常情况和异常情况。 首先,咱们得确保消息队列在正常工作时结果正确。比如,消息发送出去的时候,所有的字段都得齐全,接收方收到的消息也得一样。咱们得确保系统能够正确无误…...
Python爬取国家医保平台公开数据
国家医保服务平台数据爬取python爬虫数据爬取医疗公开数据 定点医疗机构查询定点零售药店查询医保机构查询药品分类与代码查询 等等,数据都能爬 接口地址:/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital 签名参数:signData {dat…...
B站大课堂-自动化精品视频(个人存档)
基础知识 工业通信协议 Modbus 施耐德研发,有基于以太网的 ModbusTCP 协议和使用 485/232 串口通信的 ModbusRTU/ASCII。 Modbus 协议面世较早、协议简洁高效、商用免费、功能灵活、实现简单,是目前应用最广泛的现场总线协议。 我的笔记里边有一些推荐…...
C++_STL---priority_queue
priority_queue的相关介绍 优先级队列是一种容器适配器,根据严格的排序标准,它的第一个元素总是它所包含的元素中最大(小)的。该容器适配器类似于堆,在堆中可以随时插入元素,并且可以检索最大(小)堆元素(优先级队列中位于顶部的元…...
可移动天线辅助宽带通信的性能分析和优化
可移动天线辅助宽带通信的性能分析和优化 可移动天线 (MA) 已成为一种很有前景的技术,通过在发射器 (Tx) 和/或接收器 (Rx) 处实现天线的本地移动来实现更有利的信道条件,从而增强无线通信性能。 由于现有的MA辅助无线通信研究主要考虑平坦衰落信道中的…...