记得刚做javaweb开发的时候被这个编码问题搞得晕头转向,经常稀里糊涂的编码正常了一会编码又乱了。那个时候迫于项目进度大多都是知其然不知其所以然。后来有时间就把整个体系搞了个遍,终于摸通了来龙去脉。

在C++的CGI开发时大家喜欢用latin,这个属于字节方式的编码格式,存储mysql节约空间,而C++也是比较容易控制到byte级别的语言。所以经过框架封装基本也问题不大。

在Java语言中,要涉及修改编码问题的地方还真多。一个地方没有设好就会乱码满天飞。大概总结包括以下这几部分:浏览器、服务器、数据库、操作系统。

浏览器:
如果使用模板语言,html需要设置显示的字符集。这个适用于浏览器判断什么编码显示。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

扩展,浏览器识别编码的顺序:
1.如果HTTP头部申明了charset,则会使用HTTP头部的,
2.让HTTP头部没有设置,则会去解析meta标签的,
3.如果meta也没有的话,浏览器会根据是否设置了auto detect来进行编码识别,
4.否则会使用本地UI的字符编码。

服务器:
对于JSP等动态语言,需要在jsp头部设置编码格式,J2EE服务器解析这个JSP的时候才会把整个页面编码为UTF-8输出,不然就按照系统默认编码格式ISO-8859-1输出了。JSP设置格式如下:

<%@ page language= "java" contentType = "text/html; charset=UTF-8"
      pageEncoding ="UTF-8" %>

大家都知道,JSP对应的就是servlet。servlet的编码对应如下设置:

public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException{
response.setContentType("text/html;charset=utf-8");
}

还有不要漏掉大家常用的spring工具类,编码转换filter,很实用。在你用struts、spring mvc时这个过滤器帮你转换没有设置的编码过滤。如下设置:

       <filter>
             <filter-name> Set Character Encoding</filter-name>
             <filter-class>
                  org.springframework.web.filter.CharacterEncodingFilter
             </filter-class>
             <init-param>
                   <param-name> encoding</param-name>
                   <param-value> UTF-8</param-value>
             </init-param>
       </filter>

万一还有乱码怎么办呢?doGet方式的参数传递肯定会有乱码问题。只需要在tomcat的监听器里设置编码字符集如下(文件一般存储在 /tomcat安装目录/conf/server.xml ):

<Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="utf-8"   />

大家在开发的时候别忘了java文件本身也是有编码格式的。在类文件右键查看属性。
eclipse属性

 

 

如果开发时忘记更改文件的编码格式,windows默认是GBK的,后来又要一直到utf8编码的linux怎么办。文件巨多,总不能一个一个去更改吧。其实很简单,只需要在java命令的环境参数设置 -Dfile.encoding=GBK 解决。

编译java代码时,如果使用ant需要在javac里设置编译的字符集。这样打印的log输出到文件或者控制台上就不会乱码了。

<javac debuglevel= "source,lines" source= "1.6"   encoding= "utf-8">

maven编译时设置的字符集:

 < artifactId> maven-compiler-plugin </artifactId >
       < version> 2.5 </version >
                       
         < configuration>
           < optimize> true </optimize >
           < showDeprecation> false </showDeprecation >
           < debuglevel> lines,source </debuglevel >
            < source> 1.6 </source >
            < target> 1.6 </target >
            < encoding> UTF-8 </encoding >
            < meminitial> 128m </meminitial >  
             < maxmem> 768m </maxmem >
                       
         </ configuration>

sqlmap的sql xml,sping的xml 也是需要设置的,因为涉及到跨平台。 顶上添加:

<!--?xml version="1.0" encoding="UTF-8"?-->

数据库:
这里列出大家用的最多的Mysql字符集设置。打开mysql的配置文件( linux 一般在 /etc/my.cnf ,windows在mysql的安装目录 my.ini)。设置如下:

[mysqld]
default-character-set = utf8

[ mysql]
character_set_server = utf8

jdbc需要设置
jdbc : mysql://192.168.0.237:3306/dzh_db?useUnicode=true&characterEncoding=UTF-8

这些都设置了一般的中文是不会有问题的。

不过最近出现了一个问题很搞怪。以前以为所有的字符只要设置好了所有数据都可以录入数据库,结果有些字符就不行,比如●■★这类型的。后来把这些字符变成字节码,居然不是三位utf8的,我擦,大汗淋漓。后来查询可以通过过滤utf8 特殊字符的方式处理。

public static String Utf2String (byte buf[]) {
int len = buf.length ;
StringBuffer sb = new StringBuffer(len / 2);
for (int i = 0; i &lt; len; i++) {

if (by2int(buf[i]) &lt;= 0x7F)
sb.append(( char ) buf[i]);
else if (by2int(buf[i]) &lt;= 0xDF &amp;&amp; by2int(buf[i]) &gt;= 0xC0) {
int bh = by2int(buf[i] &amp; 0x1F);
int bl = by2int(buf[++i] &amp; 0x3F);

bl = by2int(bh &lt;&lt; 6 | bl); bh = by2int(bh &gt;&gt; 2);
int c = bh &lt;&lt; 8 | bl;
sb.append(( char ) c);
} else if (by2int(buf[i]) &lt;= 0xEF &amp;&amp; by2int(buf[i]) &gt;= 0xE0) {
int bh = by2int(buf[i] &amp; 0x0F);
int bl = by2int(buf[++i] &amp; 0x3F);
int bll = by2int(buf[++i] &amp; 0x3F);

bh = by2int(bh &lt;&lt; 4 | bl &gt;&gt; 2);
bl = by2int(bl &lt;&lt; 6 | bll);

int c = bh &lt;&lt; 8 | bl;
// 空格转换为半角
if (c == 58865) {
c = 32;
}
sb.append(( char ) c);

}
}
return sb.toString();
}

或者把mysql的字符集改为 utf8mb4 ,记得这个只有mysql55支持哦!

[mysqld]
default-character-set =utf8mb4

[ mysql]
character_set_server = utf8mb4

操作系统:
windows默认是gbk,一般不需要变动。不过大家又想每个文件都要建立为utf8格式怎么办,不可能我们每个文件建立后都去用属性改变一下?太麻烦!直接在eclipse设置后,同种类型的文件建立都会是utf8格式。

eclipse属性2

 

linux,可以有两个地方修改基本就足够了:
vi /etc/sysconfig/i18n
修改

LANG="zh_CN.GB3212"
LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
SUPPORTED="zh_CN.GB18030:zh_CN:zh:en_US.UTF-8:en_US:en"

vi /etc/profile

export LC_ALL="zh_CN.GB2312"
export LANG="zh_CN.GB2312"

原创文章,转载请注明: 转载自LANCEYAN.COM

本文链接地址: 谈谈WEB开发中的苦大难字符集问题

前端

    css架构
    js架构
    js例子开发
    css规范
    js规范
    交互设计

java

    java开发规范
    jeeframework框架
    eclpse工具使用
    dal访问层
    cache层 memcached等
    quartz封装
    eclipse rcp开发
    web服务器 tomcat jetty
    jvm 参数调整 jconsole
    rss封装
    日志系统
    线程池
    socket网络

python

云计算
hadoop
hdfs
hbase

爬虫

搜索引擎

    分词
    lucene
    solr
    语义
    分布式搜索

windows

    vc
    vb

linux

    nfs服务
    sftp
    shell脚本
    nginx
    apache
    squid、vanish、haproxy、keepalived

监控

    catic
    nagios
    zabbix
    tanglia

算法

    simhash
    paxos

数据挖掘 可视化

推荐引擎

架构 其他架构

    资源调度
    配置中心
    消息中心

图像识别

虚拟机

企业管理

项目管理

敏捷

浏览器内核

持续集成 ant、ivy、maven

存储 硬件

数据库 mysql mongodb oracle

代码仓库 svn、git

seo

移动 andriod ios

原创文章,转载请注明: 转载自LANCEYAN.COM

本文链接地址: 整理了一个目录,督促自己写博客

不管是什么程序开发都可能会出现各种各样的异常。可能是程序错误,也可能是业务逻辑错误。针对这个各个开发人员都有自己的处理方式,不同的风格增加了业务系统的复杂度和维护难度。所以定义好一个统一的异常处理框架还是需要的。我们开发框架采用java实现,java中的异常一般分为两种,检查异常和运行时异常。检查异常(checked exception)有可能是程序的业务异常,这种异常一般都是开发人员自定义的、知道什么时候会抛出什么异常并进行捕捉处理。也可以是系统的异常,不捕捉编译不会通过,如  IOException、SQLException、ClassNotFoundException , 这种是必须要捕捉的并且大多都是继承Exception。 运行时异常一般都是系统抛出来的异常,这种异常不捕捉处理也不会报编译错误,如NullPointerException,ClassCastException。运行异常都是继承至RuntimeException。不管是检查异常还是运行时异常都是继承至Exception。另外还有一种异常是系统错误Error,这种异常是系统出现了故障抛出来的不能捕捉,如OutOfMemoryError。Exception和Error都是继承至Throwable。

了解了java的异常体系后,我们设计一下web框架的异常处理格式。在以往EJB时代的J2ee系统,一般是标准的三层架构:web层、业务逻辑层、数据访问层,并且每一层都分别部署在不同的机器集群中。这样我们的异常一般分为三个,WebException、BizException、DAOException分别映射到web层、业务逻辑层、数据访问层。并且这些异常都要设计的串行化可以跨机器传递生成异常链。这样的好处是看到异常链知道从哪儿抛出来的错误,比较清晰明了。

老异常链

随着后面spring的推出,java的开发越来越轻量级很多时候一台服务器可以同时部署三层并集群化,架构模式也慢慢由充血模式演变为贫血模式,再也没有了厚重的实体Bean和有状态会话Bean。针对现在轻量级的框架,异常结构如何设计呢?

先看看我们这个异常结构需要解决的问题是什么?

  1. 规范大家的异常处理方式。
  2. 简化异常处理。
  3. 区分业务异常和系统异常,业务异常需要业务逻辑支持,系统异常需要记录log。
  4. 友好的异常展示。
  5. 异常结构可扩展。

针对这些点,我的想法是开发可以使用三个类:SDKException、BizException、BizSystemException。SDKException是处理的基础类,可以在里面封装一些异常处理的基本函数。BizException是业务逻辑处理异常,一般这类异常是不需要记录log,只是展示给页面显示并提示给用户。如你的用户名、密码为空等错误。BizSystemException是业务系统异常,这类异常一般需要捕捉并记录log,比如数据库的主键冲突、sql语句错误等。按照三层架构的话,我们不可能对每一层都捕捉并且记录log,会造成重复log。可以从DAO层把捕捉到的数据库异常转换为BizSystemException抛出,如果有BizException也抛出。业务逻辑层对于BizSystemException、BizException不处理直接抛出。所有处理都在web层进行集中处理,如果是BizException,根据错误码和错误消息显示给用户对应的页面和错误消息。如果是BizSystemException告知用户系统错误,并把错误结果记入log。如果是其他异常和BizSystemException一致。这样就减少了异常处理的复杂度,开发也不用关心什么检查异常,运行时异常。

新错误结构

如果是ajax请求在做web层时,把返回的jsp变成json格式或者流格式输出即可,不影响异常框架。如采用struts2结构的代码:

public String testAjax()
{
    try
    {
         genAjaxDataStr(0, "{}");
    } catch (BizException e)
    {
         getRequest().setAttribute(this.ERRORMESSAGE, e.getErrorMessage());
         return this.ERRORJSON;
    } catch (BizSystemException e)
    {
         getRequest().setAttribute(this.ERRORMESSAGE, this.SYSTEMERROR);
         return this.ERRORJSON;
    } catch (Exception e)
    {
         this.errorTrace("test", e.getMessage(), e);
         getRequest().setAttribute(this.ERRORMESSAGE, this.SYSTEMERROR);
         return this.ERRORJSON;
    }
    return this.NONE;
}

这样前台就能根据我们的异常显示对应的错误页面了,并能把系统知道的和未知的异常记入log。

针对struts2还有个问题,在开发模式时,struts2和webwork的异常打印在页面,我们可以根据页面输出进行调试。一但部署在生产环境,需要将这个模式关闭,log就没有了。

<constant name="struts.devMode" value="false" />

为了记录一些未知的错误,需要做以下步骤:

  1. 将全局的异常映射页面从struts2的包定义里去掉。如果不去掉,在webwork不会抛出异常也就找不到出了什么问题。
  2. 扩展struts的DispatcherFilter捕捉未知的异常并记录入log。
<global-exception-mappings>
    <exception-mapping exception="com.linktong.sdk.biz.exception.BizException"
                result="checkedException" />
</global-exception-mappings>

这样,基本的异常框架就搭建完成。更进一步需要做的是:

  1. 分布式全局错误码体系,保证所有机器都共用一套错误码。
  2. 分布式部署,异常传递。可以采用hessian序列化错误码的机制,不用传输整个异常链节省带宽。
  3. 集中logger服务处理,所有机器的log统一发送到集中服务器处理。logger框架和log4j也有服务器的机制。

针对web框架、分布式部署、log服务器再讨论:)

原创文章,转载请注明: 转载自LANCEYAN.COM

本文链接地址: WEB框架的错误体系