字符编码与java和jsp的爱恨纠缠

部分内容参考:https://blog.csdn.net/seabiscuityj/article/details/80762658

一、最基本的记事本编译

  首先声明我使用的是汉语的windows操作系统。
  最开始学习java时,是在记事本中写的代码,然后将后缀txt强制改为java,然后在cmd中javac xxx.java和java xxx运行。下面将这一个过程细分:

  1. 通常我们手动建立一个java文件Demo.java(txt强制改后缀),并保存。此时Demo.java文件的编码为ANSI,中文操作系统下就是GBK。

在这里插入图片描述

  1. 使用javac命令来编译该源文件。”javac Demo.java”。javac也需要读取java文件,那么javac是使用什么编码解码我们的java文件呢?其实javac采用了操作系统默认的GBK编码解码我们读取的字节,这个编码正好也是Demo.java文件的编码,二者一致,所以不会出现乱码情况。

  2. 我们来做点改变,在保存Demo.java文件时,我们选择UTF-8保存。此时Demo.java文件编码就是UTF-8了。我们再使用”javac Demo.java”来编译,如果Demo.java里含有中文字符,此时控制台会出现警告信息,而且控制台的内容输出也会乱码。究其原因,就是因为javac采用了GBK编码解码我们读取的字节。因为我们的字节是UTF-8编码的,所以会出现乱码。

  3. 那么解决办法呢?解决办法就是使用javac的encoding参数来制定我们的解码编码。如下:javac -encoding UTF-8 Demo.java。这里我们指定了使用UTF-8来解码读取的字节,由于这个编码和Demo.java文件编码一致,所以不会出现乱码情况了。

  至此,已经生成了class文件,这个class文件编码就没必要研究了。因为在Java(其中主要包括在JVM中、内存中、在代码里声明的每一个char、String类型的变量中。)中字符只以一种形式存在,那就是Unicode,不选择任何特定的编码,直接使用它们在字符集中的编号,这是统一的唯一的方法,也是平台无关性的必备条件。在JVM内部,统一使用Unicode表示,当着字符从JVM内部移动到外部时(即保存为文件系统中的一个文件内容时),就进行了编码转换,使用了具体的编码方案。因此也可以说,所有的编码转换只发生在边界的地方,也就是各种输入/输出流的起作用的地方。

二、其他形式编译

  1. Eclipse中编译java文件
      我们习惯把Eclipse的编码设置成UTF-8。那么每个项目中的java源文件的编码就是UTF-8。这样编译也从没有问题,也没有出现过乱码。正是因为这样才掩盖了使用javac可能出现的乱码。那么Eclipse是如何正确编译文件编码为UTF-8的java源文件的呢?唯一的解释就是Eclipse自动识别了我们java源文件的文件编码,然后采取了正确的encoding参数来编译我们的java源文件。功劳都归功于IDE的强大了。

  2. 使用Ant来编译java文件
      Ant也是我常用的编译java文件的工具。首先,必须知道Ant在后台其实也是采用javac来编译java源文件的,那么可想而知,1会出现的问题在Ant中也会存在。如果我们使用Ant来编译UTF-8编码的java源文件,并且不指定如何编码,那么也会出现乱码的情况。所以Ant的编译命令<javac>有一个属性” encoding”允许我们指定编码,如果我们要编译源文件编码为UTF-8的java文件,那么我们的命令应该如下:<javac destdir="${classes}" target=“1.4” source=“1.4” deprecation=“off” debug=“on” debuglevel=“lines,vars,source” optimize=“off” encoding=“UTF-8”>,指定了编码也就相当于”javac –encoding”了,所以不会出现乱码了。

三、jsp的编译

jsp运行原理

  在一个JSP文件第一次被请求时,JSP引擎把该JSP文件转换成为一个Servlet。而这个引擎本身也是一个Servlet。JSP的运行过程如下所示:
(1) JSP引擎先把该JSP文件转换成一个Java源文件(Servlet),在转换时如果发现JSP文件有任何语法错误,转换过程将中断,并向服务端和客户端输出出错信息。
(2) 如果转换成功,JSP引擎用javac把该Java源文件编译成相应的class文件。
(3) 创建一个该Servlet(JSP页面的转换结果)的实例,该Servlet的Init()方法被执行,Init()方法在Servlet的生命周期中只被执行一次。
(4) Service()方法被调用来处理客户端的请求。对每一个请求,JSP引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求该JSP文件,则JSP引擎会创建多个线程。每个客户端请求对应一个线程。以多线程方式执行可以大大降低对系统的资源需求,提高系统的并发量及响应时间。但不过也应该注意多线程的编程限制,由于该Servlet始终驻于内存,所以响应是非常快的。
(5) 如果.jsp文件被修改了,服务器将根据设置决定是否对该文件重新编译,如果需要重新编译,则将编译结果取代内存中的Servlet,并继续上述处理过程。
注意:当这个jsp页面再次被请求执行时,jsp引擎将直接执行字节码文件来响应客户。jsp页面的首次执行往往由服务器管理者来执行。

在上述过程中,有几个过程的转换:
jsp—>java—>class—>html
下面要说明,在这几个过程中,所使用的编码和解码格式。
  第一阶段:jsp到java文件。在我们书写jsp代码时,一般要在文件开头声明pageEncoding属性,这个属性就是用来设置JSP源文件本身的编码。告诉jsp引擎 这个jsp本身采用的编码,然后jsp引擎根据这个编码读取再翻译成一个unicode的java文件,也就是说声明pageEncoding这个属性就是为了让jsp引擎正确的读取jsp。也就是说不管你jsp是哪种编码,最后都会统一成一个Unicode的java文件。这个过程中产生的乱码原因是,你并没有告诉jsp引擎使用哪种编码格式读取jsp,所以就采用默认的编码读了,这样就造成了读取错误,进而导致生成的java错误。需要注意的是,如果pageEncoding属性存在,那么JSP页面的字符编码方式就由pageEncoding决定,否则就由contentType属性中的charset决定,如果charset也不存在,JSP页面的字符编码方式就采用默认的ISO-8859-1。
  第二阶段:java文件到class文件。这个过程没有什么好说的,因为它都是jvm虚拟机内部的事情了,值得注意的是,jsp文件不像单纯的java文件。上面讲的java文件在被编译器读入的时候默认采用的是操作系统所对应的编码,比如中国大陆就是GBK,台湾就是BIG5或者MS950。而一般我们在记事本上写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。所以编译器采用的方法刚好可以让虚拟机得到正确的资料。但是,这里不一样,在上个阶段生成的java文件已经是Unicode文件了,所以继续以Unicode编译成class文件。
  第三阶段:从class文件到html文件,也就是从服务器到客户端浏览器,在这个过程中要依赖的参数是contentType属性。它指定了服务器将class文件翻译成什么形式的文件发送给客户端,同时告诉客户端以怎样的方式显示内容。所以在contentType需设置MIME类型(一般都是使用html解释器)和jsp页面字符的编码。

综上所述,一般我们在jsp开头声明的内容是:
<%@ page language=“java” contentType=“text/html; charset=utf-8” pageEncoding=“utf-8” %>

这里language属性是定义jsp页面使用的脚本语言,该属性的值目前只能取“java”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值