AJAX乱码解决大全【精】


1、编码
      
编码比较常用的有:UTF-8GBKGB2312ISO-8859-1,除了iso-8859-1之外的其它三个编码都能很好的支持中文,但它们都兼容ISO-8859-1的编码(就是说无论编码怎么改变,只要是ISO-8859-1中的字符,永远不会出现乱码)。
     
这四种编码中,GB2312是中国规定的汉字编码,也可以说是简体中文的字符集编码;GBKGB2312的扩展,除了兼容GB2312外,它还能显示繁体中文,还有日文的假名;UTF-8虽然也支持中文,但却GB码不兼容(编码值不同)UTF-8使用的是可变长的UNICODE编码,编码可能是116进制(即ISO-8859-1中的字符,其编码也是相同的)也有可能是2位或3位的16进制。UTF-8的优点是:1CPU字节顺序无关,可以在不同平台之间交流。2、容错能力高,任何一个字节损坏后,最多只会导致一个编码码位损失,不会链锁错误(GB码错一个字节就会整行乱码),所以在国际化处理中基本都是建议使用UTF-8作为编码。

2、文件的编码
     
文件编码最常使用的有两种:ANSIUTF-8,光看名字估计你都可以猜到了,ANSI就是我们保存文件时使用的默认编码,而UTF-8则需自己设置。对于编码的改变,我使用的工具是NOTEPADECLIPSENOTEPAD使用最简单,只要打开文件后在另存为中选择相应的编码就行了,而且它对编码的支持非常好;而在ECLIPSE中,只要稍微设置一下就行了,打开首选项,然后选择:常规->内容类型(ContentType),在右边选中你想改变保存编码的文件类型,然后在下方的缺省编码中改变其值,最后点击更新(UPDATE)按钮即可。


而在其它的编辑器中,默认保存的内容都是GB2312或者GBK(NOTEPAD中对应ANSI).而根据前面所说的UTF-8和GBK,GB2312等 的编码值是不同的这一点,可以知道,如果文件使用了UTF-8,那么字符编码就必须使用UTF-8,否则编码值的不同就可能造成乱码。而这也就是为什么那 么多的人使用了UTF-8编码后还会产生乱码的根本原因。(JS和JSP都是这个道理)
3、JSP,STRUTS等的中文乱码解决方案
     其实解决的方法只有一个:

request.setCharacterEncoding(encoding);

    方法只有一种,但处理方式就多种多样了,初学者会在JSP页面上直接使用,而有经验的程序员会使用过滤器。而现在所要说的方法也是过滤器。这里以统一使用 UTF-8作为编码作为例子说明。具体过程就不多说了,网上有很多教程。偷懒一点的,到TOMCAT中复制就行了。在TOMCAT的目录下 的"webapps"jsp-examples"WEB-INF"classes"filters"找到 SetCharacterEncodingFilter.java 这个类,放到你的程序中并配置好映射路径。配置好后基本上你的乱码问题就解决了。但要映射路径中需要注意的就是不能使用 '*'

  <filter-mapping>
    
<filter-name>Set Character Encoding</filter-name>
    
<servlet-name>*</servlet-name>
  
</filter-mapping>

像上面这样配置的话(可能也是网上大多教程的做法,想当年也是害苦了我),可能你只有JSP的乱码解决了,要解决STRUTS的乱码需要映射 *.do 或者 servletActionName。然后在初始化参数中设置encoding的值就行了。

<init-param>
      
<param-name>encoding</param-name>
      
<param-value>UTF-8</param-value>
</init-param>

当然,最重要的是要记得根据前面所说的方法,改变你所使用的编辑器保存文件的编码要与使用的字符编码一致。
而在JSP内容中,还是使用如网上教程所说的那种技俩,在所有页面的页首加入:

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

至此,相信JSP,ACTION都不太可能出现乱码了。
4、资源文件的乱码解决方案
      资源文件谁都知道是国际化支持不可或缺的一部分,如果资源文件都出现乱码了那还了得?其实资源文件的乱码是很好解决的,其原因也是因为使用了UTF-8做 为JSP编码后,没有相应地改变资源文件的文件编码造成的,所以只要对资源文件保存的编码进行更正后,乱码问题也就解决了。当然,你的中文要使用 native2ascii 命令进行正确的转换。
5、调用JS时,JS内容乱码的解决方案。
     其实JS的乱码还是跟文件的编码有关系的,如果JS中有中文的话,那JS文件保存的编码就必须跟调用此JS的页面编码相同,否则,你的所有中文都要从JSP页面传给JS才会显示正常。可以看出对于调用JS出现的乱码是最容易解决的.

6、AJAX提交数据乱码,返回数据乱码的解决方案

     万变不离其宗,AJAX的乱码问题自然跟编码有关了,其实很多人跟我一样想到了对文件编码进行设置,并且在接数据时设置了requet的编码,在返回的数 据时设置了response的编码一切都以为会很顺利,可是这一切都是徒劳无功的,讨厌的乱码再一次出现在你眼前。在你试了N多种方法,包括JS自身的 escape,unescape方法后,你发现乱码仍然猖狂地出现在屏幕上。
    其实在试过这N多方法后,很多人都没发现,解决的方法其实很简单,而且其答案就在我们之前处理的JSP乱码之中。让我们先看一下AJAX的经典请求代码

xmlhttp.open( "post", url, async );
xmlhttp.setRequestHeader( "Content-Type", "text/html" );
xmlhttp.send( params );

通过前面的说明,不知道你现在看出端倪了没有。不知道是受了网上教程的影响还是其它方面影响,setRequestHeader并是万年不变的,也没人想过去改它,而问题就正好出在这个地方。回想一个JSP页面内容的编码设置,其中有这么一节:

contentType="text/html; charset=UTF-8"

现在知道问题了吧,所以我们要把第二句代码改为:

xmlhttp.setRequestHeader( "Content-Type", "text/html;charset=UTF-8" );

如果提交的是form,那么设置为"application/x-www-form-urlencoded; charset=UTF-8"

最后别忘了在返回数据时也设置上:

response.setContentType( "text/xml" );
response.setCharacterEncoding( "UTF-8" );

如果要问为什么的话,其实我们可以把xmlhttp看成是一个临时页面,它由浏览 器动态生成,主要作用是在后台获得请求的数据(可以看成是一个高级的iframe)。所以对于普通页面设置的编码,对它也要同样设置。而在servlet 中返回数据为什么要设置contentType和encoding其道理也是一样的。众所周知,jsp的最后形态就是servlet,而jsp页首设置的 那个内容其实也就是让生成的servlet中生成这么两句话:

response.setContentType( "text/html" );
response.setCharacterEncoding( "UTF-8" );

而pageEncoding则是跟jvm说明了这个页面的内容要使用什么编码保存(这跟之后生成的CLASS有关系)。所以在servlet设置response的编码也是理所当然的了。

response.setContentType("text/xml;charset=UTF-8");

response.setHeader("Pragma",   "no-cache");   //HTTP   1.0  

response.setDateHeader("Expires",   0);   //prevents   caching   at   the   proxy   server  

PrintWriter out = response.getWriter();

out.write(outXML);

out.flush();

out.close();

OK!这样向客户端写的数据中的中文也是UTF-8编码了,客户端js脚本获取到request.responseXML也好,responseText也好,里面的数据都不会有乱码了


标签: 乱码, 编码, utf, jsp

JSP生成静态HTML页面的3种方法


一、从数据库中取相应数据并替换掉模板中的对应标签,下面是一个简单的示例


1.buildhtml.jsp
<%@ page contentType="text/html; charset=gb2312" import="java.util.*,java.io.*"%>
<%
try{
String title="This is Title";
String content="This is Content Area";
String editer="LaoMao";
String filePath = "";
filePath = request.getRealPath("/")+"test/template.htm";
//out.print(filePath+"<br>");
String templateContent="";
FileInputStream fileinputstream = new FileInputStream(filePath);//读取模块文件
int lenght = fileinputstream.available();
byte bytes[] = new byte[lenght];
fileinputstream.read(bytes);
fileinputstream.close();
templateContent = new String(bytes);
//out.print(templateContent);
templateContent=templateContent.replaceAll("###title###",title);
templateContent=templateContent.replaceAll("###content###",content);
templateContent=templateContent.replaceAll("###author###",editer);//替换掉模块中相应的地方
//out.print(templateContent);
// 根据时间得文件名
Calendar calendar = Calendar.getInstance();
String fileame = String.valueOf(calendar.getTimeInMillis()) +".html";
fileame = request.getRealPath("/")+fileame;//生成的html文件保存路径
FileOutputStream fileoutputstream = new FileOutputStream(fileame);//建立文件输出流
byte tag_bytes[] = templateContent.getBytes();
fileoutputstream.write(tag_bytes);
fileoutputstream.close();
}
catch(Exception e){
out.print(e.toString());
}
%>

2. template.htm
<html>
<head>
<title>###title###</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<LINK href="../css.css" rel=stylesheet type=text/css>
</head>

<body>
<table width="500" border="0" align="center" cellpadding="0" cellspacing="2">
   <tr>  
     <td align="center">###title###</td>
   </tr>
   <tr>  
     <td align="center">author:###author###  </td>
   </tr>
   <tr>
     <td>###content###</td>
   </tr>
</table>
</body>
</html>


=======================================================

二、从动态页的URL获取相应页面内容并写入到文件

/*
* Created on 2006-3-4
* To change the template for this generated file go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
package com.easydone.cn.tools.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;

/**
* @author Administrator
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class MakeHtml {
         private static long star = 0;
         private static long end = 0;
         private static long ttime = 0;

         //返回html代码
         public static String getHtmlCode(String httpUrl){
         Date before = new Date();
         star = before.getTime();
         String htmlCode = "";
         try {
         InputStream   in;
         URL url = new java.net.URL(httpUrl);
         HttpURLConnection connection = (HttpURLConnection)url.openConnection();
         connection = (HttpURLConnection) url.openConnection();
         connection.setRequestProperty("User-Agent","Mozilla/4.0");
         connection.connect();
         in = connection.getInputStream();
         java.io.BufferedReader breader = new BufferedReader(new InputStreamReader(in , "GBK"));
         String currentLine;
           while((currentLine=breader.readLine())!=null){
         htmlCode+=currentLine;
           }
         } catch (Exception e) {
         e.printStackTrace();
         }finally{
         Date after = new Date();
         end = after.getTime();
         ttime = end-star ;
         System.out.println("执行时间:"+ttime +"秒");
         }
         return htmlCode;
         }
         //存储文件
         public static synchronized void writeHtml(String filePath,String info,String flag) {

         PrintWriter pw = null;
         try {
         File writeFile = new File(filePath);
         boolean isExit = writeFile.exists();
         if (isExit != true) {
         writeFile.createNewFile();
         } else {
         if (!flag.equals("NO")) {
         writeFile.delete();
         writeFile.createNewFile();
         }  
         }
         pw = new PrintWriter(new FileOutputStream(filePath, true));
         pw.println(info);
         pw.close();
         } catch (Exception ex) {
         System.out.println(ex.getMessage());
         }finally{
         pw.close();
         }
         }

         public static void main(String[] args) {
         String url = "http://www.easydone.cn/index.htm";
         writeHtml("c:/demo.htm",getHtmlCode(url),"NO");
         }
}

三、利用Filter和定制Response,把服务器返回的JSP响应输出到我们自己的Response中,就可以将响应快速写入Html文件,然后再发送给客户。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Calendar;

public class CacheFilter implements Filter {
   ServletContext sc;
   FilterConfig fc;
   long cacheTimeout = Long.MAX_VALUE;

   public void doFilter(ServletRequest req,
                        ServletResponse res,
                        FilterChain chain)
       throws IOException, ServletException {
     HttpServletRequest request =
         (HttpServletRequest) req;
     HttpServletResponse response =
         (HttpServletResponse) res;

     // check if was a resource that shouldn't be cached.
     String r = sc.getRealPath("");
     String path =  
         fc.getInitParameter(request.getRequestURI());
     if (path!= null && path.equals("nocache")) {
       chain.doFilter(request, response);
       return;
     }
     path = r+path;

     String id = request.getRequestURI() +  
         request.getQueryString();
     File tempDir = (File)sc.getAttribute(
       "javax.servlet.context.tempdir");

     // get possible cache
     String temp = tempDir.getAbsolutePath();
     File file = new File(temp+id);

     // get current resource
     if (path == null) {
       path = sc.getRealPath(request.getRequestURI());
     }
     File current = new File(path);

     try {
       long now =
         Calendar.getInstance().getTimeInMillis();
       //set timestamp check
       if (!file.exists() || (file.exists() &&
           current.lastModified() > file.lastModified()) ||
           cacheTimeout < now - file.lastModified()) {
         String name = file.getAbsolutePath();
         name =
             name.substring(0,name.lastIndexOf("/"));
         new File(name).mkdirs();
         ByteArrayOutputStream baos =
             new ByteArrayOutputStream();
         CacheResponseWrapper wrappedResponse =
           new CacheResponseWrapper(response, baos);
         chain.doFilter(req, wrappedResponse);

         FileOutputStream fos = new FileOutputStream(file);
         fos.write(baos.toByteArray());
         fos.flush();
         fos.close();
       }
     } catch (ServletException e) {
       if (!file.exists()) {
         throw new ServletException(e);
       }
     }
     catch (IOException e) {
       if (!file.exists()) {
         throw e;
       }
     }

     FileInputStream fis = new FileInputStream(file);
     String mt = sc.getMimeType(request.getRequestURI());
     response.setContentType(mt);
     ServletOutputStream sos = res.getOutputStream();
     for (int i = fis.read(); i!= -1; i = fis.read()) {
       sos.write((byte)i);
     }
   }

   public void init(FilterConfig filterConfig) {
     this.fc = filterConfig;
     String ct =
         fc.getInitParameter("cacheTimeout");
     if (ct != null) {
       cacheTimeout = 60*1000*Long.parseLong(ct);
     }
     this.sc = filterConfig.getServletContext();
   }

   public void destroy() {
     this.sc = null;
     this.fc = null;
   }
}

参考文章:

使用Filter实现静态HTML缓冲(一种折中方法)  
缓冲是Web应用中必须考虑的一个提高性能的重要手段。对于基于JSP/Servlet技术的站点,常用的缓冲有持久层的数据库连接池缓冲,内存中的值对象缓冲,JSP页面缓冲,以及各种各样的缓冲框架等等,无不是为了提高系统的吞吐量。

然 而对于大型站点来说,将JSP页面转换为静态Html也许是最高效的方法,特别适合于数据不经常变化但是页面访问量特别大的站点,如新闻等,通过把JSP 动态页面预先转换为静态Html页面,当用户请求此页面时,系统自动导向到对应的Html页面,从而避免解析JSP请求,调用后台逻辑以及访问数据库等操 作所带来的巨大开销。

如何将一个已有的JSP站点的动态JSP页面转化为静态Html呢?我们希望在不用更改现有Servlet,JSP的前提下让系统自动将这些JSP转换为Html页。幸运的是,Filter为我们提供了一种实现方案。

Filter 是Servlet 2.2规范中最激动人心的特性。Filter能过滤特定URL如/admin/*并进行必要的预处理,如修改Request和Response,从而实现 定制的输入输出。更强大的是,Filter本身是一个责任链模式,它能一个接一个地传递下去,从而将实现不同功能的Filter串起来,并且可以动态组 合。

要自动生成静态页面,用Filter截获jsp请求并先进行预处理,自动生成Html,是个不错的主意。一个很容易想到的方法是在Filter截获Request后,导向一个Servlet,在这个Servlet中向本机发送一个http请求,然后将响应写入一个文件:

   URLConnection urlConn = URLConnection.open(http://localhost/req);  

注意要避免递归。

另一个方法是不模拟http,而是定制Response,把服务器返回的JSP响应输出到我们自己的Response中,就可以将响应快速写入Html文件,然后再发送给客户。而且,由于没有http模拟请求,直接读取服务器响应速度非常快。

截 获Response的关键便是实现一个WrappedResponse,让服务器将响应写入我们的WrappedResponse中。这类似于一个代理模 式,Servlet 2.x已经提供了一个WrappedResponse类,我们只需要复写其中的一些关键方法即可。

WrappedResponse 实现了Response接口,它需要一个Response作为构造函数的参数,事实上这正是代理模式的应用:WrappedResponse充当了代理角 色,它会将JSP/Servlet容器的某些方法调用进行预处理,我们需要实现自己的方法。

综上:用Filter实现HTML缓冲的步骤是:

1. 用Filter截获请求,如/a.jsp?id=123,映射到对应的html文件名为/html/a.jsp$id=123.htm。
2. 查找是否有/html/a.jsp$id=123.htm,如果有,直接forward到此html,结束。
3. 如果没有,实现一个WrappedResponse,然后调用filterChain(request, wrappedResponse)。
4. 将返回的WrappedResponse写入文件/html/a.jsp$id=123.htm,然后返回响应给用户。
5. 下一次用户发送相同的请求时,到第2步就结束了。  

使用这个方法的好处是不用更改现有的Servlet,JSP页,限制是,JSP页面结果不能与Session相关,需要登陆或用户定制的页面不能用这种方法缓冲。
 

标签: html, jsp