一个好的程序员不应被语言所束缚,正如我现在开源java的orm框架一样,如果您是一位转java的c#程序员,那么这个框架可以带给你起码没有那么差的业务编写和强类型体验。如果您是一位java程序员,那么该框架可以提供比Mybatis-Plus
功能更加丰富、性能更高,更加轻量和完全免费的体验来做一个happy coding crud body。
easy-query
该框架是我在使用Mybatis-Plus
(下面统称MP) 2年后开发的,因为MP
不支持多表(不要提join插件(逻辑删除子表不支持)),并且Mybatis
原本的xml十分恶心,导致项目中有非常多的代码需要编写sql,并且整体数据库架构因为存在逻辑删除字段和多租户字段所以编写的sql基本上多多少少都会有问题,我不相信大家没遇到过,而且MP得一些功能还需要收费这大大让我坚定还是自己开发一款。
easy-query
? 是一款无任何依赖的JAVA ORM 框架,十分轻量,拥有非常高的性能,支持单表查询、多表查询、union、子查询、分页、动态表名、VO对象查询返回、逻辑删、全局拦截、数据库列加密(支持高性能like查询)、数据追踪差异更新、乐观锁、多租户、自动分库、自动分表、读写分离,支持框架全功能外部扩展定制,拥有强类型表达式。
GITHUB github地址
GITEE gitee地址
GITHUB地址 | GITEE地址
先说一下缺点,目前只适配了MySql,不过基本上如果你是pgsql很少需要改动就直接可以用了,其他数据库可能因为自己的语法和特性会需要稍微做一下修改但是整体而言无需过多的变动,框架已经全部抽象好了。
sharding-core
作者不支持说不过去),全自动分库分表,仅需用户新增表和告知easy-query
系统中有的表目前项目正处于起步阶段后续会随着用户不断地完善各数据库的适配和功能的支持
以下是spring-boot
环境和控制台模式的安装
<properties>
<easy-query.version>0.8.10</easy-query.version>
</properties>
<dependency>
<groupId>com.easy-query</groupId>
<artifactId>sql-springboot-starter</artifactId>
<version>${easy-query.version}</version>
</dependency>
以mysql为例
<properties>
<easy-query.version>0.8.10</easy-query.version>
</properties>
<dependency>
<groupId>com.easy-query</groupId>
<artifactId>sql-mysql</artifactId>
<version>${easy-query.version}</version>
</dependency>
//初始化连接池
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/easy-query-test?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setMaximumPoolSize(20);
//创建easy-query
EasyQuery easyQuery = EasyQueryBootstrapper.defaultBuilderConfiguration()
.setDefaultDataSource(dataSource)
.useDatabaseConfigure(new MySQLDatabaseConfiguration())
.build();
sql脚本
create table t_topic
(
id varchar(32) not null comment '主键ID'primary key,
stars int not null comment '点赞数',
title varchar(50) null comment '标题',
create_time datetime not null comment '创建时间'
)comment '主题表';
create table t_blog
(
id varchar(32) not null comment '主键ID'primary key,
deleted tinyint(1) default 0 not null comment '是否删除',
create_by varchar(32) not null comment '创建人',
create_time datetime not null comment '创建时间',
update_by varchar(32) not null comment '更新人',
update_time datetime not null comment '更新时间',
title varchar(50) not null comment '标题',
content varchar(256) null comment '内容',
url varchar(128) null comment '博客链接',
star int not null comment '点赞数',
publish_time datetime null comment '发布时间',
score decimal(18, 2) not null comment '评分',
status int not null comment '状态',
`order` decimal(18, 2) not null comment '排序',
is_top tinyint(1) not null comment '是否置顶',
top tinyint(1) not null comment '是否置顶'
)comment '博客表';
查询对象
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = -4834048418175625051L;
@Column(primaryKey = true)
private String id;
/**
* 创建时间;创建时间
*/
private LocalDateTime createTime;
/**
* 修改时间;修改时间
*/
private LocalDateTime updateTime;
/**
* 创建人;创建人
*/
private String createBy;
/**
* 修改人;修改人
*/
private String updateBy;
/**
* 是否删除;是否删除
*/
@LogicDelete(strategy = LogicDeleteStrategyEnum.BOOLEAN)
private Boolean deleted;
}
@Data
@Table("t_topic")
@ToString
public class Topic {
@Column(primaryKey = true)
private String id;
private Integer stars;
private String title;
private LocalDateTime createTime;
}
@Data
@Table("t_blog")
public class BlogEntity extends BaseEntity{
/**
* 标题
*/
private String title;
/**
* 内容
*/
private String content;
/**
* 博客链接
*/
private String url;
/**
* 点赞数
*/
private Integer star;
/**
* 发布时间
*/
private LocalDateTime publishTime;
/**
* 评分
*/
private BigDecimal score;
/**
* 状态
*/
private Integer status;
/**
* 排序
*/
private BigDecimal order;
/**
* 是否置顶
*/
private Boolean isTop;
/**
* 是否置顶
*/
private Boolean top;
}
Topic topic = easyQuery
.queryable(Topic.class)
.where(o -> o.eq(Topic::getId, "3"))
.firstOrNull();
==> Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t WHERE t.`id` = ? LIMIT 1
==> Parameters: 3(String)
<== Time Elapsed: 15(ms)
<== Total: 1
Topic topic = easyQuery
.queryable(Topic.class)
.leftJoin(BlogEntity.class, (t, t1) -> t.eq(t1, Topic::getId, BlogEntity::getId))
.where(o -> o.eq(Topic::getId, "3"))
.firstOrNull();
==> Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t LEFT JOIN `t_blog` t1 ON t1.`deleted` = ? AND t.`id` = t1.`id` WHERE t.`id` = ? LIMIT 1
==> Parameters: false(Boolean),3(String)
<== Time Elapsed: 2(ms)
<== Total: 1
join + group +分页
EasyPageResult<BlogEntity> page = easyQuery
.queryable(Topic.class).asTracking()
.innerJoin(BlogEntity.class, (t, t1) -> t.eq(t1, Topic::getId, BlogEntity::getId))
.where((t, t1) -> t1.isNotNull(BlogEntity::getTitle))
.groupBy((t, t1)->t1.column(BlogEntity::getId))
.select(BlogEntity.class, (t, t1) -> t1.column(BlogEntity::getId).columnSum(BlogEntity::getScore))
.toPageResult(1, 20);
==> Preparing: SELECT t1.`id`,SUM(t1.`score`) AS `score` FROM `t_topic` t INNER JOIN `t_blog` t1 ON t1.`deleted` = ? AND t.`id` = t1.`id` WHERE t1.`title` IS NOT NULL GROUP BY t1.`id` LIMIT 20
==> Parameters: false(Boolean)
<== Time Elapsed: 5(ms)
<== Total: 20
String sql = easyQuery.queryable(BlogEntity.class)
.asTable(a->"aa_bb_cc")
.where(o -> o.eq(BlogEntity::getId, "123"))
.toSQL();
SELECT t.`id`,t.`create_time`,t.`update_time`,t.`create_by`,t.`update_by`,t.`deleted`,t.`title`,t.`content`,t.`url`,t.`star`,t.`publish_time`,t.`score`,t.`status`,t.`order`,t.`is_top`,t.`top` FROM `aa_bb_cc` t WHERE t.`deleted` = ? AND t.`id` = ?
Topic topic = new Topic();
topic.setId(String.valueOf(0));
topic.setStars(100);
topic.setTitle("标题0");
topic.setCreateTime(LocalDateTime.now().plusDays(i));
long rows = easyQuery.insertable(topic).executeRows();
//返回结果rows为1
==> Preparing: INSERT INTO `t_topic` (`id`,`stars`,`title`,`create_time`) VALUES (?,?,?,?)
==> Parameters: 0(String),100(Integer),标题0(String),2023-03-16T21:34:13.287(LocalDateTime)
<== Total: 1
//实体更新
Topic topic = easyQuery.queryable(Topic.class)
.where(o -> o.eq(Topic::getId, "7")).firstNotNull("未找到对应的数据");
String newTitle = "test123" + new Random().nextInt(100);
topic.setTitle(newTitle);
long rows=easyQuery.updatable(topic).executeRows();
==> Preparing: UPDATE t_topic SET `stars` = ?,`title` = ?,`create_time` = ? WHERE `id` = ?
==> Parameters: 107(Integer),test12364(String),2023-03-27T22:05:23(LocalDateTime),7(String)
<== Total: 1
//表达式更新
long rows = easyQuery.updatable(Topic.class)
.set(Topic::getStars, 12)
.where(o -> o.eq(Topic::getId, "2"))
.executeRows();
//rows为1
easyQuery.updatable(Topic.class)
.set(Topic::getStars, 12)
.where(o -> o.eq(Topic::getId, "2"))
.executeRows(1,"更新失败");
//判断受影响行数并且进行报错,如果当前操作不在事务内执行那么会自动开启事务!!!会自动开启事务!!!会自动开启事务!!!来实现并发更新控制,异常为:EasyQueryConcurrentException
//抛错后数据将不会被更新
==> Preparing: UPDATE t_topic SET `stars` = ? WHERE `id` = ?
==> Parameters: 12(Integer),2(String)
<== Total: 1
long l = easyQuery.deletable(Topic.class)
.where(o->o.eq(Topic::getTitle,"title998"))
.executeRows();
==> Preparing: DELETE FROM t_topic WHERE `title` = ?
==> Parameters: title998(String)
<== Total: 1
Topic topic = easyQuery.queryable(Topic.class).whereId("997").firstNotNull("未找到当前主题数据");
long l = easyQuery.deletable(topic).executeRows();
==> Preparing: DELETE FROM t_topic WHERE `id` = ?
==> Parameters: 997(String)
<== Total: 1
Queryable<Topic> q1 = easyQuery
.queryable(Topic.class);
Queryable<Topic> q2 = easyQuery
.queryable(Topic.class);
Queryable<Topic> q3 = easyQuery
.queryable(Topic.class);
List<Topic> list = q1.union(q2, q3).where(o -> o.eq(Topic::getId, "123321")).toList();
==> Preparing: SELECT t1.`id`,t1.`stars`,t1.`title`,t1.`create_time` FROM (SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t UNION SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t UNION SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t) t1 WHERE t1.`id` = ?
==> Parameters: 123321(String)
<== Time Elapsed: 19(ms)
<== Total: 0
Queryable<String> idQueryable = easyQuery.queryable(BlogEntity.class)
.where(o -> o.eq(BlogEntity::getId, "1"))
.select(String.class,o->o.column(BlogEntity::getId));
List<Topic> list = easyQuery
.queryable(Topic.class, "x").where(o -> o.in(Topic::getId, idQueryable)).toList();
==> Preparing: SELECT x.`id`,x.`stars`,x.`title`,x.`create_time` FROM `t_topic` x WHERE x.`id` IN (SELECT t.`id` FROM `t_blog` t WHERE t.`deleted` = ? AND t.`id` = ?)
==> Parameters: false(Boolean),1(String)
<== Time Elapsed: 3(ms)
<== Total: 1
Queryable<BlogEntity> where1 = easyQuery.queryable(BlogEntity.class)
.where(o -> o.eq(BlogEntity::getId, "1"));
List<Topic> x = easyQuery
.queryable(Topic.class, "x").where(o -> o.exists(where1.where(q -> q.eq(o, BlogEntity::getId, Topic::getId)))).toList();
==> Preparing: SELECT x.`id`,x.`stars`,x.`title`,x.`create_time` FROM `t_topic` x WHERE EXISTS (SELECT 1 FROM `t_blog` t WHERE t.`deleted` = ? AND t.`id` = ? AND t.`id` = x.`id`)
==> Parameters: false(Boolean),1(String)
<== Time Elapsed: 10(ms)
<== Total: 1
easy-query
支持分表、分库、分表+分库
//创建分片对象
@Data
@Table(value = "t_topic_sharding_time",shardingInitializer = TopicShardingTimeShardingInitializer.class)
@ToString
public class TopicShardingTime {
@Column(primaryKey = true)
private String id;
private Integer stars;
private String title;
@ShardingTableKey
private LocalDateTime createTime;
}
//分片初始化器很简单 假设我们是2020年1月到2023年5月也就是当前时间进行分片那么要生成对应的分片表每月一张
public class TopicShardingTimeShardingInitializer extends AbstractShardingMonthInitializer<TopicShardingTime> {
@Override
protected LocalDateTime getBeginTime() {
return LocalDateTime.of(2020, 1, 1, 1, 1);
}
@Override
protected LocalDateTime getEndTime() {
return LocalDateTime.of(2023, 5, 1, 0, 0);
}
@Override
public void configure0(ShardingEntityBuilder<TopicShardingTime> builder) {
////以下条件可以选择配置也可以不配置用于优化分片性能
// builder.paginationReverse(0.5,100)
// .ascSequenceConfigure(new TableNameStringComparator())
// .addPropertyDefaultUseDesc(TopicShardingTime::getCreateTime)
// .defaultAffectedMethod(false, ExecuteMethodEnum.LIST,ExecuteMethodEnum.ANY,ExecuteMethodEnum.COUNT,ExecuteMethodEnum.FIRST)
// .useMaxShardingQueryLimit(2,ExecuteMethodEnum.LIST,ExecuteMethodEnum.ANY,ExecuteMethodEnum.FIRST);
}
}
//分片时间路由规则按月然后bean分片属性就是LocalDateTime也可以自定义实现
public class TopicShardingTimeTableRule extends AbstractMonthTableRule<TopicShardingTime> {
@Override
protected LocalDateTime convertLocalDateTime(Object shardingValue) {
return (LocalDateTime)shardingValue;
}
}
数据库脚本参考源码
其中shardingInitializer
为分片初始化器用来初始化告诉框架有多少分片的表名(支持动态添加)
ShardingTableKey
表示哪个字段作为分片键(分片键不等于主键)
执行sql
LocalDateTime beginTime = LocalDateTime.of(2021, 1, 1, 1, 1);
LocalDateTime endTime = LocalDateTime.of(2021, 5, 2, 1, 1);
Duration between = Duration.between(beginTime, endTime);
long days = between.toDays();
List<TopicShardingTime> list = easyQuery.queryable(TopicShardingTime.class)
.where(o->o.rangeClosed(TopicShardingTime::getCreateTime,beginTime,endTime))
.orderByAsc(o -> o.column(TopicShardingTime::getCreateTime))
.toList();
==> SHARDING_EXECUTOR_2, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_time_202101` t WHERE t.`create_time` >= ? AND t.`create_time` <= ? ORDER BY t.`create_time` ASC
==> SHARDING_EXECUTOR_3, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_time_202102` t WHERE t.`create_time` >= ? AND t.`create_time` <= ? ORDER BY t.`create_time` ASC
==> SHARDING_EXECUTOR_2, name:ds2020, Parameters: 2021-01-01T01:01(LocalDateTime),2021-05-02T01:01(LocalDateTime)
==> SHARDING_EXECUTOR_3, name:ds2020, Parameters: 2021-01-01T01:01(LocalDateTime),2021-05-02T01:01(LocalDateTime)
<== SHARDING_EXECUTOR_3, name:ds2020, Time Elapsed: 3(ms)
<== SHARDING_EXECUTOR_2, name:ds2020, Time Elapsed: 3(ms)
==> SHARDING_EXECUTOR_2, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_time_202103` t WHERE t.`create_time` >= ? AND t.`create_time` <= ? ORDER BY t.`create_time` ASC
==> SHARDING_EXECUTOR_3, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_time_202104` t WHERE t.`create_time` >= ? AND t.`create_time` <= ? ORDER BY t.`create_time` ASC
==> SHARDING_EXECUTOR_2, name:ds2020, Parameters: 2021-01-01T01:01(LocalDateTime),2021-05-02T01:01(LocalDateTime)
==> SHARDING_EXECUTOR_3, name:ds2020, Parameters: 2021-01-01T01:01(LocalDateTime),2021-05-02T01:01(LocalDateTime)
<== SHARDING_EXECUTOR_3, name:ds2020, Time Elapsed: 2(ms)
<== SHARDING_EXECUTOR_2, name:ds2020, Time Elapsed: 2(ms)
==> main, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_time_202105` t WHERE t.`create_time` >= ? AND t.`create_time` <= ? ORDER BY t.`create_time` ASC
==> main, name:ds2020, Parameters: 2021-01-01T01:01(LocalDateTime),2021-05-02T01:01(LocalDateTime)
<== main, name:ds2020, Time Elapsed: 2(ms)
<== Total: 122
@Data
@Table(value = "t_topic_sharding_ds",shardingInitializer = DataSourceAndTableShardingInitializer.class)
@ToString
public class TopicShardingDataSource {
@Column(primaryKey = true)
private String id;
private Integer stars;
private String title;
@ShardingDataSourceKey
private LocalDateTime createTime;
}
public class DataSourceShardingInitializer implements EntityShardingInitializer<TopicShardingDataSource> {
@Override
public void configure(ShardingEntityBuilder<TopicShardingDataSource> builder) {
EntityMetadata entityMetadata = builder.getEntityMetadata();
String tableName = entityMetadata.getTableName();
List<String> tables = Collections.singletonList(tableName);
LinkedHashMap<String, Collection<String>> initTables = new LinkedHashMap<String, Collection<String>>() {{
put("ds2020", tables);
put("ds2021", tables);
put("ds2022", tables);
put("ds2023", tables);
}};
builder.actualTableNameInit(initTables);
}
}
//分库数据源路由规则
public class TopicShardingDataSourceRule extends AbstractDataSourceRouteRule<TopicShardingDataSource> {
@Override
protected RouteFunction<String> getRouteFilter(TableAvailable table, Object shardingValue, ShardingOperatorEnum shardingOperator, boolean withEntity) {
LocalDateTime createTime = (LocalDateTime) shardingValue;
String dataSource = "ds" + createTime.getYear();
switch (shardingOperator){
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
return ds-> dataSource.compareToIgnoreCase(ds)<=0;
case LESS_THAN:
{
//如果小于月初那么月初的表是不需要被查询的
LocalDateTime timeYearFirstDay = LocalDateTime.of(createTime.getYear(),1,1,0,0,0);
if(createTime.isEqual(timeYearFirstDay)){
return ds->dataSource.compareToIgnoreCase(ds)>0;
}
return ds->dataSource.compareToIgnoreCase(ds)>=0;
}
case LESS_THAN_OR_EQUAL:
return ds->dataSource.compareToIgnoreCase(ds)>=0;
case EQUAL:
return ds->dataSource.compareToIgnoreCase(ds)==0;
default:return t->true;
}
}
}
LocalDateTime beginTime = LocalDateTime.of(2020, 1, 1, 1, 1);
LocalDateTime endTime = LocalDateTime.of(2023, 5, 1, 1, 1);
Duration between = Duration.between(beginTime, endTime);
long days = between.toDays();
EasyPageResult<TopicShardingDataSource> pageResult = easyQuery.queryable(TopicShardingDataSource.class)
.orderByAsc(o -> o.column(TopicShardingDataSource::getCreateTime))
.toPageResult(1, 33);
==> SHARDING_EXECUTOR_23, name:ds2022, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_ds` t ORDER BY t.`create_time` ASC LIMIT 33
==> SHARDING_EXECUTOR_11, name:ds2021, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_ds` t ORDER BY t.`create_time` ASC LIMIT 33
==> SHARDING_EXECUTOR_2, name:ds2020, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_ds` t ORDER BY t.`create_time` ASC LIMIT 33
==> SHARDING_EXECUTOR_4, name:ds2023, Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic_sharding_ds` t ORDER BY t.`create_time` ASC LIMIT 33
<== SHARDING_EXECUTOR_4, name:ds2023, Time Elapsed: 4(ms)
<== SHARDING_EXECUTOR_23, name:ds2022, Time Elapsed: 4(ms)
<== SHARDING_EXECUTOR_2, name:ds2020, Time Elapsed: 4(ms)
<== SHARDING_EXECUTOR_11, name:ds2021, Time Elapsed: 6(ms)
<== Total: 33
希望看到这边的各位大佬给我点个star谢谢这对我很重要
GITHUB github地址
GITEE gitee地址
大家好,又见面了,我是你们的朋友全栈君。//我这个封装通过promise返回出去!!! //我这个封装通过promise返回出去!!! //创建数据库或者有该数据库就打开,这一步必须要! exportfunctionopenSqlite(cb){ //创建数据库或者打开 //这plus.sqlite只在手机上运行 plus.sqlite.openDatabase({ name:‘wallet’,//数据库名称 path:‘_doc/wallet.db’,//数据库地址,uniapp推荐以下划线为开头,这到底存在哪里去了,我也不清楚,哈哈 success(e){ cb(e) }, fail(e){ cb(e) } }) }//在该数据库里创建表格,这一步也必须要! //下面注释里说的都是说sql:’createtableifnotexists….这里 //userInfo是表格名,你也可以写其他的名,不能用数字作为表格名的开头!!! //括号里是表格的结构,列,这里我写了四列,list,id,gender,avatar这四列 //list后面大写的英文是自动增加的意思,因为表格里
2022年7月30日消息,日前传闻的国家集成电路产业投资基金(以下简称“大基金”)总裁丁文武被调查的消息,今日得到了官方的进一步确认。据中央纪委国家监委驻工业和信息化部纪检监察组、北京市监察委员会消息:国家集成电路产业投资基金股份有限公司总经理丁文武涉嫌严重违纪违法,经中央纪委国家监委指定管辖,目前正接受中央纪委国家监委驻工业和信息化部纪检监察组纪律审查、北京市监委监察调查。不久之前的7月15日,根据中央纪委国家监委驻国家开发银行纪检监察组、吉林省纪委监委的通报,国家开发银行国开发展基金管理部原副主任路军涉嫌严重违纪违法,目前正接受中央纪委国家监委驻国家开发银行纪检监察组纪律审查和吉林省监委监察调查。而路军同时也是大基金管理公司——华芯投资管理有限责任公司(以下简称“华芯投资”)原总裁。更早之前的2021年11月,中央纪委国家监委网站发布消息称,大基金管理人——华芯投资管理有限责任公司原副总裁高松涛涉嫌严重违法,正在接受监察调查。 从目前官方公告来看,仅9个月不到的时间,就有三位大基金相关的高管或原高管被调查,且均是因为“涉嫌严重违法违纪”,显然,大基金内部的管理可能确实存在问题,正面
1、安装OpenLDAP yuminstallopenldapopenldap-* serviceslapdstart2、下载 wgethttp://nchc.dl.sourceforge.net/project/phpldapadmin/phpldapadmin-php5/1.2.3/phpldapadmin-1.2.3.tgztar-zxvfphpldapadmin-1.2.3.tgz mvphpldapadmin/var/www/html/3、配置服务vi/etc/sysconfig/ldap,确保SLAPD_LDAPI=yes cp/usr/share/openldap-servers/slapd.conf.obsolete/etc/openldap/slapd.conf cp/usr/share/openldap-servers/DB_CONFIG.example/var/lib/ldap/DB_CONFIGmv/etc/openldap/slapd.d{,.bak} 生成密码: slappasswd [root@LAMP~]#slappasswd Newpassword:
事情是这样的,由于近期Flutter发布了1.17的稳定版,按照“惯例”开始着手把生产项目升级到1.12.13+hotfix.9版本,在升级适配完成之后,一个突如其来的Bug让我陷入了沉思。image如上图所示,可以看到在键盘B页面打开后,退回上一个页面A时键盘已经收起,但是原先键盘所在的区域在A页面变成了空白,而A页面内容也被resize成了键盘弹出后的大小。1、Scaffold针对这个问题,首先想到的Scaffold的resizeToAvoidBottomInset属性。在Flutter中Scaffold默认情况下resizeToAvoidBottomInset为true,当resizeToAvoidBottomInset为true时,Scaffold内部会将mediaQuery.viewInsets.bottom参与到BoxConstraints的大小计算,也就是键盘弹起时调整了内部的bottom位置来迎合键盘。但是问题发送在A界面,这时候键盘已经收起,mediaQuery.viewInsets.bottom应该更新为0,那为何界面没有产生应有的更新呢?2、MediaQuery那
PageAdminCms支持多站点,很适合制作大型站群网站,在站点管理中可以对每个站点进行管理,站点绑定域名,访问目录,站点模板等操作都在此界面进行操作,下面小编介绍一下PageAdmin建站系统站点的添加和管理1、打开站点管理,如下图2、如果需要添加新站点,点击左上角菜单中有一个添加按钮,出现如下界面 下面说一下几个重要参数:2.1、访问目录:必填项,如果没有绑定域名,则网站用:http://系统主域名/my 的形式访问当前站点。2.2、绑定域名:如果填写了此项,则网站用http://my.domain.cn来访问域名,需要注意是,你的服务器站点需要先绑定http://my.domain.cn域名 如果后期网站域名更改了,站点会出现打不开的情况,只需要进入当前管理界面,修改一下绑定域名即可。2.3、模板目录:点击右侧选择目录按钮选择即可。2.4、Gzip压缩:一般选择开启即可,如果确认服务器已经开启了,这里可以选择关闭,主要为了压缩html输出,减少http传输大小,以达到节省网络带宽,提高网站速度的作用。3、如果添加了多个站点,如何在多个站点之间切换管理比如站点栏目,网站信息数据呢
AI科技评论按:ARCore是谷歌于去年2月份正式推出的增强现实(AR)软件开发工具包,给开发者提供了一个开发ARAPP的平台。不到一个月前,谷歌正式推出ARCore1.7版本,为其添加了前置摄像头AR自拍能力以及动画效果支持;而日前,谷歌又为其引入了机器学习技术,使其实时自拍AR的逼真效果更进一步,该技术相关的文章发布在谷歌AI的官方博客上,AI科技评论编译如下。增强现实(AR)通过将数字内容与信息叠加到物质世界的真实场景中,来让人类实现超越现实的感官体验。例如,谷歌地图的AR功能,能够在现实场景中叠加方向信息来为你指路。借助于Pixel相机中的Playground模式,你可以使用AR从不同的视角看世界。并且通过借助于最新发布的「YouTubeStories」以及ARCore全新的面部增强(AugmentedFaces)API,你可以在自拍上添加动画面具、眼镜、帽子、皮肤等特效。实现这种AR功能的关键挑战之一,就是以合适的方式将虚拟内容锚定到现实世界:这一过程需要一套能够追踪到每一次微笑、皱眉或假笑的高动态表面几何结构的独特的感知技术。ARCore的3D网格以及它能实现的一些特效为此
这次的侧边栏通过scrollview和animation两种方法实现通过scrollview实现mysrollview.xml<?xmlversion="1.0"encoding="utf-8"?> <HorizontalScrollViewxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mySrollView1" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/ll_child" android:layout_width="match_parent" android:layout_height="match_parent&q
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/details/78708355 此处主要介绍较为普遍应用的centos6.5和centos7两种版本的默认启动方式修改前提是系统已经安装了GUI,一般默认的官方iso镜像文件都能支持图形界面如果没有安装图形界面,可以运行如下命令进行安装:yumgroupinstall"GNOMEDesktop""GraphicalAdministrationTools"复制【声明】本文参考了网上资源,经过实测可用,所以在此整理完善,希望能帮到你…centos6.5下的操作指导(1).解释Linux有7种运行级别,其实根据文档中的解释就能明白,在此中文说明一下:#Defaultrunlevel.Therunlevelsusedare: #0-halt(DoNOTsetinitdefaulttothis)*关机 #1-Singleusermode*单用户字符界面; #2-Multiuser,withoutN
新媒体管家在电脑上多开微信,在工作中很常见,今天来介绍一种简单的方法。(windows下)这个问题在百度和知乎上都有许多回答,很多都是:长按Enter电脑上怎么登录几个微信(微信多开)?这种方法体验并不好,下面介绍一种超级简单的。。首先在开始中搜索“微信”,右键“打开文件位置”,例如这是我电脑上微信安装的文件目录下一步,复制应用程序的全名WeChat.exe按住Shift,鼠标右键单击空白区域,“在此处打开命令窗口”输入:startWeChat.exe&WeChat.exe回车发现,现在已经出现两个可以登录的微信了、其实方法很简单,就是在微信安装文件的目录下启用start命令,使用&表示多次,三次就是startWeChat.exe&WeChat.exe&WeChat.exe这应该是非常简单的方法了吧,如果你还知道更简单的,欢迎评论交流~
一份包含几千条telnet密码的列表自7月11日起被贴到了Pastebin上,这些密码可以被黑客用来扩大僵尸网络。来自NewSkySecurity的安全研究员AnkitAnubhav发现,这份列表中包含了IP地址、设备名称和telnet密码,列表中大部分的用户名密码组合都是”admin:admin”或者”root:root”等。这整份列表中包含143种密码组合,其中60种密码组合都来自于MiraiTelnet扫描器。这份列表简直就是给黑客们的七夕礼物,通过telnet,黑客可以轻松攻占主机,进而扩大僵尸网络,如果要进行DDoS攻击,其影响也会更大。列表中共有33,138个条目,知名安全专家在推特上转发了它的链接之后火了起来。这份文件已经有22,000+的浏览量。截至目前,这份文件已经被Pastebin官方删除。据统计,前五大密码分别是:root:[blank]—782条 admin:admin—634条 root:root—320条 admin:default—21条 default:[blank]—18条GDI基金会主席VictorGevers分析了这份列表,他发现:有1,775个条
https://www.cnblogs.com/qiantao/p/9832021.html https://bbs.csdn.net/topics/392345001 https://blog.csdn.net/qq_26621859/article/details/103402217 https://blog.csdn.net/the_future_way/article/details/107966718 https://www.cnblogs.com/xielong/p/4686261.html https://www.codedown123.com/37311.html 还可参考filestream https://www.codedown123.com/37311.html 橘子Jane
1IndecisiveTaxiFee 题目链接:https://codeforces.com/problemset/problem/1163/f 2题目描述 时间限制\(2s\)|空间限制\(512M\) 给你一个\(n\)个点,\(m\)条边的无向图,每条边连接点\(u,v\),并且有个长度\(w\)。 有\(q\)次询问,每次询问给你一对\(t,x\),表示仅当前询问下,将\(t\)这条边的长度修改为\(x\),请你输出当前\(1\)到\(n\)的最短路长度。 数据范围: \(2≤?≤2\times10^5,1≤?,?≤2\times10^5\) \(1≤?_?,?_?≤?,1≤?_?≤10^9,?_?≠?_?\) \(1≤?_?≤?,1≤?_?≤10^9\) 3题解 容易发现一共有四种情况:改变的边不在最短路上且变大,改变的边不在最短路上且变小,改变的边在最短路上且变小,改变的边在最短路上且变大。 第一种情况非常简单,容易发现不在最短路上的边变大并不会影响答案,因此直接输出\(dist_{1,n}\)即可。 第二种情况稍微复杂一点点。发现此时除了原最短路之外还有一条强制经过改
Flask-Script从字面意思上来看就是Flask的脚本 是的,熟悉Django的同学是否还记得Django的启动命令呢?pythonmanager.pyrunserver大概是这样对吧 其实Flask也可以做到,基于Flask-Script就可以了-但是你还是得有一个项目就是第十四章的项目点击下载 1.安装Flask-Script pipinstallFlask-Script复制 2.将Flask-Script加入到Flask项目中 1importMyApp 2#导入Flask-Script中的Manager 3fromflask_scriptimportManager 4 5app=MyApp.create_app() 6#让app支持Manager 7manager=Manager(app) 8 9if__name__=='__main__': 10#app.run() 11#替换原有的app.run(),然后大功告成了 12manager.run()复制 MyApp/manager.py 3.使用命令启动Flask项目 pythonmanager.pyrunse
T1:组合 很容易发现,这题需要建个图 建图方法是把每个串的首尾相连,能反过来就建双向边 由于每个串都要用上,所以第一问就是判断是否存在欧拉路,第二问就是欧拉路径 考场前80打了个\(O(n^2)\)带回溯的暴搜,后20口胡了一个\(O(nlogm)\)的最长路路径记录 然后本地得了45分,联考oj得了25,原因: 1. 2. 其实一遍DFS就能找出欧拉路径(没写过。。) 判是否存在欧拉路的以前考过两次,不写了,贴个欧拉路的 voidDFS1(intu,intid){ // for(intx=now[u];x;x=e[x].next){ while(now[u]){ intx=now[u];now[u]=e[x].next; intv=e[x].to; if(black[x])continue; black[x]=1; if(opt==1)black[x^1]=1; DFS1(v,e[x].id); //sta[++top]=e[x].id; } if(id)sta[++top]=id; } 复制 T2:小W的魔术 沙雕题,十几分钟就推出来了 先
基于Node.js,为前端人员提供一个模拟服务端接口数据,一般用在前后端分离测试 安装json-server npminstall-gjson-server 复制 通过查看版本号检查是否安装成功 json-server-V 复制 创建db.json 在任意文件夹下创建db.json文件内容如下 { "posts":[ {"id":1,"title":"json-server","author":"typicode"} ], "comments":[ {"id":1,"body":"somecomment","postId":1} ], "profile":{"name":"typicode"} } 复制 启动json-server cd进入db.json存在的文件夹后运行如下代码 json-server--watchdb.json 复制
更新记录 转载请注明出处: 2022年11月2日发布。 2022年11月1日从笔记迁移到博客。 认证配置(token-basedauthentication) 基于Token方式的认证介绍 基于Token方式的认证和Session对比 Token方式,服务器端可伸缩性更好。 Token方式,状态记录更加方便。 认证生成Token和使用Token流程 Theclientistheapplicationthatistryingtoaccessourresources. Theidentityprovideristheservicethat,givenausernameandapassword,providesanencryptedauthenticationtoken. Theresourceproviderisanotherservicecalledbytheclient.Furthermore,theresourceproviderwillaccepttheencryptedauthenticationtoken,anditwillprovidetheinformationr
一、列表生成式 列表生成式即ListComprehensions,是python内置的非常强大的创建列表的方式。 比如有一个要求,列表a=[0,1,2,3,4,5],要求把列表里的每个值增加1,实现方式有以下几种: #方式一通过for循环 a=[0,1,2,3,4,5] b=[] foriina: b.append(i+1) a=b print(a) #方式二通过enumerate函数 a=[0,1,2,3,4,5] forindex,iinenumerate(a): a[index]+=1 print(a) #方式三通过lambda函数 a=[0,1,2,3,4,5] a=map(lambdax:x+1,a) foriina: print(i) #方式四通过列表生成器 a=[0,1,2,3,4,5] a=[i+1foriina] print(a)复制 ViewCode 列表生成式中,for循环后边还可以加上if判断语句: a=[0,1,2,3,4,5] a=[i+1foriinaifi<3] print(a) 结果:[1,2,3]复制 还可以使用
先上效果图: 就是一个类似微信qq那种item的shape。 即时上代码,少废话。 以下文件均为drawable文件夹下 文件:shape_general_item_top_bg_up.xml <?xmlversion="1.0"encoding="UTF-8"?> <layer-listxmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solidandroid:color="@android:color/white"/> <!--圆角--> <corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp" /><!--设置圆角半径--> <strokeandroi