0%

前言

有些朋友没有兴趣看我这啰嗦的记录可以直接跳到解决方案那一节。

小米的手机能不能在日本用?

之前给老婆买了一台小米的Note3,办的是日本乐天(Rakuten Mobile)的格安SIM卡,装上之后时不时的断网。老婆一怒之下把手机扔给我说“难用死了,我要换手机!”

然后就去日本的Yodabashi Camera办了UQ Mobile的SIM卡,还送了一台华为P10 Lite。UQ Mobile的速度比我Line Mobile的卡不知道快了多少。
Line Mobile 在2017年初的时候速度还挺快,后来慢慢的用的人多了?速度就降了下来,用Speedtest测的话只能达到2Mbps左右的网速。而老婆的手机却能测得20Mbps,让人眼馋。

我之前也是用的乐天,后来改用了Line Mobile。小米Note3貌似对日本的服务商支持不太好,我接过来之后装上也是时不时的断网。解决办法就是断网的时候就切换一下APN。看老婆的手机用的那么舒爽,于是决定也换成UQ Mobile,心想大不了也想原来一样上不了网的时候就切换一下APN嘛。

事与愿违

事实是我想的太简单了。刚开始装上SIM卡的时候,走出Yodobashi的大楼就不能用了,后来回到家里能用了一段时间,但是在上班路上电车里却总也连不上信号。就这样无信号的过了一整天。后来干脆显示为SIM卡无法识别。。。

折腾

Read more »

普通Spring Boot程序的部署

传统的spring boot web程序,其pom.xml和main函数所在的class通常是这样的。
以spring boot guide提到的程序为例,通常只需要在pom中这样写就可以让程序正常执行了

1
2
3
4
5
6
7
8
9
10
11
12
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

Spring Boot自带的tomcat容器,可以让程序无需依赖外面的容器,实现更好与外部环境的松耦合。
在诸如cloud foundry之类的环境里可以无障碍运行,但是在sap cloud platform neo环境中,
部署后的程序却总是无法正常运行,显示为404 not found。

怎样将Spring Boot程序部署在Neo上

查来查去在网上找到了sap自己给出的sample,比对了半天发现问题出在pom.xml和main函数的写法上。
spring-boot-getting-started

SAP给出的guide上明确的写着,

  1. pom.xml要写成这样:
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
<dependencies>
<!-- developer tools for hot code-replacement etc. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<!--Embedded tomcat etc. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

因为SAP Cloud Platform的Neo环境中内置了Tomcat容器,所以当部署到Neo上去的时候,你的程序就不应该再内嵌tomcat了。

Read more »

如果你在自己的Pandorabox/openwrt/lede上安装了aria2,你或许希望在外网能够访问自己家的服务器,这时候就要用到ddns。

花生壳提供的壳域名,历史悠久,便宜好用。
注册了花生壳域名之后,这篇文章教你怎样给自己的路由器设置DDNS。

前提

你家的路由器有公网的ip地址。有些家庭只有内网IP,没办法,联系电信运营商让他们给你开通吧。比如说你家要装个监控摄像头之类的。

设置花生壳域名

首先通过访问 http://ipinfo.io 这个网站,来获取自己路由器当前的ip地址。

获取了ip地址以后,在壳域名的设置页面

  1. 打开花生壳设置
  2. 测试 http://[USERNAME]:[PASSWORD]@ddns.oray.com/ph/update?hostname=[DOMAIN]&myip=[IP]
    把Username,Password,DOMAIN和IP替换成自己的用户名密码,域名和IP,测试一下能否更新。

有些情况下花生壳给的域名无法正常更新,原因不明。只能选择能够更新的来用了。

CbX3PU.md.jpg

Read more »

参考来源: Openwrt配置NAT6

假如你家的路由器是Pandorabox(或者其他openwrt,lede)的路由器,并且你家的网络支持ipv6, 那怎样设置路由器来实现网络提速呢?
先来看一下我家网络的提速效果:

speed test

之前家里的网络速度一直徘徊在100M以下,设置了ipv6之后,一直保持在100M左右。

ipv6比ipv4更快吗?

ipv6比ipv4更快吗?

说 IPv6 能提高「网速」通常是指新建的 IPv6 网络通常具有更大的带宽(比如中国正在新建的 CERNET2 骨干网动辄 10Gbps、100Gbps 的连接带宽)、更好的流量控制、更少的 NAT 从而实现更高效的网络拓扑结构(IP 地址资源多从而不需要对数据包进行多次地址翻译和转发)。在这些方面 IPv6 确实是能提高「网速」的。

NAT的工作原理

当内部网络中的一台主机想传输数据到外部网络时,它先将数据包传输到NAT路由器上,路由器检查数据包的报头,获取该数据包的源IP信息,并从它的NAT映射表中找出与该IP匹配的转换条目,用所选用的内部全局地址(全球唯一的IP地址)来替换内部局部地址,并转发数据包。
当外部网络对内部主机进行应答时,数据包被送到NAT路由器上,路由器接收到目的地址为内部全局地址的数据包后,它将用内部全局地址通过NAT映射表查找出内部局部地址,然后将数据包的目的地址替换成内部局部地址,并将数据包转发到内部主机。
nat工作原理

设置步骤

Read more »

想要得到字符串的MD5哈希值怎么办?
先来了解一下MD5哈希值的概念。

MD5散列

一般128位的MD5散列被表示为32位十六进制数字。以下是一个43位长的仅ASCII字母列的MD5散列:

1
2
MD5("The quick brown fox jumps over the lazy dog")
= 9e107d9d372bb6826bd81d3542a419d6

即使在原文中作一个小变化(比如用c取代d)其散列也会发生巨大的变化:

1
2
MD5("The quick brown fox jumps over the lazy cog")
= 1055d3e698d289f2af8663725127bd4b

也就是说,给你一串字符串,你要把它转换成固定长度的散列。
##用Java来实现MD5哈希值
Java中可以这样实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
String password = "123456";

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();

//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Digest(in hex format):: " + sb.toString());

byte数值转换为int数值时的注意事项

那么问题来了,下面这行代码做的是啥?
Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1)
这行语句其实是将byteData中的byte类型的数据转换成十六进制的数据进行表示。
为什么这么复杂?
是因为要考虑到byteData中的负数。

Read more »

在hexo执行下列命令时,没有看到生成的结果,只看到了一个kill之类的中断语句。

1
hexo generate

原因很可能是你的服务器(vps)swap不足。
通过执行下列命令可以增加swap内存。

1
2
3
sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
sudo mkswap /swapfile
sudo swapon /swapfile
Read more »

问题的提出

Spring中的依赖注入(DI)为何而生?
下面这篇日语文章提到,所有的Web应用都需要考虑到下面三个问题。[] http://penguinlabo.wp.xdomain.jp/understandspringmvc/

  1. 对象的生命周期问题。
    假设你用Servlet来接收用户的访问请求,有一个用户需要访问一个页面,你就需要一个线程来负责处理这个请求,并调用某个业务逻辑(比如调用一个UserService的实例)。如果处理不当,每新增一个用户就实例化一个业务逻辑(new一个UserService的实例),随着访问用户的增多,就会给系统带来大量垃圾回收负担,以及内存消耗的问题。为了防止这种情况发生,就需要把业务逻辑的部分设计为Singleton的,这样就不会每次都新增一个实例
  2. 松耦合问题。
    为了实现Web程序中的松耦合,即让一个类与另一个类不是那么的紧密结合,通常需要接口(Interface)来实现。但是单存的利用Interface并不能实现松耦合。还需要利用一些技巧,比如Factory Method等设计模式。
  3. 技术细节的隐藏。
    当你写一个User或者SalesOrder类的时候,你希望专注于自己的业务逻辑,比如创建用户,删除用户,创建订单,删除订单这些具体的业务。如果你在这些类中再加上访问记录(log)处理,就会明显的影响你程序的可读性。因为本质上log处理和你的业务逻辑没有什么联系,两者混杂在一起就会让人看起来比较头大。还有一些异常处理类的逻辑也会产生同样的问题。你怎样才能把这些和真正的业务逻辑无关的逻辑分离出去?

问题的回答

Spring给出的解决方案是这样的。
1)对象的生命周期问题。=>DI
2)松耦合问题。 => DI
3)技术细节的隐藏。=>AOP

首先Spring是怎么实现DI的呢,是通过DI Container来实现的。
在没有使用DI的Web应用中,Controller用到Service的时候,会生成(new)一个,Service用到DAO的时候,也是同样的生成(new)一个。 而使用了DI的Spring,则将实例化的工作全部交给了DI Container去做。 Controller中仅仅声明了Service接口的一个属性,具体的实现(new)没有去做,同样Service中也只是声明了一个DAO接口的一个属性,也没有去实现(new)。当需要实例的时候,就让DI Container根据配置去找到合适的类去实例化相应的接口属性。 而用Spring写成的Web程序,其处理顺序可以用下图来表示

  1. Dispatcher Servlet接收用户访问请求
  2. Dispatcher Servlet利用HandlerMapping取得URL所对应的Controller对象
  3. Controller来实行业务逻辑,调用Service对象和DAO对象得到业务数据,并把数据放到Model中。并返回一个View的名字,希望把数据显示到该View上。
  4. Dispatcher Servlet得到View的名字后,调用View Resolver来得到相应的View对象。
  5. Dispatcher Servlet把View对象生成为一个画面(View),画面包含Model对象中的数据,然后把这个View返回给用户(response)。用户的浏览器把这个画面呈献给用户。
Read more »

怎样理解 Javascript Closure 也就是闭包的概念,想必很多人在为此头疼。 笔者先后参考了下面这些资料

作者们都声称自己搞懂了闭包的概念,可自己还是看的云里雾里。 直到笔者看到下面这篇文章,才开始真正理解闭包的概念和应用场景。 Jonathan D. Johnson的博客 http://jondavidjohn.com/javascript-closure-explained-using-events/ 下面我试着把这篇文章边翻译边把自己的理解写出来。 先看一下下面这段程序, 效果:在第3次按下button的时候显示”Third time’s the charm”的消息框。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById("button");

element.onclick = function() {
// increment outside counter
counter++;

if (counter === 3) {
// do something every third time
alert("Third time's the charm!");
// reset counter
counter = 0;
}
};

程序中声明了一个全局变量counter,每次按下button都会唤起程序,从而让counter++ 如果你只在自己的网页中执行一次的话,这么写也无所谓,但是如果你想在其他地方复用的话, 最好还是把这段程序封装成单独的一个函数。 这时问题就来了,你要每次都声明一个外部的全局变量counter吗?很明显这种做法太笨拙。 于是closure的作用就发挥出来了。 如果你看过了MDN的解释,就会知道closure其实是这样一种机制,

函数可以访问它被创建时所处的作用域中的对象(Object)。

于是上面那段程序利用闭包可以优化成下面这种形式:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<input type="submit" id="button1" value="button1" class="button"/>
<input type="submit" id="button2" value="button2" class="button"/>

<script>
var myClosureFunc = function () {
// init the count to 0
var count = 0;
return function (e) {
//count
count++;

if (count === 3) {
// do something every third time
alert("Third time's the charm!");
//reset counter
count = 0;
}
};
}

var element1 = document.getElementById("button1");
element1.onclick = myClosureFunc();

var element2 = document.getElementById("button2");
element2.onclick = myClosureFunc();
</script>


</body>
</html>

  counter的位置移到了event handler函数的内部,而函数的返回值为一个闭包。 按照上面的概念,myClosureFunc中的闭包可以访问它创建时所处的作用域(scope), 于是它就可以访问自己的counter,而这个counter是相对全局的,也就是说,在element1被按下的过程中,这个counter是共有的。 而element1和element2中的counter又是相对独立的。 怎么样,有没有帮你理解closure在作用域这个概念里所起的作用?

Read more »

如果你在进行[SAPUI5 Tutorial] Test Suite and Automated Testing Step10 时遇到过 SAPUI5 QUnit 404 not found 问题, /resources/sap/ui/qunit/qunit-redirect.js 404 not found 这篇文章将帮你找到解决方法。 正如Tutorial一开始写的那样

If you are running the tutorial in SAP Web IDE, you will have to configure the project descriptor neo-app.json. In this descriptor file, the path to the resources is already configured. Other development environments might need the resources to be copied to the server. Alternatively, you can use the CDN version of https://sapui5.hana.ondemand.com/resources/sap-ui-core.js.

也就是说,如果你使用的是Web IDE,而你又是copy的Tutorial中给出的code,你还需要配置项目的neo-app.json文件让项目找到resources系列的文件。 If you are using web IDE and copied the code from the sample, you may aslo need to set up the neo-app.json file to let the project find the resource folder. 具体配置如下所示,其实就是简单复制一下从头开始新建的项目中的neo-app.json文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"welcomeFile": "/webapp/test/test.html",
"routes": \[
{
"path": "/resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/resources"
},
"description": "SAPUI5 Resources"
},
{
"path": "/test-resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/test-resources"
},
"description": "SAPUI5 Test Resources"
}
\],
"sendWelcomeFileRedirect": true
}
Read more »

在hybris的accelerator中新建CMS组件(hybris cms component)的步骤包括: *注意:hybris addon中的步骤有所不同,将在另一篇文章中记述。

  1. 自定义hybris item,在extension的items.xml文件中定义,类似于任何其他hybris item。
  2. 一个继承AbstractCMSComponentController的Spring MVC控制器,或使用DefaultCMSComponentController。
  3. 用于在页面上呈现组件的JSP,根据需要使用HTML,CSS和Tag Libraries。

可以通过XML配置为组件自定义hybris WCMS Cockpit:

  1. editorArea_typeName.xml:WCMS Cockpit编辑器区域的配置文件。
  2. contentEditor_typeName.xml:用于LiveEdit模式和联机编辑的配置文件
  3. wizardConfig_typeName.xml:如果通过向导对话框添加组件,则通过此文件进行向导配置。
Read more »