JoyLau's Blog

JoyLau 的技术学习与思考

本文转自 阮一峰- 开源许可证教程

开源许可证教程

作为一个开发者,如果你打算开源自己的代码,千万不要忘记,选择一种开源许可证(license)。

许多开发者对开源许可证了解很少,不清楚有哪些许可证,应该怎么选择。本文介绍开源许可证的基本知识,主要参考了 OpenSource.com (12)。

一、什么是开源许可证

开源许可证是一种法律许可。通过它,版权拥有人明确允许,用户可以免费地使用、修改、共享版权软件。

版权法默认禁止共享,也就是说,没有许可证的软件,就等同于保留版权,虽然开源了,用户只能看看源码,不能用,一用就会侵犯版权。所以软件开源的话,必须明确地授予用户开源许可证。

二、开源许可证的种类

目前,国际公认的开源许可证共有80多种。它们的共同特征是,都允许用户免费地使用、修改、共享源码,但是都有各自的使用条件。

如果一种开源许可证没有任何使用条件,连保留作者信息都不需要,那么就等同于放弃版权了。这时,软件可以直接声明进入“公共领域”(public domain)。

根据使用条件的不同,开源许可证分成两大类。

  • 宽松式(permissive)许可证
  • Copyleft 许可证

三、宽松式许可证

3.1 特点

宽松式许可证(permissive license)是最基本的类型,对用户几乎没有限制。用户可以修改代码后闭源。

它有三个基本特点。

(1)没有使用限制

用户可以使用代码,做任何想做的事情。

(2)没有担保

不保证代码质量,用户自担风险。

(3)披露要求(notice requirement)

用户必须披露原始作者。

3.2 常见许可证

常见的宽松式许可证有四种。它们都允许用户任意使用代码,区别在于要求用户遵守的条件不同。

(1)BSD(二条款版)

分发软件时,必须保留原始的许可证声明。

(2) BSD(三条款版)

分发软件时,必须保留原始的许可证声明。不得使用原始作者的名字为软件促销。

(3)MIT

分发软件时,必须保留原始的许可证声明,与 BSD(二条款版)基本一致。

(4)Apache 2

分发软件时,必须保留原始的许可证声明。凡是修改过的文件,必须向用户说明该文件修改过;没有修改过的文件,必须保持许可证不变。

四、Copyleft 许可证

4.1 Copyleft 的含义

Copyleft 是理查德·斯托曼发明的一个词,作为 Copyright (版权)的反义词。

Copyright 直译是“复制权”,这是版权制度的核心,意为不经许可,用户无权复制。作为反义词,Copyleft 的含义是不经许可,用户可以随意复制。

但是,它带有前提条件,比宽松式许可证的限制要多。

  • 如果分发二进制格式,必须提供源码
  • 修改后的源码,必须与修改前保持许可证一致
  • 不得在原始许可证以外,附加其他限制

上面三个条件的核心就是:修改后的 Copyleft 代码不得闭源。

4.2 常见许可证

常见的 Copyleft 许可证也有四种(对用户的限制从最强到最弱排序)。

(1)Affero GPL (AGPL)

如果云服务(即 SAAS)用到的代码是该许可证,那么云服务的代码也必须开源。

(2)GPL

如果项目包含了 GPL 许可证的代码,那么整个项目都必须使用 GPL 许可证。

(3)LGPL

如果项目采用动态链接调用该许可证的库,项目可以不用开源。

(4)Mozilla(MPL)

只要该许可证的代码在单独的文件中,新增的其他文件可以不用开源。

五、常见问题

本节回答一些开源许可证的常见问题。

5.1 什么叫分发(distribution)?

除了 Affero GPL (AGPL) ,其他许可证都规定只有在“分发”时,才需要遵守许可证。换言之,如果不“分发”,就不需要遵守。

简单说,分发就是指将版权作品从一个人转移到另一个人。这意味着,如果你是自己使用,不提供给他人,就没有分发。另外,这里的“人”也指“法人”,因此如果使用方是公司,且只在公司内部使用,也不需要遵守许可证。

云服务(SaaS)是否构成“分发”呢?答案是不构成。所以你使用开源软件提供云服务,不必提供源码。但是,Affero GPL (AGPL) 许可证除外,它规定云服务也必须提供源码。

5.2 开源软件的专利如何处理?

某些许可证(Apache 2 和 GPL v3)包含明确的条款,授予用户许可,使用软件所包含的所有专利。

另一些许可证(BSD、MIT 和 GPL v2)根本没提到专利。但是一般认为,它们默认给予用户专利许可,不构成侵犯专利。

总得来说,除非有明确的“保留专利”的条款,使用开源软件都不会构成侵犯专利。

5.3 什么是披露要求?

所有的开源许可证都带有“披露要求”(notice requirement),即要求软件的分发者必须向用户披露,软件里面有开源代码。

一般来说,你只要在软件里面提供完整的原始许可证文本,并且披露原始作者,就满足了“披露要求”。

5.4 GPL 病毒是真的吗?

GPL 许可证规定,只要你的项目包含了 GPL 代码,整个项目就都变成了 GPL。有人把这种传染性比喻成“GPL 病毒”。

很多公司希望避开这个条款,既使用 GPL 软件,又不把自己的专有代码开源。理论上,这是做不到的。因为 GPL 的设计目的,就是为了防止出现这种情况。

但是实际上,不遵守 GPL,最坏情况就是被起诉。如果你向法院表示无法履行 GPL 的条件,法官只会判决你停止使用 GPL 代码(法律上叫做“停止侵害”),而不会强制要求你将源码开源,因为《版权法》里面没有相应的规定。

怎么使用?

pom 中引入插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<plugin>
<groupId>cn.joylau.code</groupId>
<artifactId>joylau-compressor-plugins</artifactId>
<version>1.2.RELEASE</version>
<executions>
<execution>
<id>resource-compressor</id>
<phase>compile</phase>
<goals>
<goal>resource-compressor</goal>
</goals>
</execution>
</executions>
<configuration>
<cssConfigs>
<cssConfig>
<dir>/static/css</dir>
<include>*.css</include>
<exclude>*.min.css</exclude>
</cssConfig>
</cssConfigs>
<jsConfigs>
<jsConfig>
<dir>/static/js</dir>
<include>*.js</include>
<exclude>*.min.js</exclude>
<munge>true</munge>
</jsConfig>
</jsConfigs>
<htmlConfigs>
<htmlConfig>
<dir>/templates</dir>
<include>*.html</include>
<removeIntertagSpaces>true</removeIntertagSpaces>
<compressJavaScript>false</compressJavaScript>
<compressCss>true</compressCss>
</htmlConfig>
</htmlConfigs>
</configuration>
</plugin>

配置解释

  • phase : compile 表明该插件在 compile 时调用

  • goal : 固定为 resource-compressor 不需要改变

  • cssConfigs , 可配置多个 cssConfig

    • cssConfig
      • dir: css文件目录
      • include:包含的css文件,支持通配符
      • exclude:排除的css文件,支持通配符
  • jsConfigs , 可配置多个 jsConfig

    • jsConfig
      • dir: js文件目录
      • include:包含的js文件,支持通配符
      • exclude:排除的js文件,支持通配符
      • munge: 是否进行代码混淆,缺省值为 false
      • preserveAllSemiColons : 保留所有的分号,缺省值为 false
      • disableOptimizations : 禁用自带的所有优化措施,缺省值为 false
  • htmlConfigs , 可配置多个 htmlConfig

    • htmlConfig
      • dir: js文件目录
      • include:包含的js文件,支持通配符
      • exclude:排除的js文件,支持通配符
      • removeComments: 是否移除注释,缺省值为 true
      • removeIntertagSpaces : 是否移除标签之间的空格,缺省值为 false
      • compressJavaScript : 是否对html里的js代码进行压缩,缺省值为 false
      • compressCss : 是否对html里的css代码进行压缩,缺省值为 false

压缩信息

当看到以下图片所示的信息后,则压缩成功

joylau-compressor-plugins

例如 :[INFO] common.js(8.71KB==>4.58KB,47.39%)

表示 :common.js 源文件大小8.71KB,压缩后大小 4.58KB,压缩率47.39%

GitHub 地址

源码已开源,地址 : https://github.com/JoyLau/joylau-compressor-plugins

  • 今天在浏览网站时,http://ai.baidu.com/ ,看到一个CSS3的效果:将鼠标放到图片上,图片会稍稍方大一点,当时很好奇是怎么做的
  • 当即百度了一下,有人用js做的,有人用css做的,首先js做的肯定不够好,一看效果就是css3的效果
  • 于是自己查看了下 这块 div 的效果
  • 将压缩的css展开来
  • 原来是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 鼠标移上去各浏览器的延时效果
.solution-img {
height: 100%;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transition: -webkit-transform .2s;
transition: -webkit-transform .2s;
-moz-transition: transform .2s,-moz-transform .2s;
transition: transform .2s;
transition: transform .2s,-webkit-transform .2s,-moz-transform .2s
}

# 鼠标移上去各浏览器的放大倍数
.solution-item:hover .solution-img {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
transform: scale(1.1)
}

将 Scala 依赖 scala-library 和插件 scala-maven-plugin 添加到 Maven 项目中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    <dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.7</version>
</dependency>



<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

更新完上面的内容之后,你需要等待Maven下载完所有的依赖。

安装IDEA插件 Scala
现在可以在Java工程中使用Scala代码了
创建新的文件夹src/main/scala;
Scala Maven插件将会识别这些目录,并且编译其中的Scala文件:

1
2
3
4
5
6
object BooksProcessor {
def filterByAuthor(author: String)(implicit books: util.ArrayList[Book]) = {
books.filter(book => book.getAuthor == author)
}

}

今天没有图片

在做单系统的情况下,我还是比较喜欢使用Google 的 Guava 来做缓存的,结合 SpringBoot 使用非常简单 :

1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>

再配置 yml :

1
2
3
4
5
6
spirng:
cache:
type: guava
cache-names: api_cache
guava:
spec: maximumSize=300,expireAfterWrite=2m

上述配置了一个 缓存名为 api_cache 的缓存 ,最大数量为300,超时时间为2分钟

接下来,在类中使用注解 @CacheConfig(cacheNames = “api_cache”) 来配置整个类的配置
@Cacheable() 注解在方法上来 开启方法的注解

使用很透明

今天再次使用时发现guava.spec提示过期了,查了下文档,文档原话是这样说的:

@Deprecated
@DeprecatedConfigurationProperty(
reason = “Caffeine will supersede the Guava support in Spring Boot 2.0”,
replacement = “spring.cache.caffeine.spec”
)

原来,在SpringBoot2.0中推荐使用Caffeine,表达式就是spring.cache.caffeine.spec

更改的方法很简单,改下依赖包,换个配置名,又可以愉快的额使用了:

1
2
3
4
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>

更新配置:

1
2
3
4
5
6
spirng:
cache:
type: caffeine
cache-names: api_cache
caffeine:
spec: maximumSize=300,expireAfterWrite=2m

通常SpringBoot默认的keyGenerator 是SimpleKeyGenerator,这个策略是以参数作为key值,如果参数为空的,就会返回SimpleKey[]字符串,这对于很多无参的方法的就有问题了
我们需要重新这个keyGenerator,实现 org.springframework.cache.interceptor.keyGenerator 这个接口即可,将key值设置为类名+方法名+参数名,这样就不会冲突了

1
2
3
4
5
6
7
8
9
10
11
12
@Bean
public KeyGenerator caffeineKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}

感觉无缝切换,继续使用吧!!!

制作背景

  • 有时候宅在家里实在不知道玩什么游戏
  • 英雄联盟都玩烂了
  • 哥们提议玩红警
  • 红警是单机啊,一个人玩另一个人怎么办,一个人打电脑有啥意思 =_=|
  • 找对战平台啊,首先下载安装了红警玩家自制的战网对战平台
  • 我个人电脑从来不安装杀毒软件,Windows Defender 一直报毒搞个不停
  • 战网的平台体验也很不好,消息弹个不停,感觉像广告软件
  • 后来换了腾讯对战平台,进入红警起个名字老说含有敏感信息,结果起了半个小时,MDZZ
  • 决定自己了解下对战平台的原理,打算自己写个简单好用的玩

原理

通过socket hook + udp,针对war3来说,支持tcp,先在本地通过hook模拟建立tcp连接,然后将tcp的数据转成外网udp数据发给外网服务器转发给其他客户端,客户端接收到后通过本地tcp
模拟连接转发到游戏进程。这个过程中通过中转服务器协助进行p2p。
JoyGame-zhihu

上面是知乎上的回答
用我自己的话说就是

使用JoyGameClient客户端,在本地创建了一个虚拟的IP地址,每一个客户端通过连接远程服务器形成了一个虚拟局域网,这样在游戏的【局域网】选择项中就能找到彼此,这样自然一方创建一个游戏,其他人都可以加入进来了就能愉快的玩耍了。底层通信使用的就是TCP和UDP连接,在同一个房间的玩家都会向服务器发送和下载游戏的实时数据。服务器会向房间里的玩家的客户端上转发数据包,这样就间接形成了一个局域网,就能在一起玩游戏啦。

使用

  • 解压,打开JoyGameClient.exe
  • 选择中间的网络服务器,因为你本地肯定是没有服务端的,只能连接远程部署好的服务器
    JoyGame-Login
  • 没有账号,就注册一个账号,注册成功后登录平台
    JoyGame-Login
  • 这是主界面
  • 接下来进入一个你想玩的游戏的房间
  • 设置你的游戏启动主程序
    JoyGame-Login
  • 下面可以设置启动时游戏的参数,比如玩红警时,加入参数 -win,可以窗口启动
  • 之后点启动,进入游戏就可找到在一个房间的小伙伴了
  • 使用都很简单,看一遍就会

特色

  • 可以聊天,发表情,可以加好友。。。额,这些好像没有什么特色
    JoyGame-Login

我想说

如果你想玩玩以前的一些怀旧游戏,或者你想看看该平台是如何操作实现联机的,还等什么,跟着Joy一起来玩吧
私聊我可以给你开个 VIP 、等级直接升到将军哦!虽然没什么用,纯粹装*

下载

一款将 SpringBoot 项目做成Windows Service 的 Maven 插件

包括但不限于 SpringBoot ,任何打成 java jar 包运行的 Maven 项目都可以使用

编写初衷

  • 公司有个项目
  • Java 部分的全部使用的是SpringBoot
  • 该项目的部署环境是 Windows
  • 公司想把 各个 SpringBoot 的模块托管一下
  • 托管的使用方式要简单,易用,测试在打包部署的时候要很容易上手
  • 期间尝试过 Spring Boot Admin 和 Jenkins,都说不好用…
  • 于是就想着 将Spring Boot 的服务制作成 Windows 服务,这样基本上会操作电脑的人都会使用了,够简单易用的了吧
  • 花了一上午时间将其中一个 Spring Boot 模块制作成了 Windows Service
  • 发现再做其他的模块的时候,很多工作都是重复的,心想着能够将这个功能提取出来就好了
  • 于是就写了这个 Maven 插件

使用演示地址:

怎么使用?

  • 使用方法很简单,和普通的 Maven 插件一样使用就可以了,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <plugins>
    <plugin>
    <groupId>cn.joylau.code</groupId>
    <artifactId>joylau-springboot-daemon-windows</artifactId>
    <version>1.0.RELEASE</version>
    <executions>
    <execution>
    <id>make-win-service</id>
    <phase>package</phase>
    <goals>
    <goal>make-win-service</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>

注意:

  1. 这里的 phase 写的是 package,意思是该插件在 mvn package 的时候调用,你也可以根据不同的需求来更改,比如 install, test等等
  2. goal 写 make-win-service 就可以了,不需要改动
  3. 一般情况下我们的SpringBoot项目会有其他父项目,这时打包会使用 spring-boot-maven-plugin 插件的 repackage,这样的情况的话,请将该插件放置最后面,否则服务运行的话将提示没有主属性
  • 在你的项目中按照以上的方式引入插件后,现在可以 打包了
    1
    mvn package

打包过程中,看到如下日志信息,便制作成功了:
joylau-springboot-daemon-windows-package-info

此时,在你项目的target目录下会生成一个 jar 包名字 一样的压缩包
进入文件夹,解压这个压缩包,你会看见如下内容的文件
joylau-springboot-daemon-windows-package-file
注意:

  1. 5个 bat 文件,请右键以管理员的身份运行
  2. 各文件的文件名无特殊情况,不需要修改
  3. 一旦安装成了 Windows 服务,目录下的文件就不要移动了
  4. 命令运行时,可能会提示安装.NET,安装完成就可运行命令了,不过现在大部分的 Windows 服务器或者个人电脑都会默认安装了.NET,没有的话启用一下就好了,如下图:
    joylau-springboot-daemon-windows-.NET
  5. 运行各个命令是注意提示信息,例如卸载完服务都的状态为NonExistent,刚安装完服务后的状态为Stopped,服务成功启动的状态为Started…等等
    joylau-springboot-daemon-windows-service-status

扩展参数

想要在服务启动时添加自定义参数,如 SpringBoot 的配置参数或者 JMV 参数?
像如下配置即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<plugin>
<groupId>cn.joylau.code</groupId>
<artifactId>joylau-springboot-daemon-windows</artifactId>
<version>1.0.RELEASE</version>
<executions>
<execution>
<id>make-win-service</id>
<phase>package</phase>
<goals>
<goal>make-win-service</goal>
</goals>
</execution>
</executions>
<configuration>
<arguments>
<argument>--server.port=9090</argument>
</arguments>
</configuration>
</plugin>

上面配置了一个 Spring Boot 应用的启动端口9090

使用注意

  • 打包使用过程中需要联网
  • 文档中有些图片可能看不到,再次刷新下页面就可以
  • 服务的id为artifactId,服务的名称为artifactId+version,服务的描述为description

GitHub 地址

源码已开源,地址 : https://github.com/JoyLau/joylau-springboot-daemon-windows

前言

效果展示

JoyMusic-NoReferer
JoyMusic-NoReferer
JoyMusic-NoReferer

在线地址

问题说明

  • 为什么解析的 MV 地址无法直接播放,在上一篇文章上我也说明了
  • 相应的解决办法我在上一篇文章上也说明了
  • 这样的方法有很明显的缺点,在上一篇文章也说明了
  • 这个方法只能实现播放的功能,但是距离完美或者说好的展示效果来说,并不满意
  • 我自己就很不满意

开始动手

先说下我是怎么解决的

  • 解决的方法还是一样:去除referer
  • 同时去除了原来使用的jPlayer播放器,因为这个播放器在移动设备下的表现并不是很好,现在改为浏览器自带的视频播放空控件
  • 这个东西就没有什么兼容性了,只要IE10 以上支持HTML5 的都可以观看
  • 正如上面我截图所示的那样,我使用的是 Safari 浏览器,表现效果还是很好的
  • 同时也加入了一些比较棒的小功能:比如下滑看评论的时候,会出现小视频框在右下角
  • 我个人是比较喜欢看评论的,一些音乐或者 MV 页面打开后并不是先听或者先看,都是翻到下面看看评论
  • 这也正是我喜欢网易云音乐的原因之一,网易云音乐的评论大部分都很精彩,有时候听歌不如看评论

现在是怎么在页面上去除referer的?

  • 动态生成一个iframe,我本身是比较反对使用iframe的,因为以前使用的extjs使用的多了,都用吐了,而且性能还不是很好
  • 但是在这里它可就起了大作用了
  • iframe 里的页面就放一个<video>
  • iframe 的宽度高度及video的宽度高度都要调节好,其实这一步花了我不少时间,因为并不是所有的MV宽高的比例是一样的
  • iframe 的src不能直接写MV的MP4地址,因为那样的话就没有作用了
  • 在src里写js脚本动态生成html页面,页面里面包括的之前提到的video
  • 使用这种方法就可将网站的referer去除掉
  • 这就类似于直接在浏览器的地址栏上输入MP4的地址然后播放
  • 在前一篇的文章分析中,我们知道,这种方法是可以播放的

编写代码

动态渲染iframe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
return '<iframe \
style="border 1px solid #ff0000" \
scrolling="no" \
frameborder="no" \
allowtransparency="true" ' +
/*-- Adding style attribute --*/
objectToHtmlAttributes( iframeAttributes ) +
'id="' + id + '" ' +
' src="javascript:\'\
<!doctype html>\
<html>\
<head>\
<meta http-equiv=\\\'Content-Type\\\'; content=\\\'text/html\\\'; charset=\\\'utf-8\\\'>\
<style>*{margin:0;padding:0;border:0;}</style>\
</head>' +
/*-- Function to adapt iframe's size to content's size --*/
'<script>\
function resizeWindow() {\
var elems = document.getElementsByTagName(\\\'*\\\'),\
width = parent.document.getElementById(\\\'panel-c\\\').offsetWidth-7,\
height = 0,\
first = document.body.firstChild,\
elem;\
if (first.offsetHeight && first.offsetWidth) {\
width = first.offsetWidth;\
height = first.offsetHeight;\
} else {\
for (var i in elems) {\
elem = elems[i];\
if (!elem.offsetWidth) {\
continue;\
}\
width = Math.max(elem.offsetWidth, width);\
height = Math.max(elem.offsetHeight, height);\
}\
}\
var ifr = parent.document.getElementById(\\\'' + id + '\\\');\
ifr.height = height;\
ifr.width = width;\
};\
</script>' +
'<body onload=\\\'resizeWindow()\\\'>\' + decodeURIComponent(\'' +
/*-- Content --*/
encodeURIComponent(html) +
'\') +\'</body></html>\'"></iframe>';

注意这里的反斜杠不要去掉,是用来转义的,代码的样式虽然丑了点,但是并不影响使用

  • 这里面有个方法是encodeURIComponent(html),这个是转义了video里面的url链接
  • 在iframe的body加载完成后会调用resizeWindow()函数自适应下iframe的宽高
  • html里面写的就是要放入iframe的body里的代码,这里我们放的肯定是video
  • 于是,可以将上述代码封装成一个函数,在父页面是直接调用
  • 封装的时候我们还可以传一些参数,比如上面的iframe的初始的宽高,style,scrolling,frameborder等等

扩展一下

  • 这个方式使用的是video
  • 那么<img>呢?现在有些网站的图片也是经过了防盗链处理,这种方法也是可以实现去掉referer,直接访问图片的额

欢迎大家来看看试试看!😘 http://music.joylau.cn (当前版本 v1.5)

0%