首页 文章 精选 留言 我的

精选列表

搜索[后台管理框架],共10000篇文章
优秀的个人博客,低调大师

爱奇艺基于 Android App Bundle 动态化框架 Qigsaw 1.2.3 版本发布啦

经过各个接入方配合,迄今最稳定版本1.2.3正式发布了,解决若干打包编译问题。 目前已有不少一线知名厂商接入,欢迎咨询。本次版本更新记录如下: Qigsaw-Gradle-Plugin 适配增量编译问题。 Qigsaw-Gradle-Plugin 提供 qigsawInstall${variantName} 命令,通过该命令可以安装 qigsaw 生成的APK。 Qigsaw-Gradle-Plugin 插件升级流程体验优化。 提供 Qigsaw#registerSplitActivityLifecycleCallbacks 方法,可监听插件 Activity 生命周期回调。接入方通过该接口可以统计插件DAU。 Qigsaw-Gradle-Plugin 若干 bug 修复。

优秀的个人博客,低调大师

HP-Socket v5.6.3,高性能跨平台网络通信框架

项目主页:http://www.oschina.net/p/hp-socket 开发文档: https://www.docin.com/p-2257033571.html 下载地址: https://github.com/ldcsaa/HP-Socket 本次更新主要对 SSL、HTTP 和 UDP 系列组件作了优化和调整! v5.6.3 更新 一、SSL 组件更新 所有 SSL 组件增加以下接口方法支持加载内存证书 1) Server:SetupSSLContextByMemory(), AddSSLContextByMemory() 2) Agent:SetupSSLContextByMemory() 3) Client:SetupSSLContextByMemory() 所有 SSL 组件增加 GetSSLSessionInfo() 方法,用来获取 SSL 会话相关信息 SSL Server 组件提供默认的 SNI 服务器域名绑定机制,大多数情形下应用程序不必自定义 SNI 回调函数 1) 当 SetupSSLContext() 的 'fnServerNameCallback' 参数值为 nullptr 则启用默认的服务器域名绑定机制 2) BindSSLServerName():绑定服务器域名到指定证书 3) HP_SSL_DefaultServerNameCallback():默认 SNI 回调函数 二、HTTP 组件更新 HTTP Server 组件的 SendWSMessage() 方法删除 lpszMask 参数 所有 HTTP 组件的 SendWSMessage() 方法的 pData 参数类型改为 const BYTE*,因此可以传入常量 所有 HTTP 组件添加 SendChunkData() 方法以方便地发送 Chunked 数据 三、UDP 组件更新 优化 Linux 平台的 UDP Cast 组件,使得其与 Windows 平台的 UDP Cast 组件保持行为一致 提升所有 UDP 组件的 IPv6 兼容性 UDP Client/Server 组件关闭时自动向对端发送“关闭通知”数据报 四、其他更新 jemalloc 升级到 5.2.1 版本 OpenSSL 升级到 1.1.1d 版本 代码优化,提高稳定性 HP-Socket 组件列表 基础组件 SSL 组件 HTTP 组件

优秀的个人博客,低调大师

爱奇艺基于 Android App Bundle 动态化框架 Qigsaw 1.2.0 版本发布啦

更新日志如下: 修复多ClassLoader模式,插件Application可能未初始化的问题。 插件多ABI支持,依据用户当前设备CPU架构及APK自身ABIs来加载对应插件ABI的Native Library。 依据项目工程NDK配置以及APK文件lib目录的ABI类型,来自动选择内置插件存放APK lib还是assets目录。内置插件存放APK lib目录可减少插件一次拷贝工作,节省用户磁盘空间。 Qigsaw Gradle Plugin 修复3.2~3.5兼容性bug。 调整Report相关接口,包括SplitLoadReporter、SplitInstallReporter等,提供更多插件信息供开发者投递。 SplitInstallReporter 和 SplitLoadReporter 失败通知,包含已加载或安装成功的插件数据。 应 Qigsaw 接入者需求,增加是否校验插件签名配置。详情参考 SplitConfiguration 中 verifySignature 配置。

优秀的个人博客,低调大师

一个高准确率的Flutter埋点框架如何设计

作者:闲鱼技术-兰昊 背景 用户行为埋点是用来记录用户在操作时的一系列行为,也是业务做判断的核心数据依据,如果缺失或者不准确将会给业务带来不可恢复的损失。闲鱼将业务代码从Native迁移到Flutter上过程中,发现原先Native体系上的埋点方案无法应用在Flutter体系之上。而如果我们只把业务功能迁移过来就上线,对业务是极其不负责任的。因此,经过不断探索,我们沉淀了一套Flutter上的高准确率的用户行为埋点方案。 用户行为埋点定义 先来讲讲在我们这里是如何定义用户行为埋点的。在如下用户时间轴上,用户进入A页面后,看到了按钮X,然后点击了这个按钮,随即打开了新的页面B。 这个时间轴上有如下5个埋点事件发生: 进入A页面。A页面首帧渲染完毕,并获得了焦点。 曝光坑位X。按钮X处于手机屏幕内,且停留一段时间,让用户可见可触摸。 点击坑位X。用户

优秀的个人博客,低调大师

GO从入门到进阶教程系列 - 研发高性能ORM框架操作mysql篇

上一篇教程我们了解到了基础的GO语法,今天我们来学习如何使用GO操作mysq,下面就直接进入步骤操作环节 技术版权归属 广州市金狮网络科技有限公司 (https://kingc.cn/) ,如需商用请联系公司 1. 先获取mysql驱动,类似Java加载驱动jar, 通过window cmd命令或者Linux控制台执行 go get github.com/go-sql-driver/mysql 2. 我们先写个数据库连接对象方便扩展 // 数据库配置 type DBConfig struct { Host string // 地址IP Port int // 数据库端口 Database string // 数据库名称 Username string // 账号 Password string // 密码 } 3. 通过数据库配置进行mysql实例化 func NewMysql() (*sql.DB, error) { // 初始化mysql连接参数 conf := DBConfig{ Host: "127.0.0.1", Port: 3306, Database: "test", Username: "root", Password: "123456", } // 定义占位符字符串,使用配置值替换%s和%d link := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", conf.Username, conf.Password, conf.Host, conf.Port, conf.Database) // 打开mysql获得实例对象 db, err := sql.Open("mysql", link) // 打开mysql失败,返回nil对象,以及返回err对象 if err != nil { panic(util.AddStr("mysql初始化失败: ", err.Error())) return nil, errors.New("mysql初始化失败: " + err.Error()) } // 打开mysql成功返回db对象,err=nil return db, nil } 4. 获得mysql操作实例后,进行增删查改操作(由于时间关系,暂时只写了新增示例,包含事务和非事务) func CRUD(db *sql.DB) error { // 编写需要执行的sql createSql := "insert test_user(username, password, age, sex) values(?,?,?,?)" // 预编译sql stmt, err := db.Prepare(createSql) if err != nil { panic("预编译失败: " + err.Error()) } // 提交编译sql对应参数 ret, err := stmt.Exec("zhangsan", "123456", 18, 1) if err != nil { panic("提交数据失败: " + err.Error()) } // 保存成功后获取自增ID fmt.Println(ret.LastInsertId()) return nil } func CRUD1(db *sql.DB) error { // 编写需要执行的sql createSql := "insert test_user(username, password, age, sex) values(?,?,?,?)" // 预编译sql,事务模式 tx, err := db.Begin() if err != nil { panic("开启事务失败: " + err.Error()) } stmt, err := tx.Prepare(createSql) if err != nil { tx.Rollback() // 回滚事务 panic("预编译失败: " + err.Error()) } // 提交编译sql对应参数 ret, err := stmt.Exec("zhangsan", "123456", 18, 1) if err != nil { tx.Rollback() // 回滚事务 panic("提交数据失败: " + err.Error()) } // 保存成功后获取自增ID fmt.Println(ret.LastInsertId()) tx.Commit() // 提交事务 return nil } 5. 最后执行测试用例test func TestMysql1(t *testing.T) { db, err := NewMysql() if err != nil { panic(err) } CRUD(db) } func TestMysql2(t *testing.T) { db, err := NewMysql() if err != nil { panic(err) } CRUD1(db) } 上面的几个示例基本涵盖GO操作mysql的用法,下一篇文章我会讲解如何封装可扩展性强的mysql底层,敬请期待!

优秀的个人博客,低调大师

go微服务框架go-micro深度学习(五) stream 调用过程详解

上一篇写了一下rpc调用过程的实现方式,简单来说就是服务端把实现了接口的结构体对象进行反射,抽取方法,签名,保存,客户端调用的时候go-micro封请求数据,服务端接收到请求时,找到需要调用调用的对象和对应的方法,利用反射进行调用,返回数据。 但是没有说stream的实现方式,感觉单独写一篇帖子来说这个更好一些。上一篇帖子是基础,理解了上一篇,stream实现原理一点即破。先说一下使用方式,再说原理。当前go-micro对 rpc 调用的方式大概如下:普通的rpc调用 是这样: 1.连接服务器或者从缓存池得到连接 2.客户端 ->发送数据 -> 服务端接收 3.服务端 ->返回数据 -> 客户端处理数据 4.关闭连接或者把连接返回到缓存池 当前 rps stream的实现方式 是这样子: 1. 连接服务器 2. 客户端多次发送请求-> 服务端接收 3. 服务端多次返回数据-> 客户端处理数据 4. 关闭连接 当数据量比较大的时候我们可以用stream方式分批次传输数据。对于客户端还是服务端没有限制,我们可以根据自己的需要使用stream方式,使用方式也非常的简单,在定义接口的时候在参数或者返回值前面加上stream然后就可以多次进行传输了,使用的代码还是之前写的例子,代码都在github上: 比如我的例子中定义了两个使用stream的接口,一个只在返回值使用stream,另一个是在参数和返回值前都加上了stream,最终的使用方式没有区别 rpc Stream(model.SRequest) returns (stream model.SResponse) {} rpc BidirectionalStream(stream model.SRequest) returns (stream model.SResponse) {} 看一下go-micro为我们生成的代码rpcapi.micro.go里,不要被吓到,生成了很多代码,但是没啥理解不了的Server端 // Server API for Say service type SayHandler interface { // .... others Stream(context.Context, *model.SRequest, Say_StreamStream) error BidirectionalStream(context.Context, Say_BidirectionalStreamStream) error } type Say_StreamStream interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error Send(*model.SResponse) error } type Say_BidirectionalStreamStream interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error Send(*model.SResponse) error Recv() (*model.SRequest, error) } // .... others Client端 // Client API for Say service type SayService interface { //... others Stream(ctx context.Context, in *model.SRequest, opts ...client.CallOption) (Say_StreamService, error) BidirectionalStream(ctx context.Context, opts ...client.CallOption) (Say_BidirectionalStreamService, error) } type Say_StreamService interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error Recv() (*model.SResponse, error) } type Say_BidirectionalStreamService interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error Send(*model.SRequest) error Recv() (*model.SResponse, error) } 你会发现参数前面加了 Stream后,生成的代码会把你的参数变成一个接口,这个接口主要要的方法是 SendMsg(interface{}) error RecvMsg(interface{}) error Close() error 剩下的两个接口方法是根据你是发送还是接收生成的,如果有发送就会有Send(你的参数),如果有接收会生成Rev() (你的参数, error),但这两个方法只是为了让你使用时方便,里面调用的还是SendMsg(interface)和RecvMsg(interface)方法,但是他们是怎么工作的,如何多次发送和接收传输的数据,是不是感觉很神奇。 我就以TsBidirectionalStream 方法为例开始分析,上一篇和再早之前的帖子已经说了服务端启动的时候都做了哪些操作,这里就不再赘述,服务端的实现,很简单,不断的获取客户端发过来的数据,再给客户端一次一次的返回一些数据。 /* 模拟数据 */ func (s *Say) BidirectionalStream(ctx context.Context, stream rpcapi.Say_BidirectionalStreamStream) error { for { req, err := stream.Recv() if err == io.EOF { break } if err != nil { return err } for i := int64(0); i < req.Count; i++ { if err := stream.Send(&model.SResponse{Value: []string {lib.RandomStr(lib.Random(3, 6))}}); err != nil { return err } } } return nil } 启动服务,服务开始监听客户端传过来的数据.....客户端调用服务端方法: // 调用 func TsBidirectionalStream(client rpcapi.SayService) { rspStream, err := client.BidirectionalStream(context.Background()) if err != nil { panic(err) } // send go func() { rspStream.Send(&model.SRequest{Count: 2}) rspStream.Send(&model.SRequest{Count: 5}) // close the stream if err := rspStream.Close(); err != nil { fmt.Println("stream close err:", err) } }() // recv idx := 1 for { rsp, err := rspStream.Recv() if err == io.EOF { break } else if err != nil { panic(err) } fmt.Printf("test stream get idx %d data %v\n", idx, rsp) idx++ } fmt.Println("Read Value End") } 当客户端在调用rpc的stream方法是要很得到stream rspStream, err := client.BidirectionalStream(context.Background()) // func (c *sayService) BidirectionalStream(ctx context.Context, opts ...client.CallOption) (Say_BidirectionalStreamService, error) { req := c.c.NewRequest(c.name, "Say.BidirectionalStream", &model.SRequest{}) stream, err := c.c.Stream(ctx, req, opts...) if err != nil { return nil, err } return &sayServiceBidirectionalStream{stream}, nil } 这个调用c.c.Stream(ctx, req, opts...)是关键,他的内部实现就是和服务器进行连接,然后返回一个stream,进行操作。 客户端:和服务端建立连接,返回Stream,进行接收和发送数据 服务端:接收客户端连接请求,利用反射找到相应的方法,组织Strem,传给方法,进行数据的发送和接收 建立连接的时候就是一次rpc调用,服务端接受连接,然后客户端发送一次调用,但是传输的是空数据,服务端利用反射找到具体的方法,组织stream,调用具体方法,利用这个连接,客户端和服务端进行多次通信。

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册