高海燕的个人主页 Licoy's Blog关注互联网及软件IT技术的个人博客 Wed, 25 Mar 2020 13:02:55 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.0.8 非大众版WordPress纯代码实现阅读量统计 /3462.html /3462.html#comments Wed, 11 Mar 2020 12:34:51 +0000 /?p=3462 前言

因疫情影响,已经2个多月没有更新博客了,如果现在还不赶快出来冒个泡,怕大家误认为我走丢了(因为从来没有这么长时间断更过)。

目前我使用的Begin知更鸟主题,文章阅读次数统计是依赖于PostViews插件,大家都知道WordPress的诟病就是插件越多越慢(其实在我看来并不是插件越多越慢,而是查询、事件钩子越多就越慢),所以自己就写了一个纯代码版本,实现了阅读统计和部分查询函数。

当然,可能你想说这些早就有人分享过了;是的,在我写之前我肯定也会上网看看已存的,发现有几点不如意,例如添加meta的钩子是放在wp_head的、查询阅读数量必须要传递post_id等。
非大众版WordPress纯代码实现阅读量统计

正文

我直接贴出代码,每个函数的功能均在注释中已经标识出:

/**
 * 判断阅读数量是否需要增加并进行操作
 * 转载请注明来自:/3462.html
 */
function the_views_add($post_ID,$count,$key){
    if (is_single() || is_page()) {
        if ($count == '') {
            add_post_meta($post_ID, $key, '0');
        } else {
            update_post_meta($post_ID, $key, $count + 1);
            $count++;
        }
    }
    return $count;
}
//获取当前的阅读数量与自增
function the_views ($post_id=null,$echo=true) {
    global $post;
    if($post_id==null){
        $post_id = $post->ID;
    }
    $key = 'views';
    $count = get_post_meta($post_id, $key, true);
    if ($count == '') {
        $count = 0;
    }
    $count = the_views_add($post_id, $count, $key);
    $count = number_format_i18n($count);
    if(!$echo){
        return $count;
    }
    echo $count;
}
//设置文章发布的时候进行字段添加
function set_views ($post_ID) {
    $key = 'views';
    $count = get_post_meta($post_ID, $key, true);
    if ($count == '') {
        add_post_meta($post_ID, $key, '0');
    }
}
add_action('publish_post', 'set_views');

这里再分享一个查询函数,因为是自定义的所以就没有插件的附带函数支持,这个函数是查询N天内阅读数量最多的文章:

/**
 * 转载请注明来自:/3462.html
 * 获取查看最多的文章
 * @param $days N天内
 * @param $nums 数量
 * @return array|object|null
 */
function get_views_most_post($days, $nums){
    global $wpdb;
    $sql = "select posts.*, meta.meta_value as views
            from {$wpdb->posts} as posts INNER JOIN (select post_id,(meta_value+0) as meta_value from 
            {$wpdb->postmeta} where meta_key='views' order by (meta_value+0) DESC) as meta
            on meta.post_id = posts.ID
            where posts.post_type = 'post'
            AND posts.post_status = 'publish' AND TO_DAYS(now()) - TO_DAYS(posts.post_date) < {$days}
            ORDER BY meta.meta_value DESC limit 0, {$nums}";
    return $wpdb->get_results($sql);
}

后记

至于我为什么会分享这些代码出来,因为在过年期间博主写了一套WordPress主题,目前整体框架和内容都均已完成,现在处于优化和测试期,后续上线会专门发文告知,有兴趣的小伙伴欢迎多多关注,感谢你的支持! :idea:

]]>
/3462.html/feed/ 5
防止掉进Dubbo与Seata集成坑里的那些事 /3435.html /3435.html#comments Tue, 24 Dec 2019 08:07:01 +0000 /?p=3435

前言

博主最近在搞Dubbo分布式业务,相信来看此篇文章的开发朋友们对分布式这个名词肯定不陌生,在分布式业务中肯定就会牵涉到分布式事务,对于分布式事务博主开始听了这个词就觉得很难,但是其实还好,就是在整合Dubbo与Seata的其中踩了一些坑,并没有如同官方那么一帆风顺,那么本次就将整合步骤以及一些坑给大家爆出来,以防大家重蹈覆辙~

防止掉进Dubbo与Seata集成坑里的那些事

整合步骤

前提说明

我的业务框架是Dubbo+Mybatis-Plus+Zookeeper+Nacos+Seata,至于为什么要同时使用Zookeeper+Nacos呢,因为前期没有整合分布式事务的时候用的zk做的服务注册中心,后面可能进行移除,换为全局Nacos作为注册中心

安装Nacos

关于Zookeeper我就不多于说明了,因为本文主要是讲述DubboSeata的集成方面的业务。

Nacos我是用的Docker安装的,相关命令如下:

#拉取nacos镜像
docker pull nacos/nacos-server
# 启动镜像
docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
# 默认账户密码是:nacos/nacos

启动好Nacos之后直接访问http://{ip}:8848/nacos/index.html即可登录:

下载/配置/启动Seata

进入到https://github.com/seata/seata/releases下载seata的发行版,我这里使用的0.9.0版本。

下载完成之后进行解压,其中bin目录下存放为启动脚本,conf目录下存放为配置文件以及相关SQL和配置注入脚本,lib目录下是seata的相关依赖。

进入到conf目录修改registry.conf
打开文件我们可以看见可以使用file、nacos 、apollo、zk、consul的注册和配置中心,本次主要是搭配nacos进行食用~

registry {
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1" #nacos地址ip
    namespace = "public" #nacos的命名空间,默认为public
    cluster = "default" #集群,由于没有所以填写default
  }
  file {
    name = "file.conf"
  }
}

config {
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1" #nacos地址ip
    cluster = "default" #集群,由于没有所以填写default
  }

  file {
    name = "file.conf"
  }
}

注意:在registry中config没有namespace属性,否则会出现服务启动失败或no available!

接着我们修改file.conf,其配置主要为:

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-prefix = "NettyServerBizHandler"
    share-boss-worker = false
    client-selector-thread-prefix = "NettyClientSelector"
    client-selector-thread-size = 1
    client-worker-thread-prefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}


service {
  #transaction service group mapping
  vgroup_mapping.service-user-provider-group = "default"
  vgroup_mapping.service-order-provider-group = "default"
  vgroup_mapping.service-storage-provider-group = "default"
  #这里是你的事务分组配置,格式为vgroup_mapping.${YOUR_SERVICE_NAME}-group,当然<code>${YOUR_SERVICE_NAME}-group</code>部分你可以自定
  #下面是你的seata的服务列表
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
  disableGlobalTransaction = false
}

client {
  async.commit.buffer.limit = 10000
  lock {
    retry.internal = 10
    retry.times = 30
  }
  report.retry.count = 5
  tm.commit.retry.count = 1
  tm.rollback.retry.count = 1
}

## transaction log store, only used in seata-server
store {
  ## store mode: file、db
  mode = "db"

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    ## 此处为你的数据库配置
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "root"
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}


support {
  ## spring
  spring {
    # auto proxy the DataSource bean
    datasource.autoproxy = false
  }
}

配置好上述配置文件之后,我们将conf目录下的db_store.sql文件导入到我们的数据库,我这里的数据库名为seata(上述配置文件可以看出)

接着我们再修改目录下的nacos-config.txt,这个文件其实就是将file.conf翻译成properties格式的,这里我就不做过多的说明了,写好之后我们将配置写入到nacos中:

# 在conf目录下执行
sh nacos-config.sh {Nacos-Server-IP} #将{Nacos-Server-IP}换成你的IP

写入成功之后,你会看到这样一行小绿字:
init nacos config finished, please start seata-server.

启动seata-server

# 在bin目录下执行
sh seata-server.sh
# or
sh seata-server.sh -h 127.0.0.1 -p 8091 -m db
# 下面的是带参启动可以覆盖配置文件里面的数据

启动成功之后,你会看到Nacos的「控制台」-「服务列表」中会新增一项服务名为serverAddr的服务,如图:

业务整合

业务架构分为

service-order-provider # 订单服务
service-storage-provider # 库存服务
service-user-provider # 用户服务
service-user-consumer # 用户业务调用

导入日志数据表

将seata的conf目录下的db_undo_log.sql到你的业务数据库

业务配置

我们要在三个provider服务中写入如下配置:

/resources/file.conf

file.conf与seata的conf目录下一致

/resources/registry.conf

registry.conf与seata的conf目录下一致

pom.xml

引入需要的依赖包

<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>1.1.4</version>
</dependency>

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>0.9.0</version>
</dependency>

SeataAutoConfig.java

进行Seata的配置,包括数据库资源/数据库代理设置/SqlSessionFactory等

/**
 * @author Licoy.cn
 * @version 2019/12/23
 */
@Configuration
public class SeataAutoConfig {

    @Value("${spring.application.name}")
    private String appName;

    @Autowired
    private DataSourceProperties dataSourceProperties;

    /**
     * init durid datasource
     *
     * @Return: druidDataSource  datasource instance
     */
    @Bean
    @Primary
    public DruidDataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(dataSourceProperties.getUrl());
        druidDataSource.setUsername(dataSourceProperties.getUsername());
        druidDataSource.setPassword(dataSourceProperties.getPassword());
        druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
        druidDataSource.setInitialSize(0);
        druidDataSource.setMaxActive(180);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setMinIdle(0);
        druidDataSource.setValidationQuery("Select 1 from DUAL");
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(25200000);
        druidDataSource.setRemoveAbandoned(true);
        druidDataSource.setRemoveAbandonedTimeout(1800);
        druidDataSource.setLogAbandoned(true);
        try {
            Driver driver = new Driver();
            druidDataSource.setDriver(driver);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }



    @Bean
    public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }

    // 因为我使用的是MybatisPlus,所以需要注入此部分
    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(DataSourceProxy proxy) throws IOException {
        MybatisSqlSessionFactoryBean mybatisPlus = new MybatisSqlSessionFactoryBean();
        mybatisPlus.setDataSource(proxy);
        mybatisPlus.setVfs(SpringBootVFS.class);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        mybatisPlus.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        GlobalConfig globalConfig = new GlobalConfig();
        GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
        //使用ID_WORKER_STR,因为前后端分离使用整形,前端JS会有精度丢失
        dbConfig.setIdType(IdType.ID_WORKER_STR);
        globalConfig.setDbConfig(dbConfig);
        mybatisPlus.setGlobalConfig(globalConfig);
        MybatisConfiguration mc = new MybatisConfiguration();
        // 对于完全自定义的mapper需要加此项配置,才能实现下划线转驼峰
        mc.setMapUnderscoreToCamelCase(true);
        mc.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        mybatisPlus.setConfiguration(mc);
        return mybatisPlus;
    }



    @Bean
    public GlobalTransactionScanner globalTransactionScanner(){
        return new GlobalTransactionScanner(this.appName, String.format("%s-group", this.appName));
    }

}

业务接口

order服务下有创建订单的接口

/**
 * 创建订单
 * @param order 订单
 */
ClientOrder create(ClientOrder order);

storage服务下有减少库存的接口

/**
 * 扣除库存
 * @param productId 产品ID
 * @param total 扣除数量
 */
void decrease(String productId, Integer total);

user服务下有减少账户余额以及购买的接口

/**
 * 扣除账户余额
 * @param userId 用户ID
 * @param money 扣除金额
 */
void decreaseMoney(String userId, BigDecimal money);

/**
 * 购买产品
 * @param productId 产品ID
 * @param uid 用户ID
 * @param totalCount 购买数量
 */
void buy(String productId, String uid, Integer totalCount);

创建订单/扣除库存/扣除账户余额这三个接口我就不在此展示了,因为都是基本的CURD+业务判断,主要展示一下购买产品的业务接口实现,因为我们需要对此业务的过程中处理分布式事务:

@Override
@GlobalTransactional(name = "service-user-provider")
public void buy(String productId, String uid, Integer totalCount) {
    log.info("开始全局事务"+ RootContext.getXID());
    ClientOrder order = new ClientOrder();
    BigDecimal money = new BigDecimal(200);
    order.setMoney(money);
    order.setPid(productId);
    order.setUid(uid);
    order.setTotal(totalCount);
    log.info("====创建订单====");
    ClientOrder order1 = this.orderService.create(order);
    log.info("====创建订单完成====");
    log.info("====扣除库存====");
    this.storageService.decrease(productId, totalCount);
    log.info("====库存扣除完成====");
    log.info("====扣除账户余额====");
    this.decreaseMoney(uid, money);
    log.info("====账户余额扣除完成====");
    log.info("====购买成功====");
}

由上述代码可以看出,我们只需要添加一个@GlobalTransactional注解就可以进行分布式事务控制,其中name为该项目spring.application.name的值。

对于事务回滚,我们只需要将用户的余额设置为0,这个时候扣除余额就会失败,那么业务失败,就会进行事务回滚,当操作完成之后我们看到数据库的订单和库存并没有创建和减少,就代表我们的分布式事务Seata配置完成并可以成功使用。

后记

在配置Seata的时候确实踩了不少坑,现在回头过来有些都已经忘却(当时只顾得解决BUG,没有记录下来),所以此篇文章关于坑的展示并没有自己想的那么多,如果大家遇到了这方面的问题,可以在文章下方评论,博主将会尽可能的帮助你解决你的燃眉之急!

]]>
/3435.html/feed/ 4
好物安利之提升开发效率的APP吐血推荐 /3421.html /3421.html#comments Thu, 12 Dec 2019 07:15:20 +0000 /?p=3421

前言

俗话说的甚是好:“工欲善其事必先利其器”,在我们日常的工作中,一款好的软件应用肯定会让我们的工作效率达到事半功倍的效果,所以今天就来给大家安利一下开发中好用的软件吧~

正文

Intellij IDEA

作为Java开发的小伙伴一定对此软件玩弄于手掌之中,所以就不用过多介绍,jetbrains公司的IDE称之为全宇宙第二,就没有人敢称之为第二。

Visual Studio Code

Visual Studio Code简称VsCode,是微软出品的一款编辑器,其实质上可以通过众多的插件来将它变成一款IDE,支持Windows、Linux、MacOS,博主开发前端工程就是用它了!

Navicat Premium

Navicat Premium可以称之为数据库可视化的王者软件了,至少在我目前所见的客户端软件中它是最好用的也是功能最强大的,没有之一,不过用这款软件的小伙伴手最好还是不要颤抖,万一一抖删库了,那就只有跑路~~

Studio 3T

Studio 3T是适用于Windows,Mac和Linux的MongoDB的专业GUI,IDE和客户端。当然在上方推荐的Navicat Premium也含有MongoDB的管理工具,对于谁好用,还是看客官你的操作啦~~

iTerm2

一款非常优秀的终端软件,主要是还是免费的,你说气不气人,众多的皮肤以及可以让你自定义终端显示配置,简直是此类软件的高富帅~

PicGo

聚合图床工具,支持5种复制的链接格式以及众多图床源的支持,包括但不限于七牛云、腾讯云、又拍云、Github、SMMS、阿里云等,我现在就是用这款软件来辅助写这篇文章的(因为我需要将软件配图上传到图床中)。

ENFI

一款通用型高速下载工具
使用P2P下载技术,支持HTTP,BT,磁力链等各种协议,高速下载让你摆脱限速的困扰,从此让你看片告别低速~


Adobe PhotoShop CC

拍照一分钟,修图两小时,就靠Adobe PhotoShop CC了,自动学会了PS,找我P图的妹子都多了~

Xmind ZEN

思维导图制作软件,功能齐全的瑞士军刀,助您一臂之力,铅笔和纸的现代替代品。

GitKraken

免费的Git可视化客户端,高颜值高体验,对于刚入门使用Git的小伙伴很友好。

后记

一款好的工具可以让我在开发中大大的提升效率,当然如果你还有一些好玩的软件可以在下方评论告诉Licoy哟,让我们一起欢乐玩耍!

]]>
/3421.html/feed/ 4
Redis发布与订阅模式在SpringBoot下的使用与应用场景 /3406.html /3406.html#comments Sat, 07 Dec 2019 07:14:39 +0000 /?p=3406 前言

Redis相信对于各位开发者的朋友来说都不会陌生,特别是后端的朋友会经常性的用到Redis来进行数据缓存等操作,今日我们就来聊聊Redis的发布(Pub)与订阅(Sub)模式的在SpringBoot下如何使用,并谈谈相关的应用场景。
Redis发布与订阅模式在SpringBoot下的使用与应用场景

使用方法

首先我们需要配置redis的相关依赖包:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后我们需要配置Redis消息的监听容器:

@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                        MessageListenerAdapter listenerAdapter) {
    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.addMessageListener(listenerAdapter, new PatternTopic("topicName")); //配置名称
    return container;
}

接着我们新建一个消息实体,用于发送数据:

@Data
@AllArgsConstructor
public class Notice implements Serializable {

    private String name;

    private String val;

}

现在基本配置和消息数据体我们都定义好了,接着我们需要配置一个订阅端,用于监听订阅的消息:

@Component
@Slf4j
public class LicoyWorkMessageListener extends MessageListenerAdapter {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void onMessage(Message message, byte[] pattern) {
        byte[] body = message.getBody();
        byte[] channel = message.getChannel();
        String topic = (String) redisTemplate.getStringSerializer().deserialize(channel);
        if(!topic.equals("topicName")){
            return;
        }
        Object res = redisTemplate.getValueSerializer().deserialize(body);
        if(res instanceof Notice){ //如果反序列化得到的是我们定义的消息数据体类型
            Notice notice = (Notice)res;
            System.out.println(notice);
        }else{
            //其他处理
        }
    }
}

:smile: 到这一步,万事俱备只欠东风了,现在我们只需要在需要用到的地方发布消息即可,如(作为演示,我直接在部分逻辑写在controller层,实际业务不建议这么做):

@GetMapping("/notice/{name}/{val}")
public ResponseResult<String> notice(@PathVariable String name,@PathVariable String val){
    redisTemplate.convertAndSend("topicName", new Notice(name,val));
    return ResponseResult.ok();
}

使用场景

对于使用场景,就谈谈博主在开发中所用到的地方之一,一个平台,其分别有用户端/商家端,包含一个简单的Socket连接,用于商家及用户工单会话的消息通知,但是这两个是单独的Application,所以各自的Socket-Session分别保存在对应的内存栈中,因为不想让此复杂所以就没有采用其他框架就默认使用Springboot内置的WebSocket,但是WebSocketSession这个对象不支持序列化,所以就无法缓存到Redis中,那么只有(方法不一)两个端同时订阅一个频道,然后有新消息的时候通知两个端分别进行处理来发送消息给用户还是商家。

尾记

在实际开发的过程中,我们所遇到的问题会远比自己所设想的多,但是这并不是100%的,只要思想不滑坡,办法总比困难多,加油!

另外双十二即将来临,你准备再一波剁手了么 :grin:

]]>
/3406.html/feed/ 4
Swagger扩展用于动态显示Enum的属性说明 /3397.html /3397.html#comments Fri, 22 Nov 2019 08:08:34 +0000 /?p=3397

前言

恍恍惚惚已然有两月之久没写博文了,现在是打开电脑放佛就像是肚子里面一点儿墨水都没有,不知思绪。

就不发表那么多的感言了,进入本文的正题:对于Swagger想必大家应该都比较熟悉,在线API文档生成的佼佼者(如果不知道,请点此进行了解),但是Swagger对于Enum的属性支持不太好,不能够在文档的api参数列表中展示参数值以及参数说明,这样就会导致前后端开发人员增加沟通成本,所以我们需要进行扩展。
Swagger扩展用于动态显示Enum的属性说明

正文

基础配置

博主是参考的掘金上一位作者发表的《swagger 动态显示枚举内容 + 数值类型空指针异常统一控制》进行基础的配置,大家首先可以先参考这篇文章,再做好文章内的配置后再进行以下操作。

增加展示枚举属性

我们需要在api文档上显示这个枚举的标题,所以我们需要扩展一下@SwaggerDisplayEnum注解,新增value属性:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SwaggerDisplayEnum {

    String value();
    String valueName() default "value";
    String descName() default "desc";

}

这样我们在使用@SwaggerDisplayEnum注解的时候需要配置当前这个枚举的名称,另外对于原作者给的方式获取的name值,而我用的Mybatis-Plus枚举映射要传递枚举的名称,所以要获取枚举的名称,所以大家将其中的:

value = valueField.get(item).toString();
//以及
joinText = mField.get(context.getBuilder()) + joinText;

改成:

value = item.toString();
//以及
joinText = swaggerDisplayEnum.value() + joinText;

不过要值得注意的是,对于目标解析枚举要重写toString(),其返回的内容为this.name()

到这步就可以实现我们需要的效果了,如下:
Swagger扩展用于动态显示Enum的属性说明

]]>
/3397.html/feed/ 2
关于在travis-ci以及appveyor条件构建遇到的坑 /3385.html /3385.html#comments Sat, 14 Sep 2019 03:16:34 +0000 /?p=3385 前言

在上篇《基于Electron-Vue开发了一款美图搜罗器》文章中有提到过关于在自动化构建的方面花费了很长的时间,实际上这是一个相对比较头痛的问题,之前每次commit到github之后,travis-ci以及appveyor都会进行build,不过有时候我们就是修改了与业务无关的东西,比如readme之类的,不需要重新build,这个时候我们就需要使用条件构建,这里最好的办法就是通过推送tag来进行触发构建。
关于在travis-ci以及appveyor条件构建遇到的坑

travis-ci

关于在travis-ci中,我在官方的文档中并没有找到关于通过tag来进行触发构建的说明,可以或许会有遗漏,后面在官方github仓库的issue中发现了有人曾经提出来过,具体可以参考:https://github.com/travis-ci/travis-ci/issues/6893,于是参考着改了之后我的.travis.yml就是如下所示:

osx_image: xcode8.3
sudo: required
dist: trusty
language: c
matrix:
  include:
  - os: osx
if: tag IS present # 这里是添加的之后的部分
cache:
  directories:
  - node_modules
  - "$HOME/.electron"
  - "$HOME/.cache"
addons:
  apt:
    packages:
    - libgnome-keyring-dev
    - icnsutils
    #- xvfb
before_install:
- mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([
  "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz
  | tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi
install:
#- export DISPLAY=':99.0'
#- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- nvm install 10
- curl -o- -L https://yarnpkg.com/install.sh | bash
- source ~/.bashrc
- npm install -g xvfb-maybe
- yarn
script:
#- xvfb-maybe node_modules/.bin/karma start test/unit/karma.conf.js
#- yarn run pack && xvfb-maybe node_modules/.bin/mocha test/e2e
- npm run release
branches:
  only:
  - master

appveyor

appveyor的可以参考官方的https://www.appveyor.com/docs/appveyor-yml/中可以看出,在appveyor.yml中添加skip_non_tags: true即可使用tag来触发构建,于是改了之后我的appveyor.yml为:

# Commented sections below can be used to run tests on the CI server
# https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing
version: 0.1.{build}

branches:
  only:
    - master

skip_non_tags: true

image: Visual Studio 2017
platform:
  - x64

cache:
  - node_modules
  - '%APPDATA%\npm-cache'
  - '%USERPROFILE%\.electron'
  - '%USERPROFILE%\AppData\Local\Yarn\cache'

init:
  - git config --global core.autocrlf input

install:
  - ps: Install-Product node 8 x64
  - git reset --hard HEAD
  - npm install
  - node --version

build_script:
  - npm run release

test: off

当上面的配置好了之后,我以为到此我就可以愉快的使用git push --tags来触发构建了,但是实际情况并不是那么如意,当我试过多次之后并没有触发构建,而是像一只死鱼一般寂静 :sad:
后来终于看到一篇文章《更简单地用Travis自动发布GitHub Releases》中提到:

要注意,如果此前设置过CI的分支限制,tags: true不会生效。 因为,对Travis来说,Tag也算是一种branch。

branches:
  only:
    - master

去掉以上代码块,否则自动发布将不会执行。

于是乎,我将travis-ci以及appveyor配置文件中的相关配置移除,再执行了一次git push --tags,果不其然,成功了!
关于在travis-ci以及appveyor条件构建遇到的坑

后记

关于持续构建是对于现在的软件编译发布必要的东西,它可以减少大量的重复性的工作而减少我们的工作量,所以未来我会将线上可以进行自动化构建服务全部都完成此操作,加油! :smile:

]]>
/3385.html/feed/ 11
Docker开启RabbitMQ延时消息队列 /3361.html /3361.html#comments Wed, 07 Aug 2019 06:48:54 +0000 /?p=3361

前言

经常在开发中会遇到一些不需要同步执行的业务,那我们就需要用到消息队列来进行异步执行,但是对于某些业务就还需要用到延时的功能,比如订单支付超时关闭,那么这个时候我们就需要开启消息队列的延时功能,当然也有朋友说有其他的解决办法,例如:数据库轮训以及线程休眠,但是这些相对于延时消息队列来说,都显得比较逊色。
Docker开启RabbitMQ延时消息队列

正文

安装Docker

docker的安装就不用多说了,在Centos下就一行命令搞定(其他的系统版本请自行查阅):

yum update -y && yum install -y docker && service docker start

拉取RabbitMQ镜像并启动

docker pull rabbitmq:management

docker run -d --hostname my-rabbit --name rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:management

上述命令中的RABBITMQ_DEFAULT_USER为默认用户,RABBITMQ_DEFAULT_PASS为默认密码,请自行修改即可

安装延时插件

首先先到rabbitmq官网下载自己rabbitmq对应版本的延时插件rabbitmq_delayed_message_exchange到服务端,我的是3.7.x,所以执行:

wget https://dl.bintray.com/rabbitmq/community-plugins/3.7.x/rabbitmq_delayed_message_exchange/rabbitmq_delayed_message_exchange-20171201-3.7.x.zip

下载完成之后我们将zip文件进行解压,然后我们执行docker ps查看自己的rabbitmq的容器ID:

[root@121 download]# docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                                                                                                                                         NAMES
c5e3d04e3141        rabbitmq:management   "docker-entrypoint..."   7 days ago          Up 7 days           4369/tcp, 0.0.0.0:1883->1883/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 0.0.0.0:15672->15672/tcp, 0.0.0.0:25672->25672/tcp, 0.0.0.0:61613->61613/tcp, 15671/tcp   rabbit

接着我们将插件拷贝到容器的插件目录下:

docker cp rabbitmq_delayed_message_exchange-20171201-3.7.x.ez c5e3d04e3141:/plugins
# c5e3d04e3141是自己的容器ID

然后我们进入到容器的bash中:

sudo docker exec -it c5e3d04e3141 /bin/bash

进入到plugins目录查看是否有rabbitmq_delayed_message_exchange-20171201-3.7.x.ez文件,有的话就说明成功拷贝到rabbitmq的插件目录了,接着我们就执行最后一步,开启插件:

root@my-rabbit:/plugins# rabbitmq-plugins enable rabbitmq_delayed_message_exchange
Enabling plugins on node rabbit@my-rabbit:
rabbitmq_delayed_message_exchange
The following plugins have been configured:
  rabbitmq_delayed_message_exchange
  rabbitmq_management
  rabbitmq_management_agent
  rabbitmq_web_dispatch
Applying plugin configuration to rabbit@my-rabbit...
The following plugins have been enabled:
  rabbitmq_delayed_message_exchange

started 1 plugins.

执行rabbitmq-plugins enable rabbitmq_delayed_message_exchange在log最后出现started 1 plugins.,就说明开启成功,退出rabbitmq的bash之后执行docker restart rabbit重启rabbitmq就可以使用延时消息队列来处理业务了。

后记

在以前的业务中我都是用的文章开头说的稍显逊色的做法来处理这种业务,但是这种方法显然是不可靠的,当然以前我不用消息队列的原因就是听着这个名字就觉得很难,后来真正用上了之后发现很好上手的,所以不能再事情未开始之前就给自己下了死刑,加油! :smile:

]]>
/3361.html/feed/ 12
高海燕的个人主页联合华为云新手专享3500元福利红包发放 /3340.html /3340.html#comments Sat, 27 Jul 2019 03:28:38 +0000 /?p=3340

前言

在5G时代已经到来的今天,所有的服务都是基于云端控制,对于站长们而言更希望能够拥有性价比高的服务器,对于国内几大云服务器厂商之一华为云与高海燕的个人主页联合推出新手专享3500元的福利红包,可以全场产品通用,速速看过来吧~
高海燕的个人主页联合华为云新手专享3500元福利红包发放

详情

最新优惠

学生云服务器1h2G一年只需要99元,24岁以下还免认证,点我进入查看活动详情及购买

领取方式

点击「华为云新手专享红包」即可进入到活动详情页,注册登录账号即可领取,然后就可以开开心心的去够买自己心仪的云服务~

使用方式

1.去官网首页或活动导航栏选择需求商品进行选购
高海燕的个人主页联合华为云新手专享3500元福利红包发放
2.在结算界面点击使用代金券,即可享受满减优惠,完成购买
高海燕的个人主页联合华为云新手专享3500元福利红包发放

高海燕的个人主页联合华为云新手专享3500元福利红包发放

产品评测

it之家:https://www.ithome.com/0/431/894.htm

中国日报网:https://baijiahao.baidu.com/s?id=1638481243441507914&wfr=spider&for=pc

产品帮助

华为云产品使用帮助:点我进入

]]>
/3340.html/feed/ 14
基于Vue+iView设计开发自适应管理后台UI /3316.html /3316.html#comments Mon, 15 Jul 2019 06:09:33 +0000 /?p=3316

前言

这段时日在项目中有个需求,后台管理站点是需要PC端与移动端自适应,对于以往的惯例是直接在素材网找Bootstrap的后台管理模板,然后再进行嵌套开发,但是由于Bootstrap的后台管理模板一般都是基于jQuery的,需要异步加载数据这就要直接做大量的DOM操作,这一点对于我现在的开发模式是比较排斥的,由于我现在的管理后台全部都是Vue+iView的,所有就去看了看iView可能支持自适应不,果不其然,官方是给出了自适应栅格布局的方案,这让我内心一阵窃喜 :grin: (以前没太注意看这个布局底部还有这个东西~)

正文

首先我们看到在iView的栅格 Grid中预设六个响应尺寸,分别是:xssmmdlgxlxxl,由于我设计的后台管理的菜单在992px下菜单就展示不太友好,需要变换方式,所以一般只设置到lg这一层尺寸就可以了,然后在其主内容布局中也要用栅格自适应来进行开发,这样才能够保证移动端和PC端的样式兼容,不然容易产生页面错位。

特别需要值得注意的一点是,引入了iView之后,body的style样式会莫名其妙的出现一个overflow:hidden,这样会导致我们移动端无法进行滑动,所以我们只需要在样式表中添加如下样式即可:

body{
    overflow: auto !important;
}

大致的设计开发就是这样的,其实官方也是参考Bootstrap的,只要有一些自适应开发基础的小伙伴就可以完全快速上手,以下是我自己设计的一套后台管理模板,欢迎大家给我提供更多的建议!

PC端

基于Vue+iView设计开发自适应管理后台UI

移动端

基于Vue+iView设计开发自适应管理后台UI

项目地址

Github:https://github.com/Licoy/visamt

后记

非专业前端,还请大佬多指教指教,谢谢! :mrgreen:

]]>
/3316.html/feed/ 2
首款宝塔插件「域名解析助手」已发布 /3308.html /3308.html#comments Mon, 29 Apr 2019 12:00:51 +0000 /?p=3308

前言

前段时间在使用宝塔的时候,将版本更新至最新版之后原本的「软件管理」变成了「软件商店」,于是乎带着好奇心点进去发现多出了一个「第三方应用」,才知道原来宝塔推出了开发者平台,官方还有激励机制,于是乎就着手开始写了第一款插件,也就是今天的主角「域名解析助手」。
首款宝塔插件「域名解析助手」已发布

介绍

「域名解析助手」是一个什么东西呢?顾名思义肯定是与域名解析相关的,其实「域名解析助手」是一个超融合的域名解析集合,目前支持Aliyun/DnsPod/CloudFlare的域名解析,可以直接在宝塔后台配置好相关DNS商的API密钥参数,直接在宝塔进行域名解析的增删改查,从此再也不用登录多家管理平台去一一管理了~ :smile:

安装方法

登入最新版宝塔,打开「软件商店」-「第三方应用」选择「域名解析助手」购买即可,月付仅需3.99元,是不是便宜到家了 :grin:

API密钥获取

阿里云

https://ak-console.aliyun.com/index#/accesskey

DnsPod

https://www.dnspod.cn/User/Security

CloudFlare

登录CloudFlare之后点击头像进入「My Profile」,下滑到最底端「API Keys」中的「Global API Key」就是密钥参数

售后支持

在购买插件之后您可以选择加入售后QQ群:515497983,第一时间获得最方便快捷的售后服务支持!

]]>
/3308.html/feed/ 14