*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}

h3 {
font-size: 18px;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

ZKUI中文编码

问题

上周有同事反馈,通过ZKUI这个工具去上传带有中文的节点值时会出现中文无法显示的问题。最终发现编码是NCR编码,全称是:Numeric Character Reference。

什么是NCR?

这里引入一段维基百科的描述。
A numeric character reference (NCR) is a common markup construct used in SGML and SGML-derived markup languages such as HTML and XML. It consists of a short sequence of characters that, in turn, represents a single character. Since WebSgml, XML and HTML 4, the code points of the Universal Character Set (UCS) of Unicode are used. NCRs are typically used in order to represent characters that are not directly encodable in a particular document (for example, because they are international characters that don't fit in the 8-bit character set being used, or because they have special syntactic meaning in the language). When the document is interpreted by a markup-aware reader, each NCR is treated as if it were the character it represents.

确认是否是ZKUI的问题

由于zookeeper本身是可以存储中文的(引用一段zookeeper网站上的介绍),所以基本确认是ZKUI工具本身的问题。
The ZooKeeper Data Model
ZooKeeper has a hierarchal name space, much like a distributed file system. The only difference is that each node in the namespace can have data associated with it as well as children. It is like having a file system that allows a file to also be a directory. Paths to nodes are always expressed as canonical, absolute, slash-separated paths; there are no relative reference. Any unicode character can be used in a path subject to the following constraints:

  • The null character (\u0000) cannot be part of a path name. (This causes problems with the C binding.)
  • The following characters can't be used because they don't display well, or render in confusing ways: \u0001 - \u0019 and \u007F - \u009F.
  • The following characters are not allowed: \ud800 -uF8FFF, \uFFF0-uFFFF, \uXFFFE - \uXFFFF (where X is a digit 1 - E), \uF0000 - \uFFFFF.
  • The "." character can be used as part of another name, but "." and ".." cannot alone be used to indicate a node along a path, because ZooKeeper doesn't use relative paths. The following would be invalid: "/a/b/./c" or "/a/b/../c".
  • The token "zookeeper" is reserved.

ZKUI是基于什么实现的?

ZKUI个JAVA开源工具,可以下载源码。发现网页功能是基于HttpServlet实现的,没有使用其它一些高级的产品,比如Spring MVC等。知道是使用HttpServlet后,就会去对比Spring MVC对于中文的处理,然后就很容易去解决中文被NCR编码的问题。

这个项目结构是不是很像Spring MVC?

解决HttpServlet请求的中文编码

这里可以增加一个filter为请求对象以及响应对象增加UTF-8的处理。通过这步,ZKUI上提供的单节点的CRUD就可以正常处理中文节点值了。

@WebFilter(filterName = "filtercharset", urlPatterns = "/*")
public class CharsetFilter implements Filter { @Override
public void init(FilterConfig fc) throws ServletException {
//Do Nothing
} @Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res; request.setCharacterEncoding(StandardCharsets.UTF_8.toString());
response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); fc.doFilter(req, res);
} @Override
public void destroy() {
//Do nothing
} }

解决上传文件的中文编码

上面只是解决了页面GET,POST解决单节点的CRUD过程中的编码问题,对于文件上传还需要特殊处理。看这段源码,细节我删除了,只留下主体结构以及编码部分的代码:

public class Import extends HttpServlet {

    private final static Logger logger = LoggerFactory.getLogger(Import.class);

    @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
logger.debug("Importing Action!");
try { Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
if (item.getFieldName().equals("scmOverwrite")) {
scmOverwrite = item.getString();
}
if (item.getFieldName().equals("scmServer")) {
scmServer = item.getString();
}
if (item.getFieldName().equals("scmFilePath")) {
scmFilePath = item.getString();
}
if (item.getFieldName().equals("scmFileRevision")) {
scmFileRevision = item.getString();
} } else {
uploadFileName = item.getName();
//原来的逻辑是item.getString(),我增加了指定编码
sbFile.append(item.getString(StandardCharsets.UTF_8.toString()));
}
} List<String> importFile = new ArrayList<>();
//获取节点的值...... ZooKeeperUtil.INSTANCE.importData(importFile, Boolean.valueOf(scmOverwrite), ServletUtil.INSTANCE.getZookeeper(request,
//处理其它一些内容
request.getSession().setAttribute("flashMsg", "Import Completed!");
response.sendRedirect("/home");
} catch (FileUploadException | IOException | InterruptedException | KeeperException ex) {
logger.error(Arrays.toString(ex.getStackTrace()));
ServletUtil.INSTANCE.renderError(request, response, ex.getMessage());
}
}
}

上传的文件格式也有一定的要求:

  • 要求为无BOM的UTF-8,如果是有BOM,在处理时需要将前面的魔术数手工删除,或者是修改这个正则表达式:
  else if (!inputLine.matches("/.+=.+=.*")) {
throw new IOException("Invalid format at line " + lineCnt + ": " + inputLine);
}
  • 如果文件格式不是UTF-8的,那么会出现乱码内容。

ZKUI发布为docker

将编译好的java包,config.cfg以及项目中的Dockfile文件上传到linux服务器中。

这里简单介绍下Dockerfile

FROM java:8

MAINTAINER jim <jiangmin168168@hotmail.com>

WORKDIR /var/app

ADD zkui-*.jar /var/app/zkui.jar
ADD config.cfg /var/app/config.cfg ENTRYPOINT [ "java", "-jar", "/var/app/zkui.jar" ] EXPOSE 9090
  • FROM,这是依赖的一些环境,比如java8,ubuntu,redis等
  • MAINTAINER,这是维护人员的信息
  • WORKDIR,这里指定工作目录,进入docker后,会直接进入这个目录,root@zkui-host:/var/app#
  • ADD,复制文件到容器
  • ENTRYPOINT,容器启动后自动执行的命令,这里直接运行我们的java包
  • EXPOSE,这是主机连接容器的容器端口,实际启动容器时,可以指定-p来配置主机与容器端口的映射

制作image

docker build -t jiangmin168168/zkui .

上面的jiangmin168168是在docker网站上的ID,可以将image上传到网站上去,如果只是本地用可以不用加这个ID。当然即使加了ID,只通过build也不能实现上传功能,还需要登录docker,通过push命令去实现。

docker build非常慢

由于官方的docker网站在国内非常慢,我基本没有成功过,期待良久最后无情的显示超时。最后经过同事的介绍使用了国内的DaoCloud提供的docker加速器,就是docker的一个镜像,这样大部分原本需要从docker.io下载的内容转到国内的镜像了,速度火箭上升。

查看制作的image

docker images

发现这个image还很大,估计是自动引入java8的原因,后面可以研究下自带jdk来看看能否减少空间。

启动容器

docker run -dit --name zkui  --hostname  zkui-host  -v /data:/data -p 9090:9090 zkui:latest

简单说明下这些参数

  • -dit,以后台模式运行,后面的it详细作用可以去查文档
  • --name,是容器的名称
  • --hostname,是登录进容器后显示的名称
  • -v,指定主机与容器的目录映射,方便于容器访问主机的目录
  • -p,是指定主机与容器的端口映射,容器中的端口是固定的,主机的端口是动态配置,这样就可以部署多个容器节点
  • zkui:latest,前面是image名称,后面是tag,如果只输入image默认的tag就是latest

遗留问题

ZKUI中的NCR是在什么地方引入的?回头还需要再查找下

ZKUI中文编码以及以docker方式运行的问题的更多相关文章

  1. Docker 以 docker 方式运行 jenkins

    https://testerhome.com/topics/5798 Docker 以 docker 方式运行 jenkins jmcn · 2016年08月26日 · 最后由 blueshark 回 ...

  2. Docker 方式运行 jenkins

    原文地址:https://testerhome.com/topics/5798 简介说明 docker 是官方推荐的一种 jenkins 启动方式. 打开 jenkins 的官网,点击进入的是: ht ...

  3. Docker 方式运行 sonarqube

    From 平台测试部同事的 ppt 感谢. 拉取镜像 docker pull postgres docker pull sonarqube 运行镜像 docker run --name db --re ...

  4. docker 方式运行drill

    drill 1.14 版本已经官方支持使用docker 直接运行可,还是比较方便的,尽管镜像 有点大,但是实际测试使用还是比较方便的,实际上自己做一个也比较简单. 下载镜像 docker pull d ...

  5. 使用Docker方式运行Mysql(MariaDB)

    两者差不多.我使用的是MariaDB. 下面的docker命令,挂了数据,配置,映射了端口,指定了root密码,服务端编码. 蛮快的! docker run \ --name mariadb \ -v ...

  6. 在 docker中 运行 mono /jexus server 并部署asp.net mvc站点

    http://linuxdot.net/bbsfile-3988 1.  安装 docker:      // docker 1.7 新版 安装非常容易,理论上说,在主流的任意linux发行版上都可以 ...

  7. 在Docker中运行torch版的neural style

    相关的代码都在Github上,请参见我的Github,https://github.com/lijingpeng/deep-learning-notes 敬请多多关注哈~~~ 在Docker中运行to ...

  8. ASP.NET Core 网站在Docker中运行

    Docker作为新一代的虚拟化方式,未来肯定会得到广泛的应用,传统虚拟机的部署方式要保证开发环境.测试环境.UAT环境.生产环境的依赖一致性,需要大量的运维人力,使用Docker我们可以实现一次部署, ...

  9. [转帖]Docker里运行Docker docker in docker(dind)

    Docker里运行Docker docker in docker(dind) http://www.wantchalk.com/c/devops/docker/2017/05/24/docker-in ...

随机推荐

  1. struts tags

    HTTP ERROR 500 Problem accessing /showognl.jsp. Reason: Server Error Caused by: org.apache.jasper.Ja ...

  2. angularjs controller 继承

    前沿 最近在angularjs项目当中,看到 controller 好多都是重复性的代码,在 controller 当中有好多代码很相似 function(比如 controller 下的 CRUD ...

  3. 2017预防bug的重要性

    Bug,中文名缺陷.一个让软件测试员兴奋,让开发人员头疼的词.来源二次大战期间,一个称为"马克二型"的计算机,由于天气过热,硬件跟不上导致死机.最后发现是因为飞蛾,被继电器电死,将 ...

  4. SQL Server 创建数据库邮件

    一. 背景 数据库发邮件通知数据库的运行状态(状态可以通过JOB形式获取)和信息,达到预警的效果. 二. 基础知识 msdb系统数据库保存有关Job,Database Mail,Nodifyicati ...

  5. ClickOnce部署(4):下载多个安装包

    有时候,我们可能会一次性发布多个安装包,当然在网页上多加几个链接让用户逐个安装也是可取的.不过,也可以弄得更方便些,即用户先安装一个,作为一个"引导程序",然后通过这个程序去下载安 ...

  6. 推荐21款最佳 HTML5 网页游戏

    尽管 HTML5 的完全实现还有很长的路要走,但 HTML5 正在改变 Web,未来 HTML5 将把 Web 带入一个更加成熟和开放的应用平台.现在,越来越多的人尝试用 HTML5 来制作网页游戏等 ...

  7. 简单java在线测评程序

    简单java程序在线测评程序 一.前言 大家过年好!今年的第一篇博客啊!家里没有网,到处蹭无线!日子过得真纠结!因为毕设的需求,简单写了一个java程序在线测评程序,当然也可以在本地测试. 二.思路 ...

  8. php面向对象基础

    1.类 由众多对象抽象出来的 它包含了对象通用的特性 2.对象 一切皆对象 它是由实例化出来的 例: 求两个圆之间阴影的面积 <!DOCTYPE html PUBLIC "-//W3C ...

  9. 应用程序框架实战十七:DDD分层架构之值对象(层超类型篇)

    上一篇介绍了值对象的基本概念,得到了一些朋友的支持,另外也有一些朋友提出了不同意见.这其实是很自然的事情,设计本来就充满了各种可能性,没有绝对正确的做法,只有更好的实践.但是设计与实践的好与坏,对于不 ...

  10. 应用程序框架实战十一:创建VS解决方案与程序集

    上一篇,介绍了开发环境需要的工具和版本,本篇将动手创建VS解决方案. 对于本系列文章提供的示例,我想通过两种途径来演示,一种是单元测试,另外为了能更直观的看到效果,还会提供一个用户界面来展示.为了不分 ...