前言
首先我想说的是,百度,食屎啦你! 垃圾玩意,人家bing、谷歌做网站收录分分钟的事,就你百度叼得一批,一个月都不见收录,还因为爬虫过于频繁被github禁了,导致github上的个人博客百度都搜不到。
好了,开始正文
分享个人经验见解
首先我想说的是,百度,食屎啦你! 垃圾玩意,人家bing、谷歌做网站收录分分钟的事,就你百度叼得一批,一个月都不见收录,还因为爬虫过于频繁被github禁了,导致github上的个人博客百度都搜不到。
好了,开始正文
首先你得将代码上传至github,其次包的命名也是有规范的,如果你没有自己的域名,那么你的group id需要使用github的包路径,如:io.github.你的github用户名
如果拥有自己的域名,那么可以使用域名倒叙作为group id,如:域名为:mysite.blogs.com,那么group id开头即: com.blogs.mysite。
使用自己的域名需要配置dns,具体做法创建工单后工作人员会提示。
要上传jar库到maven中央库首先得注册他们的工单系统账号:https://issues.sonatype.org/ 。
关于注册 : 这里重点注意下密码的坑,不要使用xml中必须要转义的特殊字符作为密码,如’&’ ,否则上传时老是验证失败!
登陆成功后点新建,项目类型选 -> Community Support - Open Source Project Repository Hosting ,问题类型->new project,接着将必填项填上:
1 | Group Id:io.github.yourgithubId #也可以使用自己的域名 |
工单创建完毕后等待我们的Orlina小姐姐处理,由于时差关系所以一般是晚上才有动静,所以趁这个时间将代码上的准备工作解决。
more >>使用mysql作为数据分页查询的时候我们一般使用limit,这样做在数据量不大的情况下是完全没问题的,当数据量达到几百万或者几千万的时候,使用limit速度将会非常的慢,比如在一张600万数据量的表中使用以下sql分页查询
SELECT * FROM TABLE WHERE IS_DELETE=0 LIMIT 5000000,20
也许你查前几页的时候是很快的,比如limit 0,20,但是当分到第几百万行的时候,越往后速度越慢,这是由于mysql的innoDB引擎使用的是B+Tree数据存储结构。
有人可能说数据量上千万了为何不直接分表分库,而我个人觉得分表分库会增加查询的复杂性,能通过优化索引解决的问题还没有必要分表,除非数据量大到了索引无法解决问题的地步.
另外一个,一般很少有业务需求是直接把一张大数据量表的数据分页查询的,一般都是要带点条件,比如订单表那肯定是根据用户ID和删除状态去查,这种情况只需要建好索引即可。
先来看看未优化前的SQL
select * from TEST_ORDER WHERE limit 10000000,10000010
从第一千万条开始,查10条数据,结果是执行时间12秒。
more >>需要引入的头文件
#include "cocos2d.h"
#include "Box2D\Box2D.h"
#include <string>
创建物理世界
world = new b2World(b2Vec2(0,-10));
- bird = Sprite::create("bird0_0.png");
- bird->setName("bird");
- Size size = bird->getContentSize();
- b2BodyDef def;
- def.type = b2_dynamicBody;
- def.position = b2Vec2(screenSize.width / 4 / RATIO, screenSize.height / 2 / RATIO + 1);//鸟的位置
- b2PolygonShape shape;
- shape.SetAsBox(size.width/2/RATIO,size.height/2/RATIO); //碰撞体积?
- b2FixtureDef fixtureDef;
- fixtureDef.density = 1;
- fixtureDef.friction = 0.3;
- fixtureDef.shape = &shape;
- b2Body *body = world->CreateBody(&def);
- body->CreateFixture(&fixtureDef);
- addChild(bird);
- bird->setPosition(Point(def.position.x*RATIO, def.position.y*RATIO));//物理物体会自动往下掉 因此绑定物理物体的位置到sprite上 就形成了物理
- body->SetUserData(bird);//与sprite绑定
- this->body = body;
- void HelloWorld::bingSprite(){ //让物理盒子和精灵实时绑定来达到物理效果 物理盒子本身是看不到的
- Sprite *s;
- for (b2Body *b = world->GetBodyList(); b; b = b->GetNext()){
- s = (Sprite*)b->GetUserData();
- if (b->GetUserData() && b->GetType() == b2_dynamicBody||b->GetType()==b2_kinematicBody){
- if (s != NULL){
- s->setPosition(b->GetPosition().x*RATIO, b->GetPosition().y*RATIO);//每次渲染都让sprite与box body保持位置绑定
- }
-
- }
- }
- }
more >>
pagehelper-sprng-boot-starter 和mybatis-plus-spring-boot-starter 同时引入启动时会报错,即使按网上的排出pagehelper-starter的mybatis包依旧报错,具体解决办法如下:
- <dependency>
- <groupId>com.github.pagehelper</groupId>
- <artifactId>pagehelper</artifactId>
- <version>5.1.10</version>
- </dependency>
- <!-- pagehelper 依赖 -->
- <dependency>
- <groupId>com.github.jsqlparser</groupId>
- <artifactId>jsqlparser</artifactId>
- <version>2.1</version>
- </dependency>
-
-
-
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>${mybatis-plus.version}</version>
- </dependency>
不要使用pagehelper-starter
然后手动添加pagehelper mybatis拦截器:
- package com.xh.sdk.springcloud.config;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
- import com.baomidou.mybatisplus.core.MybatisConfiguration;
- import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-
- @Configuration
- public class MyBatisPlusConfig {
-
- /*
- * 分页插件,自动识别数据库类型
- * 多租户,请参考官网【插件扩展】
- */
- @Bean
- public PaginationInterceptor paginationInterceptor() {
- return new PaginationInterceptor();
- }
-
-
- @Bean
- ConfigurationCustomizer mybatisConfigurationCustomizer() {
- return new ConfigurationCustomizer() {
- @Override
- public void customize(MybatisConfiguration configuration) {
- configuration.addInterceptor(new com.github.pagehelper.PageInterceptor());
- }
- };
- }
-
- }
在微服务架构下开发权限控制一般的做法是,独立开发一个专门用于鉴权的服务,其它服务每次请求接口时都调用鉴权服务鉴权,这样做的好处是,代码耦合低,权限控制功能好扩展,其坏处是每次鉴权都要请求鉴权服务,增加服务器资源消耗,因此我弄了一个简单的权限验证,能满足接口级别的验证,不通过专门的鉴权服务,而是每个服务自己去验证权限。
并非每个服务都需要验证权限,因此我们可以定义一个类似@EnableDiscoery 这样的注解开关来控制:
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.TYPE)
- @Documented
- @Import(AuthenticationInterceptor.class)
- public @interface EnableAuthentication {
-
- }
关键代码是@Import,当你在代码中使用了@EnableAuthentication 注解时,spring 会自动扫描并加载Import注解中的AuthenticationInterceptor类
more >>
突然发现自己以前常用的parent_id ,node_id这种简单直观的树形结构设计效率很低,数据量一大,就需要不停迭代寻找节点,于是这几天学习了新的数据结构(modified preorder tree traversal),在此做下笔记。
此数据结构的好处是查询非常快,当网站查询树形数据比修改多时使用此结构会比较好,一般用于电商网站的商品分类,查询仅仅需要判断left> ? right <?这样即可,缺点是修改节点表数据量大时很慢,而且操作复杂一点。
附最新更新: 左右值树形移动节点方法]
左右值数据结构网上教程很多,不再赘述,总结一下就是:要保持父节点右值比所有子节点的右值大,左节点左值比所有子结点左值小 。
直接上代码,上面有注释 ,说明了如何找子节点,如何找父节点、删除节点,同级平移,兄弟节点前插入等(基于postgreSQL数据库)。
- CREATE TABLE "public"."t_test" (
- "id" int4 NOT NULL DEFAULT nextval('"T_TEST_ID_seq"'::regclass),
- "name" varchar(255) COLLATE "pg_catalog"."default",
- "l" int4,
- "r" int4,
- "level" int4,
- "other" varchar(255) COLLATE "pg_catalog"."default",
- "status" int2 DEFAULT 0,
- PRIMARY KEY ("id")
- )
- ;
more >>
之前写过一遍比较粗略的jenkins + docker部署文章,这次有时间,认真的写一遍比较详细完整的jenkins +docker部署文章,由于有时间所以这次就多写一点吧,记录下我自己对docker的看法,以及它的作用,若有不对之处还请指出。
其实一般的小型项目是用不上也没有必要使用docker的,docker的作用是资源隔离以及快速部署,在项目比较小的时间我们完全可以手动上传jar/war 包到服务器上,并输入命令启动即可,但是,想像一下如果你用上了微服务,好几个团队开发,那么这些服务加起来可能有好几十个,这个时候再手动去部署,想想看你要做什么? 1、安装 JDK 2、配置环境变量 3、安装一些必要的软件如TOMCAT之类的 4、等等不止这些,有些服务甚至有可能要修改JDK配置。
每部署一台机器都要做如此多的操作是不是得烦死?如果是这种情况下,那么docker就可以派上用场了,我们可以直接把安装好各种软件以及配置的系统环境打包成一个docker镜像并保存在某个镜像中心,然后其它服务器只需几行命令就可以轻松使用打包好的环境并完成部署了,而且由于各个docker容器之间是隔离了,一台机器可以部署多种镜像也不会有影响。
最近网上看到很多老程序员们在谈论中年危机,仿佛看到了几年后的自己,我自认为自己也不属于那无可替代的1%,而且自己也确实感觉到了行情不好(如工资下降,面试变少等),感觉自己有可能以后会不再干程序员,希望留下来的文章能够帮到其他人吧,好了,下面开始正题。
最好将jenkins和docker安装在同一台服务器上,当然不是同一台服务器也可以,只不过要多一个步骤,docker安装步骤如下,以centOs为例:
卸载旧版本:
- sudo yum remove docker \
- docker-client \
- docker-client-latest \
- docker-common \
- docker-latest \
- docker-latest-logrotate \
- docker-logrotate \
- docker-engine
设置docker存储库:
- sudo yum install -y yum-utils \
- device-mapper-persistent-data \
- lvm2
- sudo yum-config-manager \
- --add-repo \
- https://download.docker.com/linux/centos/docker-ce.repo
安装docker:
sudo yum install docker-ce docker-ce-cli containerd.io
启动docker:
sudo systemctl start docker
测试docker:
sudo docker run hello-world
看到打印hello world! 就表示成功了。
more >>在调用微信支付接口中遇到各种问题,真不知道是哪个人才写的接口文档,几个简单的接口调了好几天。
1、小程序获取code2Session时errcode出错时是会返回错误码,但正常时居然连这个字段都不返回了,说好的正常返回0呢?
2、小程序支付的时间戳参数,在调用小程序支付接口时需要后台生成签名,有个timeStamp参数,文档上写的是当前时间,注意这里有个坑,它要的是到秒级别的,如果用java直接System.currentTimeMillis() 是不行的!会提示签名错误!
正确做法是: System.currentTimeMillis() / 1000
3、小程序支付签名时key是要拼接的,文档上没有写明,示例上是写的了搞得不知道以哪个为准。
4、建议所有签名统一MD5,否则 不知道哪个地方默认了其它签名就会签名通不过
5、小程序支付,也就是交易类型是JSAPI的情况下是要传openId的,另外appId appkey sercrt mechId 等有一个不对应就会报签名失败,这点要注意。
6、微信支付demo里代码的一个大坑,其中有一段:
- public WXPay(){
-
- if(useSandBox){
- signType = MD5;
- }else{
- signType = HMACSHA256
- }
- }
注意这里一定要改下,改成统一的MD5 :
- public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {
- this.config = config;
- this.notifyUrl = notifyUrl;
- this.autoReport = autoReport;
- this.useSandbox = useSandbox;
- if (useSandbox) {
- this.signType = SignType.MD5; // 沙箱环境
- }
- else {
- //TODO 默认用MD5
- this.signType = SignType.MD5;
- }
- this.wxPayRequest = new WXPayRequest(config);
- }
否则你会发现接收支付成功结果通知的时候怎么老是签名不通过,然后再发现换成HMACSHA256就通过了,看文档里明明写的是默认MD5, 问题就出现在这,demo代码 默认却是HMACSHA256 !
7、沙盒模式测试时报金额不正确,这个问题我自己也不记得在哪看到的了,总之微信文档上是没找到,其原因是沙盒模式测试的金额(total_fee)必须是固定的330 !
另外,沙盒模式下的付款码是不能付款的,不能付款也就是说没法测试接收支付结果通知,只能上正式用1分钱测。
最后记一下接收支付结果通知spring mvc 的接收方式代码:
- @RequestMapping(value="receiveResult",consumes = {MediaType.TEXT_XML_VALUE},produces = {MediaType.TEXT_XML_VALUE})
- public String receiveResult(@NotNull @RequestBody String xml){
- //TODO
- ....
-
- }
算是比较偷懒了,不怕麻烦的建议用实体类加注解 接收
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia-plus根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true