若依的使用(token补充、HTTPS(网络安全)、分页前后端配置)
本文章转载于公众号:王清江唷,仅用于学习和讨论,如有侵权请联系
QQ交流群:298405437
本人QQ:4206359 具体视频地址:8 跑后端_哔哩哔哩_bilibili
1、HTTP?
曾经我们在讲JWT的时候,当时JWT需要配合https使用呢?
因为http自身是明码传输,我们通过网卡抓包可以轻而易举得到token。
我们的token相当于在网络上明码传输,很容易被人拦截查看!
下面演示一下拦截token!
效果图:
2、不安全怎么办呐?
既然不安全,那咋办呢?上https!
视频演示腾讯云上https。
3、HTTPs实现
现在我们利用腾讯云实现HTTPs。
首先得有一个域名吧?怎么买我就不多说了,直接在腾讯云搜索域名,选择自己喜欢的购买。
然后呢,还需要购买SSL证书,一般来说,买域名会送一个SSL证书,反正我的是送的。如果没送可以点击申请免费证书,证书界面如下:
https://console.cloud.tencent.com/ssl
有了证书之后,我们需要先下载证书,下载nginx证书。请直接看视频。
腾讯云官方学习视频:
https://cloud.tencent.com/document/product/400/35244
把打包下载的证书直接全部丢到nginx/conf文件夹,然后改写nginx配置文件:
user www;worker_processes auto;error_log /www/wwwlogs/nginx_error.log crit;pid /www/server/nginx/logs/nginx.pid;worker_rlimit_nofile 51200;events{use epoll;worker_connections 51200;multi_accept on;}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;client_max_body_size 100m;#用于tomcat反向代理,解决nginx 504错误proxy_connect_timeout 7200; #单位秒proxy_send_timeout 7200; #单位秒proxy_read_timeout 7200; #单位秒proxy_buffer_size 16k;proxy_buffers 4 64k;proxy_busy_buffers_size 128k;proxy_temp_file_write_size 128k;# ps:以timeout结尾配置项时间要配置大点server {listen 80;server_name localhost;charset utf-8;location / {root /home/wqj/dist;try_files $uri $uri/ /index.html;index index.html index.htm;}location /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://localhost:8765/;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}server {#SSL 默认访问端口号为 443listen 443 ssl;#请填写绑定证书的域名server_name wangqingjiang.top;#请填写证书文件的相对路径或绝对路径ssl_certificate wangqingjiang.top_bundle.crt;#请填写私钥文件的相对路径或绝对路径ssl_certificate_key wangqingjiang.top.key;ssl_session_timeout 5m;#请按照以下协议配置ssl_protocols TLSv1.2 TLSv1.3;#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;ssl_prefer_server_ciphers on;charset utf-8;location / {root /home/wqj/dist;try_files $uri $uri/ /index.html;index index.html index.htm;}location /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://localhost:8765/;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}
}
回头再看,其实就是一些固定的配置。然后重启nginx之后就发现https已经生效:
后来抓的包我就没读懂过:
4、分页的前端配置
接下来以操作日志页面为例子,进行讲述。
前端每次给后端发请求的时候,都是带了分页参数的,默认都是请求第一页,每页10条数据。源码:
//请求参数:queryParams: {pageNum: 1,pageSize: 10,title: undefined,operName: undefined,businessType: undefined,status: undefined}//每次 发送请求带上了分页参数的:/** 查询登录日志 */getList() {this.loading = true;list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {this.list = response.rows;this.total = response.total;this.loading = false;});
},
ry对elementUI的分页组件进行了小小的封装:
<template><div :class="{'hidden':hidden}" class="pagination-container"><el-pagination:background="background":current-page.sync="currentPage":page-size.sync="pageSize":layout="layout":page-sizes="pageSizes":pager-count="pagerCount":total="total"v-bind="$attrs"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div></template><script>import { scrollTo } from '@/utils/scroll-to'export default {name: 'Pagination',props: {total: {required: true,type: Number},page: {type: Number,default: 1},limit: {type: Number,default: 20},pageSizes: {type: Array,default() {return [10, 20, 30, 50]}},// 移动端页码按钮的数量端默认值5pagerCount: {type: Number,default: document.body.clientWidth < 992 ? 5 : 7},layout: {type: String,default: 'total, sizes, prev, pager, next, jumper'},background: {type: Boolean,default: true},autoScroll: {type: Boolean,default: true},hidden: {type: Boolean,default: false}},data() {return {};},computed: {currentPage: {get() {return this.page},set(val) {this.$emit('update:page', val)}},pageSize: {get() {return this.limit},set(val) {this.$emit('update:limit', val)}}},methods: {handleSizeChange(val) {if (this.currentPage * val > this.total) {this.currentPage = 1}this.$emit('pagination', { page: this.currentPage, limit: val })if (this.autoScroll) {scrollTo(0, 800)}},handleCurrentChange(val) {this.$emit('pagination', { page: val, limit: this.pageSize })if (this.autoScroll) {scrollTo(0, 800)}}}}</script><style scoped>.pagination-container {background: #fff;padding: 32px 16px;}.pagination-container.hidden {display: none;}
</style>
我们跟着elementUI学习一下分页插件即可:
https://element.eleme.cn/#/zh-CN/component/pagination
参考学习资料:
https://blog.csdn.net/chenxi_li/article/details/118682708
我们看到了,前端只需要维护好数据,我需要当前是第几页,一共有几条数据,每页多少条。
前端只需要维护好这三个数据,其他的交给后端就行了。
4.1后端分页实现pagehelper
后端是通过pagehelper插件实现的。
ry通过pagehelper间接引入了mybatis:
现在我们需要学习一波pagehelper的使用。
这就不得不介绍一波pagehelper的官网了:
https://pagehelper.github.io/docs/howtouse/
通过官网,我们需要知道为啥ry引入了分页插件就可以使用了,难道没有配置吗?
确实,如果使用了SpringBoot可以零配置。我们先通过创建一个新的项目零配置来使用一下pagehelper:
通过官网讲述常见的下面的分页方式:
// //第二种,Mapper接口方式的调用,推荐这种使用方式。//获取第1页,10条内容,默认查询总数count// ry用的就是下面这种。PageHelper.startPage(1, 10);//第五种,参数对象//如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页//有如下 User 对象public class User {//其他fields//下面两个参数名和 params 配置的名字一致private Integer pageNum;private Integer pageSize;}//支持 ServletRequest,Map,POJO 对象,需要配合 params 参数// 1、如果是request 则需要请求的时候带上对应的参数。// 2、如果是Map 则Map中需要包含pageNum,pageSize等选项。// 3、如果是POJO 则需要在pojo中带上对应的属性。PageHelper.startPage(request);
通过官网讲解常见的几种分页方式:
PageHelper.startPage传普通参数(ry使用的)。
PageHelper.startPage方法传POJO或Map或ServletRequest。
分析pagehelper源码
首先是需要分析分页拦截器。
分页插件在哪进行注入到SqlSessionFactory的?
这就不得不提到两个主动配置的类了:
其中PageHelperProperties是为了去yml取出相应的配置,以供PageHelperAutoConfiguration在执行构造方法的时候找到。
PageHelperAutoConfiguration实现了InitializingBean接口,所以重写了afterPropertiesSet方法,该方法会在构造方法执行后执行。
接下来打俩断点,看看执行过程:
我们的yml配置是这样写的:
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
debug的时候需要注意,以上参数的默认值是什么?【debug讲述】
经过debug发现其实ry设置的几个参数全部不设置也可以。
helperDialect如果不设置,程序每次执行SQL都要分析方言,何不索性告诉分页插件,这样也让程序执行略快一点。
supportMethodsArguments虽然设置了,但是其实ry中根本没用过。
params设置了个寂寞,原本默认就是count=countSql,本来就是默认值,设置也是白设置。
分析ry如何使用pagehelper
ry在BaseController中封装了分页方法。也就是说我们自己写的controller只要继承了BaseController,直接调用startPage方法即可完成分页。
ry的分页源码也非常简单:
/**
* 设置请求分页数据
*/
public static void startPage()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
从源码可以发现,无非就是从请求中拿到从前端传来的pageNum,pageSize,reasonable,orderBy和isAsc这些分页参数,然后直接调用分页插件pagehelper的静态分页方法PageHelper.startPage。
5、ry中的Mybatis详解
5.1 mybatis和SpringBoot结合方式
经过以前的经验,我们直接看mybatis的自动配置类:
@Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setVfs(SpringBootVFS.class);if (StringUtils.hasText(this.properties.getConfigLocation())) {factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));}applyConfiguration(factory);if (this.properties.getConfigurationProperties() != null) {factory.setConfigurationProperties(this.properties.getConfigurationProperties());}if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors);}if (this.databaseIdProvider != null) {factory.setDatabaseIdProvider(this.databaseIdProvider);}if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());}if (this.properties.getTypeAliasesSuperType() != null) {factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());}if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}if (!ObjectUtils.isEmpty(this.typeHandlers)) {factory.setTypeHandlers(this.typeHandlers);}if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {factory.setMapperLocations(this.properties.resolveMapperLocations());}Set<String> factoryPropertyNames = Stream.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName).collect(Collectors.toSet());Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {// Need to mybatis-spring 2.0.2+factory.setScriptingLanguageDrivers(this.languageDrivers);if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {defaultLanguageDriver = this.languageDrivers[0].getClass();}}if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {// Need to mybatis-spring 2.0.2+factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);}return factory.getObject();
}
可以发现,无非就是创建SqlSessionFactoryBean并且进行一系列配置之后,getObject得到SqlSessionFactory(实际是DefaultSqlSessionFactory对象)对象。
so,ry也是如此,重写了一个方法来获得sqlSessionFactory:
@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");String mapperLocations = env.getProperty("mybatis.mapperLocations");String configLocation = env.getProperty("mybatis.configLocation");typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);VFS.addImplClass(SpringBootVFS.class);final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);sessionFactory.setTypeAliasesPackage(typeAliasesPackage);sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));return sessionFactory.getObject();
}
在SpringBoot项目中,把SqlSessionFactory接口的实例注入到Spring容器中,mybatis的配置也就随之完成。
经过debug源码,发现本质上ry的注入SqlSessionFactory和原本的自动注入没什么差别,如果一定要说有差别,那就是亲自去扫描了别名包typeAliasesPackage。但其实必要性不大,框架自己也会去扫。
通过以上的说明,我们发现其实可以把ry的mybatis配置必要性并不大,可以完全删除ry自己配置的bean,发现一点也不影响当前项目的功能。
5.2mybatis-plus集成
关于mybatis-plus只是部分同学的需求,我们现在来做一下。做完再解释!
ry集成mybatis-plus最简秘诀
第一步,引入mybatis-plus,在common模块中:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version>
</dependency>
第二步,删除冲突依赖:
<!-- pagehelper 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions>
</dependency>
第三步,填写yml配置:
mybatis-plus:configLocation: classpath:mybatis/mybatis-config.xml
typeAliasesPackage: com.ruoyi.**.domain
第四步,删除MyBatisConfig,也就是删除ry自己的配置文件,删除下面这个文件:
package com.wqj.test;import java.io.IOException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.List;import javax.sql.DataSource;import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;import org.apache.commons.lang3.StringUtils;import org.apache.ibatis.io.VFS;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.env.Environment;import org.springframework.core.io.DefaultResourceLoader;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.core.io.support.ResourcePatternResolver;import org.springframework.core.type.classreading.CachingMetadataReaderFactory;import org.springframework.core.type.classreading.MetadataReader;import org.springframework.core.type.classreading.MetadataReaderFactory;import org.springframework.util.ClassUtils;/*** Mybatis支持*匹配扫描包** @author ruoyi*/@Configurationpublic class MyBatisConfig{@Autowiredprivate Environment env;static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";public static String setTypeAliasesPackage(String typeAliasesPackage){ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);List<String> allResult = new ArrayList<String>();try{for (String aliasesPackage : typeAliasesPackage.split(",")){List<String> result = new ArrayList<String>();aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;Resource[] resources = resolver.getResources(aliasesPackage);if (resources != null && resources.length > 0){MetadataReader metadataReader = null;for (Resource resource : resources){if (resource.isReadable()){metadataReader = metadataReaderFactory.getMetadataReader(resource);try{result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());}catch (ClassNotFoundException e){e.printStackTrace();}}}}if (result.size() > 0){HashSet<String> hashResult = new HashSet<String>(result);allResult.addAll(hashResult);}}if (allResult.size() > 0){typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));}else{throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");}}catch (IOException e){e.printStackTrace();}return typeAliasesPackage;}public Resource[] resolveMapperLocations(String[] mapperLocations){ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();List<Resource> resources = new ArrayList<Resource>();if (mapperLocations != null){for (String mapperLocation : mapperLocations){try{Resource[] mappers = resourceResolver.getResources(mapperLocation);resources.addAll(Arrays.asList(mappers));}catch (IOException e){// ignore}}}return resources.toArray(new Resource[resources.size()]);}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");String mapperLocations = env.getProperty("mybatis.mapperLocations");String configLocation = env.getProperty("mybatis.configLocation");typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);VFS.addImplClass(SpringBootVFS.class);final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);sessionFactory.setTypeAliasesPackage(typeAliasesPackage);sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));return sessionFactory.getObject();}
}
然后直接重启项目,成功!
解释疑问:
疑问一:为什么要排除pagehelper中的mybatis依赖?
答:因为mybatis-plus的启动器和pagehelper都引入了mybatis,mybatis-plus的启动器的mybatis版本比较高。
pagehelper引入的mybatis的版本比较低,mybatis-plus用到了高版本mybatis的方法。所以需要排除pagehelper中的mybatis。否则报错没找到方法。
疑问二:pagehelper中排除了mybatis,为啥不把mybatis-spring一块给排除掉?
答:确实可以一块排除掉,可以。但是mybatis-plus也引入了mybatis-spring,所以并不冲突,maven会自动排除一个。
疑问三:为啥在pagehelper中不把MybatisAutoConfiguration的依赖排除掉?不都有mybatis-plus了吗,我还要MybatisAutoConfiguration有啥用?
答:因为pagehelper的自动配置类用到了MybatisAutoConfiguration,虽然不起作用,但是也不能排除依赖,否则直接报【类没有找到异常】。那么在哪里用到的呢?
疑问四:为啥yml配置中不写mapperLocations的相关配置?
答:可以写,但是默认就是classpath*:mapper/**/*Mapper.xml,写不写都一样,相关源码:
疑问五:为啥要删除原本的MybatisConfig?
答:因为原来的MybatisConfig会生成一个名字为sqlSessionFactory的bean,那么mybatis-plus的自动配置bean失效,因为mybatis-plus的自动配置加了注解@ConditionalOnMissingBean,也就是说sqlSessionFactory若存在,mybatis-plus则不会注入sqlSessionFactory。相关代码:
测试mybatis-plus
直接测试一波登录日志的查询!
先给mapper接口加buff:
public interface SysLogininforMapper extends BaseMapper<SysLogininfor>
然后直接查询即可:
@Override
public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) {
return logininforMapper.selectList(null);
// return logininforMapper.selectLogininforList(logininfor);
}
报错!
然后生成的SQL:
SELECT
info_id,
user_name,
STATUS,
ipaddr,
login_location,
browser,
os,
msg,
login_time,
search_value,
create_by,
create_time,
update_by,
update_time,
remark,
params
FROM
sys_logininfor
LIMIT ?
好玩的事情发生了,BaseEntity的属性也被写入了SQL中。对于这种残花败柳,我们直接标记它不存在:
/**
* 搜索值
*/
@TableField(exist = false)
private String searchValue;
/**
* 创建者
*/
@TableField(exist = false)
private String createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(exist = false)
private Date createTime;
/**
* 更新者
*/
@TableField(exist = false)
private String updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(exist = false)
private Date updateTime;
/**
* 备注
*/
@TableField(exist = false)
private String remark;
/**
* 请求参数
*/
@TableField(exist = false)
private Map<String, Object> params;
随之查询成功,mp集成到此结束!
3►扩展学习
请大家自主学习下面注解的含义。
网站一:
https://wenku.baidu.com/view/20631ddf0142a8956bec0975f46527d3240ca624.html
网站二:
https://blog.csdn.net/Lou_Lan/article/details/106192074
网站三:
https://blog.csdn.net/weixin_43808717/article/details/118214615
网站四:
https://baijiahao.baidu.com/s?id=1740059649839757132&wfr=spider&for=pc
图片一(引用自csdn:):
相关文章:
若依的使用(token补充、HTTPS(网络安全)、分页前后端配置)
本文章转载于公众号:王清江唷,仅用于学习和讨论,如有侵权请联系 QQ交流群:298405437 本人QQ:4206359 具体视频地址:8 跑后端_哔哩哔哩_bilibili 1、HTTP? 曾经我们在讲JWT的时候,当时JWT需要配合https…...
Java源码分析(一)Integer
当你掌握Java语言到了一定的阶段,或者说已经对Java的常用类和API都使用的行云流水。你会不会有一些思考?比如,这个类是如何设计的?这个方法是怎么实现的?接下来的一系列文章,我们一起学习下Java的一些常见类…...
WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机
WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机 在之前已经实现了WebRTC调用ossrs服务,实现直播视频通话功能。但是在使用过程中,RTCCameraVideoCapturer类提供的方法不能修改及调节相机的灯光等设置,那就需要自定义RTCVideoCaptur…...
【基于鲲鹏及openEuler20.03TLS下MySQL8.0.17性能调优】
【基于鲲鹏及openEuler20.03TLS下MySQL8.0.17性能调优】 一、环境说明二、实验过程三、实验小结 一、环境说明 华为云ECS 规格:8vCPU 32G arm架构操作系统:openEuler 20.03.TLSMySQL版本:8.0.17 二、实验过程 创建用户及用户组:…...
GRPC 学习记录
GRPC 安装 安装 grpcio、grpcio-tools、protobuf、 pip install grpcio -i https://pypi.tuna.tsinghua.edu.cn/simple pip install grpcio-tools -i https://pypi.tuna.tsinghua.edu.cn/simple pip install protobuf -i https://pypi.tuna.tsinghua.edu.cn/simple常用类型 p…...
C++语言的QT写软件界面,结合python深度学习模型的综合应用处理方案
C与python问题合集: 后面内容涉及到api的创建问题 如果我用C语言的QT写软件界面,然后用python语言去写和人工智能相关的东西。就比如说一些模型,那么现在我想将用python写的模型放在QT写的软件当中调用,那么请问是否会导致C语言…...
Linux环境下python连接Oracle教程
下载Oracle client需要的 安装包 rpm包下载地址:Oracle官方下载地址 选择系统版本 选择Oracle版本 下载3个rpm安装包 oracle-instantclient12.2-basic-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-devel-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-sq…...
第 7 章 排序算法(1)
7.1排序算法的介绍 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。 7.2排序的分类: 内部排序: 指将需要处理的所有数据都加载到**内部存储器(内存)**中进行排序。外部排序法: 数据量过大&am…...
wsl,字体乱码问题
配置wsl,字体乱码问题 一、前言 用zsh配置好wsl,每次打开还是会出现乱码,只有再新打开一个终端才会显示字体 如下图:第一次打开,出现乱码 如图:按加号,再开一个新终端才会显示字体。 二、解…...
【NetCore】10-路由定义
文章目录 路由与终结点:如何规划好Web Api1. 路由1.1 路由映射1.2 路由注册方式1.3 路由约束总结: Web Api定义 路由与终结点:如何规划好Web Api 1. 路由 1.1 路由映射 路由系统核心作用是指URL和应用程序Controller的对应关系的一种映射 这种映射的作…...
软考:中级软件设计师:数据库模式、ER模型
软考:中级软件设计师:数据库模式、ER模型 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准…...
海量数据迁移,亚马逊云科技云数据库服务为大库治理提供新思路
1.背景 目前,文档型数据库由于灵活的schema和接近关系型数据库的访问特点,被广泛应用,尤其是游戏、互联网金融等行业的客户使用MongoDB构建了大量应用程序,比如游戏客户用来处理玩家的属性信息;又如股票APP用来存储与时…...
DevOps系列文章之 GitlabCICD自动化部署SpringBoot项目
一、概述 本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。 二、前期准备 准备三台 CentOS7服务器,分别部署以下服务: 序号系统IP服务1CentOS7192.168.56.10Gitlab2CentOS7192.168.56.11Runner (安装Docker)3Cen…...
汽车租赁管理系统/汽车租赁网站的设计与实现
摘 要 租赁汽车走进社区,走进生活,成为当今生活中不可缺少的一部分。随着汽车租赁业的发展,加强管理和规范管理司促进汽车租赁业健康发展的重要推动力。汽车租赁业为道路运输车辆一种新的融资服务形式、广大人民群众一种新的出行消费方式和…...
语句覆盖、条件覆盖、判定覆盖、条件-判定覆盖、路径覆盖
白盒测试是结构测试,主要对代码的逻辑进行验证。 逻辑覆盖率:语句覆盖<条件覆盖<判定覆盖<条件-判定覆盖<组合覆盖<路径覆盖 例子 一、语句覆盖 最基础的覆盖,只要每一个执行处理框内的语句都能执行就可,不用关注…...
二进制逻辑运算符
运算的优先级:非>与>或 1.逻辑与:“ ∧ \wedge ∧“,“ ⋅ \cdot ⋅“,and 在逻辑问题中与是所有的都是真结果才是真,比如: 1010101011 1010101011 1010101011和 1010110010 1010110010 1010110010…...
Bug日记-webstorm运行yarn 命令报错
在windows中输入yarn -v正确输出,在webstrom终端中运行yarn命令输出错误 问题:可能是由于 WebStorm 配置问题导致的。 解决方案: 检查 WebStorm 的终端配置:在 WebStorm 中,点击菜单栏的 “File”(文件&am…...
C++11并发与多线程笔记(9) async、future、packaged_task、promise
C11并发与多线程笔记(9) async、future、packaged_task、promise 1、std::async、std::future创建后台任务并返回值2、std::packaged_task:打包任务,把任务包装起来3、std::promise3、小结 1、std::async、std::future创建后台任务…...
Mr. Cappuccino的第63杯咖啡——Spring之AnnotationConfigApplicationContext源码分析
Spring之AnnotationConfigApplicationContext源码分析 源码分析 源码分析 以上一篇文章《Spring之Bean的生命周期》的代码进行源码分析 AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(SpringConfig02.class); LifeCycleBe…...
opencv直方图与模板匹配
import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows() 直方图 cv2.calcHist(images,channels,mask,histSize,ran…...
Apache Doris 入门教程31:计算节点
需求场景 目前Doris是一个典型Share-Nothing的架构, 通过绑定数据和计算资源在同一个节点获得非常好的性能表现. 但随着Doris计算引擎性能持续提高, 越来越多的用户也开始选择使用Doris直接查询数据湖数据. 这类场景是一种Share-Disk场景, 数据往往存储在远端的HDFS/S3上, 计…...
Nacos和GateWay路由转发NotFoundException: 503 SERVICE_UNAVAILABLE “Unable to find
问题再现: 2023-08-15 16:51:16,151 DEBUG [reactor-http-nio-2][CompositeLog.java:147] - [dc73b32c-1] Encoding [{timestampTue Aug 15 16:51:16 CST 2023, path/content/course/list, status503, errorService Unavai (truncated)...] 2023-08-15 16:51:16,17…...
2021年9月全国计算机等级考试真题(二级C语言)
2021年9月全国计算机等级考试真题(二级C语言) 第1题 下列叙述中正确的是( )。 A. 算法的复杂度是指算法所处理的数据量 B. 算法的复杂度是指算法程序中指令的数量 C. 算法的复杂度是指算法控制结构的复杂程度 D. 算法的复杂度包…...
串口通讯
USART是全双工同步通讯 在同步通信中,数据信号所传输的内容绝大多数属于有效数据,而异步通信中包含了各种帧的标识符,所以同步通讯的效率更高。但是同步通信对时钟要求苛刻,允许的误差小。而异步通信则允许双方的误差较大 比特率…...
自动拉取 GitHub 仓库更新的脚本
更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 由于将 HAUE-CS-WIKI 部署到了我自己的服务器上作为国内镜像站,每次在源站更新后都需要手动拉取镜像站的更新实在是太麻烦了,因此产生了编写该脚本的需求( 读者可根据该…...
如何获得Android 14复活节彩蛋
每个新的安卓版本都有隐藏复活节彩蛋的悠久传统,可以追溯到以前,每个版本都以某种甜食命名。安卓14也不例外,但这一次的主题都是围绕太空构建的——还有一个复活节彩蛋。 安卓14复活节彩蛋实际上是一款很酷的小迷你游戏,你可以乘…...
国产32位单片机XL32F001,带1 路 12bit ADC,I2C、SPI、USART 等外设
XL32F001 系列单片机采用高性能的 32 位 ARM Cortex-M0内核,宽电压工作范围的 MCU。嵌入 24KbytesFlash 和 3Kbytes SRAM 存储器,最高工作频率 24MHz。包含多种不同封装类型多款产品。芯片集成 I2C、SPI、USART 等通讯外设,1 路 12bit ADC&am…...
typescript基础之null和undefined
TypeScript是一种基于JavaScript的编程语言,它支持静态类型检查和面向对象的特性。TypeScript中的null和undefined是两种基本类型,它们分别表示空值或未定义的值。在本文中,我将介绍TypeScript中null和undefined的含义、区别、检查方法和使用…...
php_mb_strlen指定扩展
1 中文在utf-字符集下占3个字节,所以计算出来长度为9。 2 可以引入php多字节字符的扩展,默认是没有的,需要自己配置这个函数 3 找到php.ini文件,去掉;extension mbstring的注释,接着重启apache服务 可以看到准确输出的中文的长度…...
利用OpenCV光流算法实现视频特征点跟踪
光流简介 光流(optical flow)是运动物体在观察成像平面上的像素运动的瞬时速度。光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。…...
探索无限创造力的星辰大道,画出想象的浩瀚宇宙!-turtle
介绍 视频教程地址在此:https://www.bilibili.com/video/BV1Pm4y1H7Tb/ 大家好,欢迎来到本视频!今天,我们将一同探索Python编程世界中的一个有趣而创意的库——Turtle库。无需专业绘画技能,你就可以轻松地用代码绘制…...
企业数字化转型大数据湖一体化平台项目建设方案PPT
导读:原文《企业数字化转型大数据湖一体化平台项目建设方案PPT》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 喜欢文章,您可以点赞评论转发…...
【3Ds Max】车削命令的简单使用(以制作花瓶为例)
简介 在3ds Max中,"车削"(Lathe)是一种建模命令,用于创建围绕轴线旋转的几何形状。通过车削命令,您可以将一个闭合的平面或曲线几何形状旋转,从而生成一个立体对象。这种方法常用于创建圆柱体、…...
Python 3 使用HBase 总结
HBase 简介和安装 请参考文章:HBase 一文读懂 Python3 HBase API HBase 前期准备 1 安装happybase库操作hbase 安装该库 pip install happybase2 确保 Hadoop 和 Zookeeper 可用并开启 确保Hadoop 正常运行 确保Zookeeper 正常运行3 开启HBase thrift服务 使用命…...
Maven方式构建SpringBoot项目
目录 1、创建maven项目 2、添加springboot相关依赖 3、配置启动端口 4、修改APP文件 5、配置controller 6、启动应用 1、创建maven项目 项目如下: 2、添加springboot相关依赖 <parent><groupId>org.springframework.boot</groupId><arti…...
不花一分钱,利用免费电脑软件将视频MV变成歌曲音频MP3
教程 1.点击下载电脑软件下载地址,点击下载,安装。(没有利益关系,没有打广告,只是单纯教学) 2.安装完成后,点击格式工厂 3.然后如图所示依次,点击【音频】->【-MP3】 3.然后点击…...
运营知识之用户运营(一)触达用户的几种方式
运营知识之用户运营(一)触达用户的几种方式 APP推送短信(DeepLink/Deferred DeepLink):短信拉起app电子邮件 EDM电话/外呼(人工、AI)电话外呼加短信(操作步骤短链)微信生…...
cocos creator pageView 循环展示 广告牌功能
在使用 creator pageView 滑动到最大或者最小为止的时候 滑动不了没法流畅的运行到最开始或者最后那个界面 循环展示 1.策划大人有需要就是要循环流畅的展示 解决方案: 做预制件的时候 最第一个界面之前 做一个最后的界面放到最前边去 比如 1,2,3,4,5,6,7,8 修改成 8,1…...
PyTorch Lightning:通过分布式训练扩展深度学习工作流
一、介绍 欢迎来到我们关于 PyTorch Lightning 系列的第二篇文章!在上一篇文章中,我们向您介绍了 PyTorch Lightning,并探讨了它在简化深度学习模型开发方面的主要功能和优势。我们了解了 PyTorch Lightning 如何为组织和构建 PyTorch 代码提…...
无涯教程-Perl - splice函数
描述 此函数从LENGTH元素的OFFSET元素中删除ARRAY元素,如果指定,则用LIST替换删除的元素。如果省略LENGTH,则从OFFSET开始删除所有内容。 语法 以下是此函数的简单语法- splice ARRAY, OFFSET, LENGTH, LISTsplice ARRAY, OFFSET, LENGTHsplice ARRAY, OFFSET返回值 该函数…...
归并排序:从二路到多路
前言 我们所熟知的快速排序和归并排序都是非常优秀的排序算法。 但是快速排序和归并排序的一个区别就是:快速排序是一种内部排序,而归并排序是一种外部排序。 简单理解归并排序:递归地拆分,回溯过程中,将排序结果进…...
【Vue】运行项目报错 This dependency was not found
背景 运行Vue 项目报错,提示This dependency was not found;然后我根据提示 执行 npm install --save vue/types/umd ,执行后发现错误,我一开始一直以为是我本地装不上这个依赖。后来找了资料后,看到应该是自己的代码里面随意的i…...
Shell编程之正则表达式
文本处理器:三剑客:grep查找sed awk shell正则表达式由一类特殊字符以及文本字符所编写的一种模式,处理文本当中的内容,其中的一些字符不表示字符的字面含义表示一种控制或者通配的功能 通配符:匹配文件名和目录名&a…...
QGraphicsView 实例3地图浏览器
主要介绍Graphics View框架,实现地图的浏览、放大、缩小,以及显示各个位置的视图、场景和地图坐标 效果图: mapwidget.h #ifndef MAPWIDGET_H #define MAPWIDGET_H #include <QLabel> #include <QMouseEvent> #include <QGraphicsView&…...
Windows基础安全知识
目录 常用DOS命令 ipconfig ping dir cd net user 常用DOS命令 内置账户访问控制 Windows访问控制 安全标识符 访问控制项 用户账户控制 UAC令牌 其他安全配置 本地安全策略 用户密码策略复杂性要求 强制密码历史: 禁止密码重复使用 密码最短使用期限…...
自定义注解和自定义注解处理器来扫描所有带有某个特定注解的Controller层
在Spring Boot中,您可以使用自定义注解和自定义注解处理器来扫描所有带有某个特定注解的Controller层。 以下是一个简单的示例,演示如何实现这个功能: 首先,创建自定义注解 CustomAnnotation ,用于标记需要被扫描的C…...
浏览器渲染原理 - 输入url 回车后发生了什么
目录 渲染时间点渲染流水线1,解析(parse)HTML1.1,DOM树1.2,CSSOM树1.3,解析时遇到 css 是怎么做的1.4,解析时遇到 js 是怎么做的 2,样式计算 Recalculate style3,布局 la…...
大文本的全文检索方案附件索引
一、简介 Elasticsearch附件索引是需要插件支持的功能,它允许将文件内容附加到Elasticsearch文档中,并对这些附件内容进行全文检索。本文将带你了解索引附件的原理和使用方法,并通过一个实际示例来说明如何在Elasticsearch中索引和检索文件附…...
35_windows环境debug Nginx 源码-CLion配置CMake和启动
文章目录 生成 CMakeLists.txt 组态档35_windows环境debug Nginx 源码-CLion配置CMake和启动生成 CMakeLists.txt 组态档 修改auto目录configure文件,在 . auto/make 上边增加 . auto/cmake, 大概在 106 行。在 auto 目录下创建cmake 文件其内容如下: #!/usr/bin/env bash NG…...
收集的一些比较好的git网址
1、民间故事 https://github.com/folkstory/lingqiu/blob/master/%E4%BC%A0%E8%AF%B4%E9%83%A8%E5%88%86/%E4%BA%BA%E7%89%A9%E4%BC%A0%E8%AF%B4/%E2%80%9C%E6%B5%B7%E5%BA%95%E6%8D%9E%E6%9C%88%E2%80%9D%E7%9A%84%E6%AD%A6%E4%B8%BE.md 2、童话故事 https://gutenberg.org/c…...