技术文章

  • 使用 Docker 基于 Debian 安装 Java 环境失败的解决方法

    2019-11-15 17:09:34 279 0 技术文章
    # 安装 default-jre 需要手动创建 /usr/share/man/man1 目录
    RUN mkdir -p /usr/share/man/man1 \
        && apt-get update \
        && apt-get install -y \
        default-jre \
    

    参考文章:https://stackoverflow.com/questions/55795154/docker-how-to-install-openjdk-jre-12-on-top-of-debian-jessie-slim

    • 升级 Catalina 后出现 Read-only file system 问题解决方案

      2019-10-12 18:03:36 684 0 技术文章

      由于项目的根目录在 /data1 目录,需要在根目录创建 data1 目录,但是提示:

      mkdir: data1: Read-only file system
      

      先关闭 sip,终端输入 sudo mount -uw /

      然后再创建目录或者创建软链接,即可成功!

      • Yii China 是官方唯一认可的中文社区

        2019-01-30 11:48:58 5977 1 技术文章

        今天是 Yii Framework 2.0.16 版本发布 的日子,经过我们坚持不懈的进行国际化翻译,以及在中国进行大量的宣传和推广,Yii China 已经成为全球最大的 Yii 中文社区。

        希望更多的 Yiiers 加入我们社区! https://www.yiichina.com

        官方提供的社区推荐地址: https://github.com/yiisoft/yii2/wiki/communities#chinese

      • GitLab 实现仓库完全迁移,包括所有提交记录、分支、标签

        2018-12-28 18:20:29 1567 0 技术文章

        具体命令如下:

        cd <项目目录>
        git fetch --all
        git fetch --tags
        git remote set-url origin <项目的新仓库地址>
        git push origin --all 
        git push --tags 
        

        参考文章:

        https://developer.atlassian.com/blog/2016/01/totw-copying-a-full-git-repo/

      • Mac OSX 目录操作遇到 Operation not permitted 问题

        2018-12-12 11:41:28 2591 0 技术文章

        今天在安装 PHP 扩展的时候发现使用 sudo 还依然提示 "Operation not permitted"。

        这是由于 10.13 版本加强了权限的限制,即 rootless 机制,可以进入恢复模式关闭 rootless 机制。

        官方说明:https://developer.apple.com/videos/play/wwdc2015/706/

        解决方案

        1. 重启 Mac,按 Command + R(Win 键盘:win + R)进入恢复模式

        2. 打开终端,输入命令:

          csrutil disable
          
        3. 重启后让机器正常启动,可以在终端查看 rootless 状态:

          csrutil status
          

          显示

          System Integrity Protection status: disabled.
          

          正常情况下 rootless 已经关闭。

        4. 要想重新开启 rootless 机制,参考步骤 1,输入命令:

          csrutil enable
          
      • 使用 pdflatex 生成 Yii 2 中文权威指南 PDF

        2018-12-02 16:46:45 1379 0 技术文章

        问题来源

        https://github.com/yiisoft-contrib/yiiframework.com/issues/142 https://en.wikibooks.org/wiki/LaTeX/Internationalization#Chinese

        解决方案

        https://github.com/yiisoft-contrib/yiiframework.com/blob/master/commands/GuideController.php#L85

        修改为:

        // https://en.wikibooks.org/wiki/LaTeX/Internationalization#Chinese
        // TODO this does not work yet. See https://github.com/yiisoft-contrib/yiiframework.com/issues/142
        file_put_contents("$pdfTarget/main.tex", str_replace(['\usepackage[british]{babel}', '\begin{document}', '\end{document}'], ['\usepackage{CJKutf8}', '\begin{document}' . PHP_EOL . '\begin{CJK}{UTF8}{gbsn}', '\end{CJK}' . PHP_EOL . '\end{document}'], file_get_contents("$pdfTarget/main.tex")));
        

        {gbsn} 是“宋体”,所以前提是服务器已经安装中文的“宋体”字体。

      • Yii 2 将 Gravatar 头像图片做本地化缓存

        2018-10-15 18:11:52 1328 0 技术文章

        Gravatar 是全球公认头像,但头像图片有时候访问奇慢无比,将整个页面的加载速度降了下来,如果能将头像图片缓存到本地,并设置过期时间,那性能会飞速提高,以下代码是 Yii2 的自定义 Helper 中的代码片断,用于实现 Gravatar 本地化访问。

        public function gravatar($email, $s = 80, $atts = [], $d = 'mp', $r = 'g')
        {
            $key = md5(strtolower(trim($email)));
            $img_file = Yii::getAlias("@webroot/uploads/avatar/$key.jpg");
            $img_url = Yii::getAlias("@web/uploads/avatar/$key.jpg");
            $noavatar_file = Yii::getAlias('@webroot/images/noavatar.jpg');
            $noavatar_url = Yii::getAlias('@web/images/noavatar.jpg');
        
            // 缓存时间 30 天,超过 30 天会重新到 gravatar.com 去取
            if (!file_exists($img_file) || filemtime($img_file) < time() - 3600 * 24 * 30) {
                file_put_contents($img_file, file_get_contents("https://www.gravatar.com/avatar/$key?s=$s&d=$d&r=$r"));
            }
        
            // 没有设置过头像的用户,显示自定义头像
            if (md5_file($img_file) == md5_file($noavatar_file)) {
                $img_url = $noavatar_url;
            }
        
            return Html::img($img_url, $atts);
        }
        
        • 使用 YUI Compressor 压缩 CSS 导致 image/svg+xml 无法显示的问题

          2018-08-06 22:04:20 1462 0 技术文章

          bootstrap 升级到 4.3 以后,.navbar-toggler-icon 的背景是一个 svg 图像,但被压缩后,url 中的空格全部消失了,所以无法显示这个图标。

          .navbar-light .navbar-toggler-icon { background-image: url(data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://ww…p='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E); }
          

          于是想到修改 java 代码,重新编译。

          https://github.com/yui/yuicompressor/blob/master/src/com/yahoo/platform/yui/compressor/CssCompressor.java
          

          修改源码

          找到 CssCompressor.java,修改第 141 行,

          css = this.preserveToken(css, "url", "(?i)url\\(\\s*([\"']?)data\\:", true, preservedTokens);
          

          改为

          css = this.preserveToken(css, "url", "(?i)url\\(\\s*([\"']?)data\\:", false, preservedTokens);
          

          重新编译

          安装 ant

          # yum -y install ant
          # ant // 编译为 jar 文件
          

          生成 .jar 文件位于 build 目录。

          THE END

        • Tengine 2.2.2 配置 http2 协议出现的坑

          2018-08-01 12:46:11 2116 1 技术文章

          昨天本站将 nginx 配置改为支持 http2 协议,发帖,浏览帖子都很正常,但上传图片出现 504,改回 http 1.1 恢复正常,于是确定是配置 http2 造成的恶果,于是 google 搜索 "tengine http2 504" 等关键字,最终发现了阿里官方 issue:

          https://github.com/alibaba/tengine/issues/1003

          此 issue 作者遇到同样的情况:

          从 nginx 1.10.1 升级为 tengin 2.1.2 后, 用户通过 multipart/form-data 上传文件时 如果文件大于 1M 就会上传失败 抓包分析后,发现在用户在上传大文件时,http body 内容不完整 导致 java MultipartHttpServletRequest request 拿到的 request.getFileNames() size 为 0

          抓取了 tengin 与 tomcat 之间的报文,异常报文中 http body 内容异常

          看这个 issue,确定是 2.2.2 的一个 BUG,接着回退到 2.2.1,问题依旧,回退到 2.2.0,问题得到解决。

          在此提醒大家,如果使用 Tengine 需要配置 http2,建议不要使用 2.2.1 和 2.2.2 版本。

        • Golang 中 Goroutine 的调度器模型

          2018-07-24 18:35:36 1164 0 技术文章

          Goroutine 可以说是 Golang 最大的特色

        • Go 语言的 Goroutine 和 channel

          2018-07-13 17:50:27 1322 0 技术文章

          进程,线程的概念在操作系统的书上已经有详细的介绍。进程是内存资源管理和cpu调度的执行单元。为了有效利用多核处理器的优势,将进程进一步细分,允许一个进程里存在多个线程,这多个线程还是共享同一片内存空间,但cpu调度的最小单元变成了线程。

          那协程又是什么东西,以及与线程的差异性??

          协程,可以看作是轻量级的线程。但与线程不同的是,线程的切换是由操作系统控制的,而协程的切换则是由用户控制的。

        • Go 语言中 json 的操作以及常见问题

          2018-06-16 17:04:16 1432 1 技术文章

          常见问题

          结构体里的字段首字母必须大写

          type Person struct{
              Name string
              Age int
          }
          
          func main(){
            person := Person{"小明",18}
            if result, err := json.Marshal(&person);err == nil {
              fmt.Println(string(result))
            }
          }
          

          控制台输出:{"Name":"小明","Age":18}

          如果字段首字母为小写的话,解析会有问题,得到的值为空。

          可以通过字段的 tag 指定 struct 转 json 后的首字母小写

          type Person struct {
              Name string `json:"name"`    
              Age int `json:"age"`
              Time int64 `json:"-"` // 忽略字段
          }
          
          func main(){
            person:=Person{"小明",18, time.Now().Unix()}
            if result,err:=json.Marshal(&person);err==nil{
               fmt.Println(string(result))
            }
          }
          

          控制台输出:{"name":"小明","age":18}

        • Go 语言的面向对象使用场景

          2018-06-13 18:42:25 1335 0 技术文章

          目前大部分高级语言都支持面向对象,比如 C++, JAVA, PHP 等,那么 Go 语言的面向对象怎么使用? 下面我们从面向对象的三个基本特性说起:封装、继承和多态。

          封装,就是指运行的数据和函数绑定在一起,C++ 中主要是通过 this 指针来完成的; 继承,就是指 class 之间可以相互继承属性和函数; 多态,主要就是用统一的接口来处理通用的逻辑,每个 class 只需要按照接口实现自己的回调函数就可以了。

          封装

          package main
          
          import "fmt"
           
          type data struct {
              val int
          }
          
          func (p_data* data)set(num int) {
              p_data.val = num
          }
          
          func (p_data* data)show() {
              fmt.Println(p_data.val)
          }
          
          func main() {
              p_data := &data{4}
              p_data.set(5)
              p_data.show()
          }
          

          继承

          package main
           
          import "fmt"
           
          type parent struct {
              val int
          }
           
          type child struct {
              parent
              num int
          }
           
           
          func main() {
              var c child
           
              c = child{parent{1}, 2}
              fmt.Println(c.num)
              fmt.Println(c.val)
          }
          

          多态

          package main
          
          import "fmt"
          
          type act interface {
              write()
          }
           
          type xiaoming struct {
          }
          
          type xiaofang struct {
          }
          
          func (xm *xiaoming) write() {
              fmt.Println("xiaoming write")
          }
           
          func (xf *xiaofang) write() {
              fmt.Println("xiaofang write")
          }
          
          func main() {
              var w act;
          
              xm := xiaoming{}
              xf := xiaofang{}
          
              w = &xm
              w.write()
          
              w = &xf
              w.write()
          }
          

          以下就是 Go 语言的面向对象的使用方法。使用上比 C++ 表现得更加简洁和直接。

        • Go 语言中使用 defer 的几个场景

          2018-05-20 15:04:16 1216 0 技术文章

          简化资源回收,相当于析构函数

          在 Go 语言中,没有析构函数,如果需要在实例完成后进行资源回收的情况,可以使用 defer 语句。 defer 是先进后出,这样做很合理,后面的语句会依赖前面的资源,如果先前面的资源先释放了,那后面的语句就没法执行了。 当然, defer 也有一定的开销, 也有为了节省性能而回避使用的 defer 的。 使用示例:

          func set(mu *sync.Mutex, i int) {
              mu.Lock()
              mu.Unlock()
          }
          

          panic 异常捕获,recover 只能在 defer 语句中使用

          使用方法如下:

          func main() {
              defer func() {
                  if r := recover(); r != nil {
                      fmt.Println(r)
                  }
              }()
              panic("Error")
          }
          

          修改返回值,适用于特定场景

          func doubleSum(a, b int) (sum int) {
              defer func() {
                  sum *= 2
              }()
              sum = a + b
          }
          

          安全回收资源,即使 panic 抛出异常,recover 也可捕获

          不使用 defer 的情况,前面的语句出现异常,后面的语句就没有机会执行。

          func set(mu *sync.Mutex, i, v int) {
              mu.Lock()
              i := v / 0 // 0 不能做除数,会抛出异常,后面的语句不能被执行
              mu.Unlock()
          }
          

          使用 defer 的情况,即使前面出现异常,后面的语句照样可以执行。

          func set(mu *sync.Mutex, i, v int) {
              mu.Lock()
              i := v / 0 // 0 不能做除数,会抛出异常,后面的语句不能被执行
              mu.Unlock()
          }
          
        • SVN 仓库完美迁移到 Git 的方法

          2018-04-29 14:42:43 1282 0 技术文章

          使用 git svn clone 命令拷贝 svn 仓库

          cd ~
          mkdir temp
          git svn clone url/to/svn/repo/ -T trunk -b branches -t tags
          

          svn 的 url 不要加 trunk ,否则不能迁移 branches 和 tags

          新建 git 的裸仓库

          cd ~
          mkdir temp.git
          cd temp.git
          git init --bare
          

          将 git 的 master 和 svn 的 trunk 分支对应

          git symbolic-ref HEAD refs/heads/trunk
          
        • 阿里云服务器添加 Swap 分区

          2018-03-30 22:04:34 1390 0 技术文章

          Linux 中 Swap(即:交换分区),类似于 Windows 的虚拟内存,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

          由于我的 MySQL 总是报错 InnoDB: Fatal error: cannot allocate memory for the buffer pool 分配内存不足,使用 Swap 分区可以缓解内存不够的情况。

          • Tengine 配置优化小结

            2018-03-22 12:03:58 1657 0 技术文章

            Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。

            从2011年12月开始,Tengine成为一个开源项目,Tengine团队在积极地开发和维护着它。Tengine团队的核心成员来自于淘宝、搜狗等互联网企业。Tengine是社区合作的成果,我们欢迎大家参与其中,贡献自己的力量。

          • 阿里云登录报错 Permission denied (publickey,gssapi-keyex,gssapi-with-mic)

            2018-01-23 15:49:17 2949 0 技术文章
            vim /etc/ssh/sshd_config
            
            PasswordAuthentication yes
            

            重启服务器

            • Mac OSX 升级系统后 Git 出现 Error Running Git

              2017-11-16 17:55:28 1516 0 技术文章

              Mac 更新系统后 Git 不能用,提示信息如下:

              errors while executing git -- version. exitCode=1 
              errors: xcrun: error : invalid active developer path(/Library/Developer/CommandLineTools),missing xcrun at:
              /Library/Developer/CommandLineTools/usr/bin/xcrun
              

              解决办法:

              xcode-select --install
              
              • 使用 go 命令升级至 go1.9beta2

                2017-08-14 09:55:50 2183 0 技术文章

                从 go1.9beta2 运行 go 命令。

                若要安装 go1.9beta2,请运行:

                $ go get golang.org/x/build/version/go1.9beta2
                $ go1.9beta2 download