JoyLau's Blog

JoyLau 的技术学习与思考

怎么使用?

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)

前言

效果展示

在线地址

开始

需要准备

  • 这次要解析的是 网易云音乐的 MV
  • 需要准备的解析的有
  • 获取 MV 信息列表
  • 获取 MV 详细信息
  • 获取 MV 播放地址
  • 在线播放 MV
  • 获取 MV 排行榜
  • 获取最新 MV

说明

  • 大部分解析提供的接口都和我以前2篇文章类似,之前的文章有分析过,这里就不再多说了
  • 这里重点说明下 MV 的播放问题

关于 MV 的播放

  • 解析 MV 详细信息,可获得 MV 的真实播放的 MP4 的地址
  • 但是这个地址,网易云做了防盗链处理
  • 什么是防盗链?
  • 一般情况下,我的资源文件,比如 图片, css,js,视频,我们自己放到服务器上可以直接引用
  • 同样的道理,别人可以访问你的服务器,也可以直接引用
  • 那么,不想被别人引用怎么办呢?
  • 这就引申出了防盗链的操作
  • 最常见的防盗链的处理就是加上 referer识别,就是来源网址信息
  • referer 其实是个错误的拼写,这个就是有历史原因了,以前的开发人员在定义这个属性的时候,把这个单词写错了,后来没有人注意到,一直使用到他作为标准
  • 后来,也没有人去特意改他了,就这么用着吧
  • 这个是简单防盗链处理
  • 还有更复杂的,比如 js 加密路径信息,每次请求路径都会变化,这个就复杂了
  • 很幸运,网易云的 MV 采用的就是 referer 的识别方式
  • 那么就有相应的破解方法了

关于 referer

  • MP4 的地址在浏览器地址栏直接粘过去是可以播放的,但是由其他网站跳进去的则不能访问,因为带进了 rerferer
  • 那么,要做的就是去除 请求的 rerferer
  • 我找了很多资料也尝试了很多次,想在浏览器端把 rerferer 去除掉,基本是实现不了的,如果你实现在页面里单独请求 mp4 地址时不带referer, 请联系我
  • 那么要做的就是在服务端操作了
  • 在服务端操作很简单,就是伪造头信息进行请求

这个是带 referer 的请求,被网易云直接拒绝了

joymusic-mv-referer

这个是复制地址到地址栏,则可以直接播放

joymusic-mv-no-referer

服务单去除 referer

  • 严格来说不能说去除 refere,我们需要将原本我们自己服务器的 referer 修改为网易云服务器的 referer

Java 版

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
public void playMV(HttpServletResponse res, String mvurl) throws IOException {
if (StringUtils.isEmpty(mvurl)){
return;
}
res.setContentType("video/mpeg4; charset=utf-8");
URLConnection connection = new URL(mvurl).openConnection();
connection.setRequestProperty("referer", "http://music.163.com/");
connection.setRequestProperty("cookie", "appver=1.5.0.75771;");
connection.connect();
InputStream is = connection.getInputStream();
OutputStream os = res.getOutputStream();
byte bf[] = new byte[2048];
int length;
try {
while ((length = is.read(bf)) > 0) {
os.write(bf, 0, length);
}
} catch (IOException e) {
is.close();
os.close();
return;
}
is.close();
os.close();
}

解释:

  1. 首先我们请求的资源不是本地的资源,是存储在其他服务器上的,这里用到的是URL
  2. 这里我们需要设置 referer 和 cookie,结合前面使用的 URL, 这里使用的是URLConnection
  3. 后面的就很好理解了,相当于做了一个管道,将读取的文件流原封不动的通过Response返回给调用者
  4. 不要忘了设置 setContentType 为 MP4 的格式

nodejs 版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const express = require("express");
const router = express();
const request = require("request");

router.get("/", (req, res) => {
const url = req.query.url;
const headers = {
"Referer": "http://music.163.com/",
"Cookie": "appver=1.5.0.75771;",
'Content-Type': 'video/mp4',
'Location': url
};
const options = {
header: headers,
url: url
};
request(options).on('error', err => {
res.send({ err })
}).pipe(res)
});

module.exports = router;

解释:
和上面的 Java 版代码是一个意思,主要是 pipe 流管道将文件流返回给调用者

功能完成

  • 那么这样解决了 MP4 地址防盗链的问题

缺点

  • 不足之处也暴露了
  • 首先这段代码必须部署到服务端
  • 部署到服务端就需要服务器去拉去 MV 的流信息,这无疑给服务器增加过多的流量压力
  • 其次,由于使用的流传输,这个 MP4 的播放是不支持快进操作的

有个简单的解决方式

  • 在 html5 之后,想去除 referer 信息, a标签有个属性 rel
  • rel="noreferrer" 即可在 a 标签的 href 的链接上去除 referer信息
  • 这一属性已被我使用在播放器的右下角的一个小飞机的按钮上
  • 点击小飞机按钮就可以直接看 MV 视频了,流量走的是网易云的CDN,不再试自己的服务器

joymusic-mv-no-referer-href

不完美

  • 总感觉这个解决不够完美
  • 如果你看到这篇文章能有更好的解决办法,请联系我

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

0%