传智播客培训的第1天1. 这是同学的一个问题
他用javac(1.4)编译,用java(1.6)运行,出现不支持的类版本错误。我们用javac -version和java -version各看了一下版本,就发现了这个问题。然后查看path环境变量,发现他计算机上安装了oracle,oracle/bin排在了整个path的前面,调整path,让jdk1.6/bin排在最前面即可。
2. 由内存中一切皆二进制引出字符编码的讲解
大陆写的“中”到台湾显示不正常的原理分析,翻译软件的翻译原理,GBK-->“中”-->BIG5。讲解UTF-8编码和unicode编码,ASCII与Unicode码的转换规则,演示记事本显示字符时的趣味问题,分析乱码原因,GB2312码中也包含英文字符,如何识别GB2312码中的英文与汉字。最后课结束时讲了GB18030,如何支持?
3. xml文档中设置encoding属性的重要性
xml文档保存的编码类型和encoding指定的编码方式是两码事,前者表示xml文档内容的编码方式而后者是告诉解析器以什么编码方式来解析xml文档。二者必须一致,否则在浏览器中打开xml文档就会出现问题。默认情况下encoding属性的值是UTF-8。
沈继龙:以为指定了encoding="GBK",那文件就用GBK保存了,这正好理解反了。我是张,我戴顶帽子说明我是张,以便解析软件知道我是谁,如果我戴顶李的帽子,解析软件就认为我是李,显然就出了问题。
4. CDATA区
要小心的是XML文档是通过一个程序生成出来的,如下所示的一个jsp程序,对于用变量生成的信息,
要特别注意加上CDATA区。
<%@page pageEncoding="GBK"%>
<%@page contentType="text/xml;charset=UTF-8"%>
<?xml version="1.0" encoding="UTF-8"?>
<country>
<name>中国</name>
<info><![CDATA[${param.info}]]></info>
</country>
这个JSP文件涉及了两个编码:源文件是用什么码写的,程序执行后以什么码输出结果。
为了加深理解处理软件必须文件中的字符编码的情况,又演示了javac编译utf-8源文件的问题。
与CDATA区类似的一个小技巧:
<%@page pageEncoding="GBK"%>
<form>
<input type="hidden" name="email" value="${param.email}"/>
请输入用户名:<input type="text" name="name" />
</form>
如果给隐藏字段传递的参数是“zxx" a="b”,那么也会出问题,对于程序生成值时,一定要考虑值的特殊情况。
5. 编码转换
编码转换程序:
char [] codes = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
byte b = (byte)Integer.parseInt(args[0]);
System.out.print(codes[((b>>4) & 0x0f)]);
System.out.println(codes[(b & 0x0f)]);
得到字符的big5码
<%@page pageEncoding="GBK"%>
<%@page contentType="text/html;charset=GBK"%>//修改contentType="audio/x-mp3"说明头的作用
<%
String china="中一二";
for(int i=0;i<china.length();i++)
{
out.println(Integer.toHexString((int)china.charAt(i)));
}
System.out.println();
byte[] bufGBK = china.getBytes("GBK");
for(int i=0;i<bufGBK.length;i++)
{
out.println(Integer.toHexString(bufGBK [i]));
}
byte[] buf = china.getBytes("Big5");
for(int i=0;i<buf.length;i++)
{
out.println(Integer.toHexString(buf[i]));
}
byte [] buf ={0xa4, 0xa4,0xa4,0x40,0xa4,0x47}
%>
输出big5码给浏览器:
<%
byte [] buf ={(byte)0xa4, (byte)0xa4,(byte)0xa4,(byte)0x40,(byte)0xa4,(byte)0x47};
response.getOutputStream().write(buf);
%>
6. 区分中文英文的程序代码
buf[] = new byte[1024];
int len = System.in.read(buf);
boolean halfChinese = false;
for(int i=0;i<len;i++)
{
if(halfChinese)
{
//buf[i-1] + buf[i]合并
System.out.write('[');
Systen.out.write(buf[i-1]);
Systen.out.write(buf[i]);
System.out.write(']');
halfChinese = false;
continue;
}
if((buf[i] & 0x80) == 0)
{
//为什么必须用write???
System.out.write('[');
Systen.out.write(buf[i]);
System.out.write(']');
}
else
{
halfChinese = true;
//等下一个,暂时不处理
/*
System.out.write('[');
Systen.out.write(buf[i++]);
Systen.out.write(buf[i]);
System.out.write(']');
*/
}
}
System.out.write();方法要用flush();刷新缓存,才能正常显示。
我写的代码,但还有地方没弄明白:为什么去掉了if()判断是否有'\r','\n'后,显示的结果不正常。
import java.io.*;
class TestInputChinese {
public static void main(String[] args) {
byte[] buf = new byte[1024];
int len = 0;
try {
len = System.in.read(buf);
}catch(IOException e) {
e.printStackTrace();
}
change(buf, len);
}
public static void change(byte[] b, int len) {
for( int i=0; i<len; i++ ) {
if(b[i] == '\r' || b[i] == '\n' ) {
continue;
}
if((b[i] & 0x80) == 0 ) {
System.out.write('[');
System.out.write(b[i]);
System.out.write(']');
} else {
System.out.write('[');
System.out.write(b[i++]);
System.out.write(b[i]);
System.out.write(']');
}
}
System.out.flush();
}
}详细查询:www.itcast.cn

解决方案 »

  1.   

                                        在传智播客培训的第2天1. 讲特殊字符
    &lt;学了自定义实体后,我们就明白了预定义实体名称的由来,为什么用&#39表示单引号。
    讲处理指令引出一个重要的思想:“内容与表现相分离”,xml文档提供内容,该怎样显示,由CSS或XSL定义。以后做网页,尽量采用div+css模式,这样可以方便地切换皮肤,不要再用<table>进行布局。
    2.接着讲解了DTD的语法细节,这是要掌握的重点内容,还给大家看了几个真实框架的DTD文档
    实体定义:
    <!ENTITY copyright SYSTEM "http://www.it315.org/copyright.xml"> 
    有SYSTEM关键字,那就表示别名对应的是xml文件的内容,否则,表示别名对应的是这个串本身。
    4. 一针见血的总结
    框架总是跟xml结合使用,通过xml文件来把门窗,屋顶装配到房屋框架上,就得到了最终的房屋。在xml文件中描述用什么样的门窗,把门窗与框架缝合起来。
    5.讲解了浏览器与Web服务器交互的过程,并做出实例
    分析了HttpServer.java的编写原理,特别是sendData方法的参数要用接口的思想。
    例:
    import java.net.*;
    import java.io.*;
    public class WebServer
    {
    public static void main(String args[])
    {
    try
    {
    ServerSocket serverSocket = new ServerSocket(8888);
    while(true)
    {
    Socket sockets = serverSocket.accept();
    new Thread(new Servers(sockets)).start();
    }
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    }
    }
    class Servers implements Runnable
    {
    Socket s = null;
    public Servers(Socket s)
    {
    this.s = s;
    }
    //覆盖Runnable接口中的run()方法
    public void run()
    {
    InputStream in = null;
    BufferedReader br = null;
    FileInputStream fis = null;
    OutputStream ops = null;
    try
    {
    in = s.getInputStream();
    br = new BufferedReader(new InputStreamReader(in));
    //读取浏览器传送来的信息的第一行,一般为GET /xx.html HTTP/1.1
    String line = br.readLine();
    //用String的split方法结合正则表达式,分割出一个String数组
    String parts[] = line.split(" +");
    //将文件名截掉第一个字符后赋值给filename
    String filename=parts[1].substring(1);
    if("".equals(filename))
    {
    filename="index.html";
    }
    System.out.println(filename);
    File f = new File("d:\\www",filename);
    fis = new FileInputStream(f);
    ops = s.getOutputStream();
    sendData(fis,ops);
    }
    catch(FileNotFoundException fn)
    {
    System.out.println("fn error!");
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    finally
    {
    try
    {
    ops.close();
    fis.close();
    br.close();
    in.close();
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    }
    }
    void sendData(FileInputStream fis,OutputStream ops) throws Exception
    {
    byte[] b = new byte[1024];
    int len =0;
    while((len=fis.read(b)) != -1)
    {
    ops.write(b,0,len);
    }
    }
    }
      

  2.   

                                          在传智播客培训的第3天1. 又遇乱码问题
    在分析conf\server.xml时,如果在里面添加中文注释,那么startup.bat启动服务器则会出现错误。是因为编码问题,如果文件中出现中文,则文件读取错误,因为xml默认是以unicode编码存的。添加声明<?xml version="1.0" enconding="GB2312"?>或文件另存为编码为UTF-8则启动正常。
    2. 怎样在telnet命令行窗口中显示本地回显
    用ctrl+”]”然后按回车,再输入命令,telnet就可以本地回显。
    3. 讲解Tomcat中的server.xml
    (1)在分析conf\server.xml时,如果在里面添加中文注释,那么startup.bat启动服务器则会出现错误.是因为编码问题,如果文件中出现中文,则文件读取错误,因为xml默认是以unicode编码存的.添加声明<?xml version="1.0" encondin="GB2312"?>或文件另存为编码为UTF-8则启动正常。
    (2)server.xml是给java执行的,所以在添盘符路径时可以不用\\来表示\,而java程序是给javac看的,编译器需要用\\来转意表示\,否则编译器会报错。
    <Host></Host>之间添加<Context path="/abc" docBase="e:abc\"/> path代表浏览器中的目录,docBase代表path的设置中对应本地磁盘的目录。
    (3)当用startup.bat启动tomcat时,如果server.xml配置有错误,那么startup.bat将闪一下就消失了,如果想让命令窗口停住,好方便查看错误信息,则用如下方法修改:修改catalina.bat,找到里面的:
    :doStart
    shift
    if not "%OS%" == "Windows_NT" goto noTitle
    set _EXECJAVA=start %_RUNJAVA%
    goto gotTitle
    :noTitle
    set _EXECJAVA=start %_RUNJAVA%
    :gotTitle
    if not ""%1"" == ""-security"" goto execCmd
    shift
    echo Using Security Manager
    set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
    goto execCmd
    将上面set _EXECJAVA=start %_RUNJAVA% 中的start去掉,就可以让命令行出错后不消失。set _EXECJAVA=start %_RUNJAVA% 的意识是重新启动一个命令行窗口。去掉start后,则不会再重新启动窗口,就达到了使命令行停住的效果。要在命令行中启动startup.bat才能看到效果。
    4. 配置虚拟子目录的三种方法
    1.使用server.xml文件中的<context>元素。
    2.在某个特定的目录中的xml文件中包含<Context>元素
    例如:Tomcat5.x中主目录/conf/cat/localhost/manager.xml中的<Context>元素
    3.<Host>元素的appBase属性所设置的应用程序基准目录中含有WEB-INF/web.xml文件的子目录会自动被映射成虚拟子目录。
    4.<Host>元素的appBase属性所设置的应用程序基准目录中的war文件,这个war文件的名称也会自动被映射成虚拟子目录。
    5. 其它知识点
    将一个WAR的压缩包放到webapps目录下时,服务器会自动解压这个压缩文件。
    Web.xml文件中
    <welcome-file-list>
            <welcome-file>a.html</welcome-file>
           </welcome-file-list>
    <welcome-file>内放如想要直接显示的页面(比如说欢迎页面),如果设置了该属性则站点下默认的网页就是a.html。
      

  3.   

                      培训第四天1. Servlet程序详细讲解
    ①Servlet的class文件必须放在WEB-INF\classes文件夹下
    ② 对每个单独的WEB程序的Servlet容器进行讲解。写了一个servlet实例
    ③ 用显示火车票剩余数量的例子引入产生动态网页内容的讲解,服务器送给浏览器的内容不一定非得是来自一个网页文件,而可以是程序动态创建出来的,Servlet就是这样一种程序。
    ④ 查看Servlet的使用帮助,在<Tomcat安装目录>\webapps\tomcat-docs\servletapi
    ⑤ 配置 web.xml文件的servlet元素,主要有servlet-name和servlet-class
    其中name可随意,指定servlet-class是WEB程序中WEB-INF\classes文件夹中的要加载的 .class 文件
    ⑥ 配置 web.xml文件的servlet-mapping元素,主要有servlet-name和url-pattern
    其中name必须与servlet的name相同,url-pattern为要映射的虚拟路径,可以是在硬盘上并不存在的文件(夹)
    ⑦  同一个servlet类可以在web.xml中映射成为多个名称不同的servlet容器
    ⑧ 讲解了Servlet程序的作用,在讲解Servlet接口中的方法时,顺便说明了ServletContext和ServletConfig是什么,接着分析如何写Servlet时带出了GenericServlet类的大概代码原理。
    伪代码:
    class xxx implements Servlet
    {
    private ServletConfig config = null;
    init(ServletConfig config)
    {
    this.config = config;
    }

    service(ServletRequest request,ServletResponse response)
    {
    config.getServletContext();
    }

    ServletConfig getServletConfig()
    {
    return config;
    }

    destroy
    {
    }

    getServletInfo()
    {
    reutrn "i am "
    }
    }
    ⑨ Java虚拟机的类装载器的加载根目录为<JAVA安装目录>\jdk1.6\jre\lib\ext
    讲了Tomcat与Java虚拟机的类加载机制,大致为当运行的代码需要装载某个类时,上下文类装载器会委托它的父级类装载器来装载这个类,如果父级类装载器无法装载这个类时,上下文装载器才自己进行装载,如果它自身仍不能装载,就会产生错误,如下图…类的加载需要正确的classpath设置
     
    2.时刻想着线程安全问题,只要是多段函数访问同一个方法,多个对象的变量引用同一个目录,都有可能会出现线程安全问题
    3.模板方法设计模式的一些思想
    架构师将类的框架设计好后,将某部分不确定代码做成一个抽象方法,然后交由其它程序员继承这个类,并实现这个抽象方法.
    Class abstract BaseServlet
    {
    service() throws IOException,ServletException
    {
    try
    {
    doService()
    }
    catch(SqlException e)
    {
    throw new IOException(e);
    }
    }
    public abstract void doSevice();
    }
    YourServlet extends BaseServlet
    {
    public doService()
    {
    ....
    }
    }
    4.class编译文件自动保存目录的方法
    使用命令  Javac –d  class文件的保存目录 XX.java
    可写个批处理文件,例 a.bat,直接将JAVA源文件托至些BAT文件即可
    javac –d d:\ %1
    pause
    5.同学的问题
    为什么加了System.out.println()后,前面用write方法写入的内容才会显示在屏幕上?
    这是因为System.out是PrintStream类,PrintStream是个带缓冲的包装类,println()会自动调用System.out.flush()方法。
    6. 写了一个获取ip地址和请求参数的Servlet例子程序,并注册运行。接着分析了Servlet的工作原理,以及Request和Response是接口的设计原理,很好地说明了“面向接口编程,而不要面向类编程”的思想。
    例:MyWebServlet.java   我自己写的
    import javax.servlet.*;
    import java.io.*;
    public class MyWebServlet extends GenericServlet
    {
    public void service(ServletRequest  req,ServletResponse  response) throws ServletException,IOException
         {
       String ip = req.getRemoteHost();
       response.getWriter().println("Your ip issss:"+ ip);
         }
    }
    7. 在上面的例子基础上进行扩展,讲解了Servlet的映射问题,接着演示了ServletContext和ServletConfig的应用,通过ServletConfig获得Servlet的注册名称和配置参数,通过ServletContext获得Web服务器程序的名称getServerInfo方法。Servlet运行于Web应用程序中,而每一个WEB应用程序对应一个Context元素,所以,就把Servlet运行的Web应用程序称之为ServletContext,这从名字上就可以知道其作用。一个虚拟目录就是一个Web应用程序,把某个目录单独挂到服务器上,这个目录就成了一个独立的Web应用程序,这个目录下的子目录不是独立的web应用程序。
    8. 接着把Servlet注册两次,每个映射给不同的url,一个是/action/*,一个是*.html,借此说明了映射的优先级问题。
    9. 接着引出了tomcat的DefaultServlet,别人都不要的请求交给它。
    关于第七和第八点的例子,张老师写的。
    import javax.servlet.*;
    import java.io.*;
    import java.util.*;
    import javax.servlet.http.*;
    public class MyServlet extends HttpServlet
    {
    /*Enumeration getInitParameterNames()
    {
    return getServletConfig().getInitParameterNames();
    }*/
    public init(ServletConfig conf)
    {
    super.init(conf);
    init();
    }
    public init()
    {
    }
    public void doGet(HttpServletRequest req,HttpServletResponse response) throws ServletException,IOException
    {
    PrintWriter out = response.getWriter();
    ServletConfig config = getServletConfig();
    Enumeration e = /*config.*/getInitParameterNames();
    while(e.hasMoreElements())
    {
    String name = (String)e.nextElement();
    String value = /*config.*/getInitParameter(name);
    out.println(name + ":" + value + "<br>");
    }
    HttpServletRequest request = (HttpServletRequest)req;
    Enumeration e2 = /*config.*/request.getHeaderNames();
    while(e2.hasMoreElements())
    {
    String name = (String)e2.nextElement();
    String value = /*config.*/request.getHeader(name);
    out.println(name + ":" + value + "<br>");
    }
    String ip = req.getRemoteAddr();
    String time = new Date().toString();
    out.println(ip + ": " + time);
    out.println(req.getParameter("userid") + ": " + req.getParameter("bookid"));
    response.getWriter().println(getServletConfig().getInitParameter("corporation"));
    response.getWriter().println(getServletConfig().getServletName());
    response.getWriter().println(this.getClass().getClassLoader().getClass().getName());
    response.getWriter().println(getServletConfig().getServletContext().getServerInfo() );
    }
    }
    10. 接着讲解了类装载器
    通过对比Student类的实例对象是各个学生,强调了Class类的实例对象是各个类字节码。
    Class clazz1 = Class.forName("Abc")
    Class clazz2 = Class.forName("Student")
    Student st = clazz2.newInstance();
    一个类装载器负责从特定的位置加载和创建类字节码,应用程序中安装有多个类装载器,应用程序会尝试依次使用各个类装载器去加载某个名称的类,这个尝试使用的规则就是委托代理机制。
    11. 要让多个应用程序都能装载某个Servlet,把Servlet放在哪里?
    应把Servlet放在<tomcat安装目录>\common\lib中,要做成jar包放在这个文件夹中.classes文件夹放置零散的class文件。
    12. 按书做了类装载器的实验,不过是把Servlet类放置到了<java安装目录>/jre/lib/ext目录中,一定要打成jar包。
    13. 讲解了Servlet程序的作用,在讲解Servlet接口中的方法时,顺便说明了ServletContext和ServletConfig是什么,接着分析如何写Servlet时带出了GenericServlet类的大概代码原理。
    14. 讲解了HttpServlet类
    HttpServlet是GenericServlet的子类,SUN公司在HttpServlet中重写了service方法,并在这个方法中调用了另一个service方法(两个service接受的参数类型不同),,所以我们只需要根据自己的需要重写service2方法即可。详细:www.itcast.cn
      

  4.   

    今天是在传智播客培训的第5天
    学习了HTTP信息头,知道了很多文件的类型是如何被服务器识别,并做出相应的反应的。
    1. HTTP消息头
    (1)通用信息头
    即能用于请求消息中,也能用于响应信息中,但与被传输的实体内容没有关系的信息头,如Data,Pragma
    主要: Cache-Control , Connection , Data , Pragma , Trailer , Transfer-Encoding , Upgrade
    (2)请求头
    用于在请求消息中向服务器传递附加信息,主要包括客户机可以接受的数据类型,压缩方法,语言,以及客户计算机上保留的Cookie信息和发出该请求的超链接源地址等.
    主要: Accept , Accept-Encoding , Accept-Language , Host , 
    (3)响应头
    用于在响应消息中向客户端传递附加信息,包括服务程序的名称,要求客户端进行认证的方式,请求的资源已移动到新地址等.
    主要: Location , Server , WWW-Authenticate(认证头)
    (4)实体头
    用做实体内容的元信息,描述了实体内容的属性,包括实体信息的类型,长度,压缩方法,最后一次修改的时间和数据的有效期等.
    主要: Content-Encoding , Content-Language , Content-Length , Content-Location , Content-Type
    (4)扩展头
    主要:Refresh, Content-Disposition
    2. 几个主要头的作用
    (1)Content-Type的作用
    该实体头的作用是让服务器告诉浏览器它发送的数据属于什么文件类型。 
    例如:当Content-Type 的值设置为text/html和text/plain时,前者会让浏览器把接收到的实体内容以HTML格式解析,后者会让浏览器以普通文本解析.
    (2)Content-Disposition 的作用
    当Content-Type 的类型为要下载的类型时 , 这个信息头会告诉浏览器这个文件的名字和类型。
    在讲解这个内容时,张老师同时讲出了解决中文文件名乱码的解决方法,平常想的是使用getBytes() , 实际上应使用email的附件名编码方法对文件名进行编码,但IE不支持这种作法(其它浏览器支持) , 使用javax.mail.internet.*包的MimeUtility.encodeWord("中文.txt")的方法进行编码。
      Content-Disposition扩展头的例子:
    <%@ page pageEncoding="GBK" contentType="text/html;charset=utf-8" import="java.util.*,java.text.*" %>
    <%=DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.CHINA).format(new Date())%>
    <%
    response.setHeader("Content-Type","video/x-msvideo");
    response.setHeader("Content-Disposition", "attachment;filename=aaa.doc");
    %>
    Content-Disposition中指定的类型是文件的扩展名,并且弹出的下载对话框中的文件类型图片是按照文件的扩展名显示的,点保存后,文件以filename的值命名,保存类型以Content中设置的为准。
    注意:在设置Content-Disposition头字段之前,一定要设置Content-Type头字段。
    (3)Authorization头的作用
    Authorization的作用是当客户端访问受口令保护时,服务器端会发送401状态码和WWW-Authenticate响应头,要求客户机使用Authorization来应答。
    例如:
    <%@ page  pageEncoding="GBK" contentType="text/html;charset=utf-8" import="java.util.*,java.text.*" %>
    <%=DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.CHINA).format(new Date())
    %>
    <%
    response.setStatus(401);
    response.setHeader("WWW-Authenticate", "Basic realm=\"Tomcat Manager Application\"");
    %>
    3.如何实现文件下载
    要实现文件下载,我们只需要设置两个特殊的相应头,它们是什么头?如果文件名带中文,该如何解决?
    两个特殊的相应头:
    ----Content-Type:       application/octet-stream 
    ----Content-Disposition:  attachment;filename=aaa.zip
    例如:
    response.setContentType("image/jpeg");response.setHeader("Content- Disposition","attachment;filename=Bluehills.jpg");
    如果文件中filename参数中有中文,则就会出现乱码。
    解决办法:
    (1)MimeUtility.encodeWord("中文.txt");//现在版本的IE还不行
    (2)new String("中文".getBytes("GB2312"),"ISO8859- 1");//实际上这个是错误的
    4. 测试并分析文件名乱码问题
    response.setHeader()下载中文文件名乱码问题
    response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
    下载的程序里有了上面一句,一般在IE6的下载提示框上将正确显示文件的名字,无论是简体中文,还是日文。不过当时确实没有仔细测试文件名为很长的中文文件名的情况。 现如今经过仔细测试,发现文字只要超过17个字,就不能下载了。分析如下:
     一. 通过原来的方式,也就是先用URLEncoder编码,当中文文字超过17个时,IE6 无法下载文件。这是IE的bug,参见微软的知识库文章 KB816868 。原因可能是IE在处理 Response Header 的时候,对header的长度限制在150字节左右。而一个汉字编码成UTF-8是9个字节,那么17个字便是153个字节,所以会报错。而且不跟后缀也不对.
    二. 解决方案:将文件名编码成ISO8859-1是有效的解决方案,代码如下:
    response.setHeader( "Content-Disposition", "attachment;filename=" + new String( fileName.getBytes("gb2312"), "ISO8859-1" ) );
    在确保附件文件名都是简 体中文字的情况下,那么这个办法确实是最有效的,不用让客户逐个的升级IE。如果台湾同胞用,把gb2312改成big5就行。但现在的系统通常都加入了 国际化的支持,普遍使用UTF-8。如果文件名中又有简体中文字,又有繁体中文,还有日文。那么乱码便产生了。另外,在上Firefox (v1.0-en)下载也是乱码。
    三. 参看邮件中的中文附件名的形式,用outlook新建一个带有中文附件的邮件,然后看这个邮件的源代码,找到:
    Content-Disposition: attachment;
    filename="=?gb2312?B?0MK9qCDOxLG+zsS1tS50eHQ=?="
    用这个filename原理上就可以显示中文名附件,但是现在IE并不支持,Firefox是支持的。尝试使用 javamail 的MimeUtility.encode()方法来编码文件名,也就是编码成 =?gb2312?B?xxxxxxxx?= 这样的形式,并从 RFC1522 中找到对应的标准支持。
     折中考虑,结合了一、二的方式,代码片断如下:
     String fileName = URLEncoder.encode(atta.getFileName(), "UTF-8");
     /*
    * see http://support.microsoft.com/default.aspx?kbid=816868
     */
     if (fileName.length() > 150) {
     String guessCharset = xxxx
    //根据request的locale 得出可能的编码,中文操作系统通常是gb2312
     fileName = new String(atta.getFileName().getBytes(guessCharset), "ISO8859-1"); 
     }
    response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
    编码转换的原理:
    首先在源程序中将编码设置成GB2312字符编码,然后将源程序按Unicode编码转换成字节码加载到内存中(java加载到内存中的字节码都是Unicode编码),然后按GB2312编码获得中文字符串的字节数组,然后生成按ISO8859-1编码形式的Unicode字符串(这时的4个字节就变成了8个字节,高位字节补零),当在网络中传输时,因为setHeader方法中的字符只能按ISO8859-1传输,所以这时候就又把Unicode字符转换成了ISO8859-1的编码传到浏览器(就是把刚才高位补的零全去掉),这时浏览器接收到的ISO8859-1码的字符因为符合GB2312编码,所以就可以显示中文了。
    5. jsp翻译成class时的编码问题
    记事本中代码块1:
    <%=
    "a中文".length()
    %>
    代码块2:
    <%@ page pageEncoding="gbk"%>
    <%=
    "a中文".length()
    %>
    为什么上面的输出值为5,改成下面的则输出3?
    因为上面的代码没有添加该文件的编码说明 , WEB应用程序在将jsp翻译成class文件时 , 把该字符串的内容按默认的保存方式指定的编码ASCII码来算的,在UTF-8中,原ASCII字符占一个字节,汉字占两个字节,对应两个字符,长度就变成了5 , 而下面的是GBK编码, 一个汉字和一个英文都对应一个字符,得到结果就为3.