帐前卒专栏

code, software architect, articles and novels.
代码,软件架构,博客和小说

这几天一直在捣鼓blog.因为很久没有用Octopress写blog.另外也没有碰HTML相关。所以写markdown或者改Octopress都手生。这里把各种修改方法一一记下。要学习的是ruby, Liquid.

Read more »

0. 前言

       下面这个blog介绍一下如何借助有道云笔记来写blog. 这里的blog当然是公开的非私密的。帐前卒 的 blog是借助Octopress搭建在github上,使用的markdown写成。由于github对于免费的成员只提供400MB的空间。对于图文并茂的blog来说,这点空间有点相形见绌。所以急需找到一个能提供图片分享的地方。图片分享的地方很多:

  1. 当然很多图床网站可以提供的(当然也有可能不小心被封了)
  2. 小bbs站(游客身份也可以查看,同时这个小站提供上传图片功能)可以试试有道云笔记官方论坛
  3. 网易云相册啥的
  4. 各种其他的blog站点,写一篇blog上传,里面加入图片。然后把图片地址放入markdown中
  5. 本文重点要介绍使用有道云笔记 分享方式添加图片。不过这一种不如前面几种简单实用。但是可以分享25M以下的任意图片,并且没有数量限制,空间还在不断增长。

1. 分享你的图片

       首先打开有道云笔记的客户端,然后创建一篇新的笔记,然后点击**‘分享链接’**
分享链接 图片

2. 获取图片地址

       打开浏览器(chrome, 火狐,IE均可) 这里只介绍firefox. 点击分享链接。然后在调出firebug. 使用它,选中你要获取的图片。然后就可以看到下面这段html. 注意其中的src属性。没错,这就是你的图片url了。

firebug界面

3. 在markdown中编辑

        接下来要做的就是在markdown中插入图片.
![图片名] (刚才从有道云笔记分享获取的url)

4. 发布

        这里就没有什么好说的了。Deploy it!
另外编写markdown需要注意的:

  1. 段首空格需要加   另外如果需要多个空格,那么每个&nbsp之间都要有空格。
  2. 如果写为段落列表那么需要在每个列表后加入一个空行
  [空行]
  1.  aaa
  1.  bbb 

帐前卒今天遇到 JAVA mail MimeUtility.quote 函数抛出 NULL Pointer Exception问题。找这个问题的确废了一番功夫:看栈信息,看源码,debug.  然后终于发现了问题的原因:

在Email里MimeBody中有这样一行:

Content-Type: application/octet-stream; name=""

这句话相当的神奇,让JavaMail抛出NPE. 
但是这个问题是JavaMail这个库有问题,还是这封email没有遵循rfc规范?

于是 帐前 卒 找了一下rfc文档,在 rfc 2045 中找到了5.1章,发现如下内容:

value := token / quoted-string

token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
                 or tspecials>

tspecials :=  "(" / ")" / "<" / ">" / "@" /
                   "," / ";" / ":" / "\" / <">
                   "/" / "[" / "]" / "?" / "="
                   ; Must be in quoted-string,
                   ; to use within parameter values

这是语法定义。这里说,对于Content-Type header域的词法定义中,明确写了,不应该为空。那么JavaMail在这里发现为空抛出Exception也是理所应当。所以错在发信方。看到这里,那封不能被很好解析的邮件该怎么丢弃就怎么丢弃吧。然后把这个bug反馈给发信方。所以软件开发…还是需要时不时的看看rfc呀…

另外上面的问题是在获取Multipart p后,调用p.getContent(); 或者 p.getDataHandler()或者p.getInputStream()方法时,抛出的Null Pointer Exception.

Caused by: org.apache.http.ProtocolException: The server failed to respond with a valid HTTP response

昨天帐前卒使用java 的HttpClient时遇到这个错误。这个错误大致是说server给的不是正确的http response.这个错误是可能是由于:使用同一个HttpClient长连接/保持连接, 然后又使用这个httpClient进行其他网络请求。

如果使用的是HttpGet进行的请求(其他请求类似解决)。那么解决方法是:

//  帐前卒的code
HttpGet get = new HttpGet(urlWithParam);
HttpResponse response;
        try {
            response = httpclient.execute(get);
           // read response entity
           // do something!!!

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            get.abort();
            if (response != null) {
                 EntityUtils.consumeQuietly(response.getEntity());
            }
        }

在abort()之前要把所有的内容都获取到。然后强制关闭这个连接。同时把entity也干掉。这里解决问题的关键是get.abort()。如果entity不关掉,那么引发的问题是:httpclient卡死。 详情猛击这里

当然还有一种解决方法:不断new出httpclient. 这种方法不推荐(消耗大量资源)。

调用 OpenAPI 发送带有图片的微博。该openAPI接口为: https://open.t.qq.com/api/t/add (Oauth2.0专用)

然后收到如下错误:

"errcode":2,"msg":"error content len","ret":1,"seqid":5884029410824328274  

这个错误信息是说微博内容长度太长。我开始以为是字数的问题,然后只发送两个ascii字符,但是结果仍然会有这个问题。然后细细研究了腾讯微博的SDK.发现它发送multipart/form-data请求时, 头部信息没有带上charset=“utf-8”.然后就成功了。所以解决方法就是去掉Multipart 头部的charset=UTF-8。

Content-Type: multipart/form-data; boundary=---------------------------7d83e2d7a141e; charset=UTF-8 // 这里的charset=UTF-8要去掉才可以。
-----------------------------7d83e2d7a141e
Content-Disposition: form-data; name="content";charset=UTF-8

这个问题出现的相当tricky. 所以已经把这个问题反馈给腾讯微博的技术人员了。

如果不知道MultipartResolver 或者ServletFileUpload 的,请 JAVA Server上传文件 Spring MultipartResolver 或者 ServletFileUpload

如果同时使用了MultipartResolver和ServletFileUpload,就会在iter.hasNext()返回false.然后整个循环就跳出去了。

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
if (isMultipart) {
DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 1024 * 20, null);
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
upload.setSizeMax(1024 * 1024 * 20);

List<FileItem> fileItems = upload.parseRequest(req);
Iterator<FileItem> iter = fileItems.iterator();
// 这里获取不到任何FileItem
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString("UTF-8");
request.put(name, value);
} else {
byte[] filebytes = item.get();
if (StringUtils.isBlank(item.getName())) {
continue;
}

request.put(item.getFieldName(), new String(filebyte, "utf-8"));
}
}
}
}

整个问题产生的原因是Spring框架先调用了MultipartResolver 来处理http multi-part的请求。这里http multipart的请求已经消耗掉。后面又交给ServletFileUpload ,那么ServletFileUpload 就获取不到相应的multi-part请求。

如果帐前 卒想快速解决这个问题。解决方法是加入帐前卒的 multipartResolver, 来单独处理某些请求。这些请求需要特判。例如下面的代码:

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
package example;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.multipart.commons.CommonsMultipartResolver;

/**
* @author 帐前卒
*/
public class MyMultipartResolver extends CommonsMultipartResolver {
private String excludeUrls;
private String[] excludeUrlArray;

public String getExcludeUrls() {
return excludeUrls;
}
public void setExcludeUrls(String excludeUrls) {
this.excludeUrls = excludeUrls;
this.excludeUrlArray = excludeUrls.split(",");
}
/**
* 这里是处理Multipart http的方法。如果这个返回值为true,那么Multipart http body就会MyMultipartResolver 消耗掉.如果这里返回false
* 那么就会交给后面的自己写的处理函数处理例如刚才ServletFileUpload 所在的函数
* @see org.springframework.web.multipart.commons.CommonsMultipartResolver#isMultipart(javax.servlet.http.HttpServletRequest)
*/
@Override
public boolean isMultipart(HttpServletRequest request) {
for (String url: excludeUrlArray) {
// 这里可以自己换判断
if (request.getRequestURI().contains(url)) {
return false;
}
}

return super.isMultipart(request);
}

}

然后在web.xml中这样写:

1
2
3
4
<bean id="multipartResolver" class="example.MyMultipartResolver">
<property name="excludeUrls" value="example"/>
<!-- url中带有example的http请求就不会被multipartResolver先解析-->
</bean>

今天好好学习了一下java中的各种reference.一共分为以下几种:

1. 强引用
2. 软引用 SoftReference
3. 弱引用 WeakReference
4. 虚引用 PhantomReference
5. FinalReference 所有实现finalize()方法的对象

一下是Oracle JDK. IBM的JDK会有些不同。

** 强引用 ** :
String a = new String(“A”);

一般程序都在使用。申请太多时,会有OutOfMemory异常。gc不会自动释放。

** 软引用 ** :
SoftReference a = new SoftReference(new String(“A”));
String real = a.get(); // if memory is near/equal to threshold of memory, real may be null.

gc自动释放。不会有OutOfMemory异常,但是在垃圾回收之前/finalize()之前就会放入到引用队列 ReferenceQueue. 适合作为cache.

** 弱引用 ** :
WeakReference a = new WeakReference(new String(“A”));
String real = a.get(); // may null

gc自动释放。不会有OutOfMemory异常,但是在垃圾回收之前/finalize()之前就会放入到引用队列 ReferenceQueue. 适合作为Cache, 并且这里的意思为:如果能在内存中看到这个cache对象最好,看不到,load这个对象也不会损失很多效率。

** 虚引用 ** :
PhantomReference a = new PhantomReference(new String(“A”));
String real = a.get(); // is always null

gc不会自动释放, 会有OutOfMemory。对象在垃圾回收/finalize()之后才会放入到ReferenceQueue中。这里会保证对象不会再次引用。也可以用于判断该对象是否已经从内存中移除。

** FinalReference ** :
其实不能直接使用。这个的子类 Finalizer也不能直接使用。系统会在运行时启动FinalizerThread。这个Thread用于清理ReferenceQueue中的对象。首先调用该对象finalize()方法,然后将引用赋值为null. 这样就解除了引用和对象的关系。这里的ReferenceQueue可以看做是以上各个引用都被最终放入到的queue对象。因为所有对象都有finalize()方法。 另外垃圾回收有两步,第一步确定垃圾回收的对象,第二步调用finalize()方法,将对象从内存中移除。在finalize()方法调用前,强引用是可以召回对象,使对象不会移除内存。这样会导致垃圾回收会反反复复回收多次,仍未能将该对象移除。但是如果使用虚引用,就能确保,进入ReferenceQueue中的引用,其对象一定已经移除内存。

参考:
http://www.ibm.com/developerworks/cn/java/j-lo-langref/
https://weblogs.java.net/blog/2006/05/04/understanding-weak-references
http://yangguangfu.iteye.com/blog/849317

如果想上传文件,那么有两种方法可以解决。一种使用Spring框架中的东西。另外一种是使用原生的代码。

使用Spring框架非常简单。将如下xml放入到servlet.xml中。

1
2
3
4
5
6
7

<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize"
value="20000000" />
<!-- 上传限制 20M -->
</bean>

然后在代码中这样写:

1
2
3
4
5
6
7
8
9
10
11

@RequestMapping(value = "upload", method = RequestMethod.POST)
public void upload(HttpServletRequest req, HttpServletResponse response,
@RequestParam(value="file", required=true) MultipartFile file,
)
throws IOException {
// 1. upload file, 获取bytes内容

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
IOUtils.copy(file.getInputStream(), bytes);
byte[] byteArray = bytes.toByteArray();}

Html上传页面这样写:

1
2
3
4
5
6
7
8

<form name="uploadForm" action="upload" method="POST" enctype="multipart/form-data" >

<label>上传文件 </label><br/>
<input type="file" name="file" size="100" style="width:300px;" /> <br />

<input type="submit" name="submit" value="submit"/>
</form>

这样写完后,就可以上传一个不超过20M的文件了。

第二种方式不使用Spring框架。代码稍微复杂一些。HTML同上。但是没有那段XML内容。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
26
27
28
29
30
31
32

@RequestMapping(value = "upload", method = RequestMethod.POST)
public void upload(HttpServletRequest req, HttpServletResponse resp
) throws ServletException, IOException, FileUploadException,
{
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
HashMap<String, String> request = new HashMap<String, String>();
if (isMultipart) {
DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 1024 * 20, null);
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
upload.setSizeMax(1024 * 1024 * 20);

List<FileItem> fileItems = upload.parseRequest(req);
Iterator<FileItem> iter = fileItems.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString("UTF-8");
request.put(name, value);
} else {
byte[] filebytes = item.get();
if (StringUtils.isBlank(item.getName())) {
continue;
}

request.put(item.getFieldName(), new String(filebyte, "utf-8"));
}
}
}
}

但是这两者不能同时使用,否则会有冲突。下一篇将介绍 如何解决两者之间的冲突

    做影评前,先做下功课:圣诞玫瑰(Christmas Rose) 是1月21日和1月25日的生日花,也是一种草药。别名秋红、圣诞红。花语为‘犹豫’。
圣诞玫瑰的图片
    个人评论:这个花和普通的玫瑰看起来没有什么区别,可能是粉色的.所以情人节那天还是只能送大红色的玫瑰
    这部影片延续了郭富城近几年的风格:压抑的侦探式剧情,虽然他在该剧中饰演律师。在这部影片一直在讲故事,中间有能预料到的转折。所以我个人认为导演怕各位观众智商低看不懂,所以各个转折之前都有铺垫。这样故事转折不是那么突兀,但是丧失意外的悬疑影片讲述的一个很压抑的故事。这样的感觉好像是妈妈对小朋友讲故事,而结局就是皆大欢喜。当然对于没有听过故事的小朋友,估计是引人入胜。而听过一遍的,基本上不想再听第二遍。故事本身的叙事还是不错,一个半小时也没有觉得多长。转折起伏不多,基本上也不费脑细胞,没有大场面,没有意外的结局。
    从整个表面上把这个影片分析完了。再来看看导演究竟想说什么主题。我和LP的分歧在于该影片在宣扬人间公义,定义律师心中的准则;还是关爱他人,给他们希望和机会;还是其实影片啥也没有说,只是讲述社会的缩影。公义这个词在这个影片中多次出现,另外还有一副不知名的油画(导演杨采妮说那叫众生相),混沌并且表情不一。在混沌中,公义或者说正义是什么?无论如何帮助弱者,因为弱者已经很弱;还是维护所谓的事实公正?这真是两难的抉择。让我想到无责撞人的司机,还有搀扶非自己撞倒的老太,这两者都要赔偿一定的损失。所谓两难,从关系人两面分析,就能知道大概。给机会和希望这个主题应该是最后一点时间郭富城所说的那几句话引发的。“假如人人都充满爱”,就没有这样的悲剧发生了。但可惜的是,就是因为当事者都太有爱了,所以才有这件事。另外一个观点:社会缩影。这个倒是有点意思,因为该影片反映的太多的是是非非。律师不是侦探。如果心有公正,就不会说星期天一根本就没有罪。而有公正之心的早就推辞不接活了。所以总结为:
不念父母情,小三想上位,
世俗偏弱势,舆论贬强人,
做人心不悔,是非谁人罪。
    影片好坏自在人心。都是在讲故事,最主要是要抓住人心,留一丝牵挂之想。或喜悦,或兴奋,或压抑,或悲伤,千言万语总汇成心底的回忆。

这个部影片插叙+倒叙+正常叙…让我想起《时间碎片》这部影片。不过看完杀生,最后记住的不过是这样两句话:

1. 哀莫大于心死

2. 死即是生

0%