`
Fly_m
  • 浏览: 258118 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

struts2乱码与json插件(1)

阅读更多

    最近要用struts2做一个体育类的系统,由于系统本身的原因(要求可操作性强,用户交互性高),所以不可避免地要用到ajax.在我的前一篇文章里已经提到了有关在struts2中运用ajax的一些东西了.这次重新再拾起来,仔细对比下其中的差别.
    在前一个例子性系统中,由于所有的编码都是以UTF-8进行编码的,所以也没有碰到过有关乱码的问题.普通调用和ajax调用都很正常地运行了.而在新的系统中,要求所有的页面(包括数据库)都要求运用GBK编码.这样,一些有关于乱码的问题就出现了,乱码...与struts2有关. 
    大家都知道,在struts2的配置文件中,有一个配置项直接跟编码有关."struts.i18n.encoding"这个配置项表示struts2将对数据进行何种形式的编码操作,默认的编码为utf-8,这也是为什么在前一个新闻系统中没有乱码的原因,因为它本身都和系统默认编码一致.而在新的系统中,由于要求必须将编码改成GBK,配置如下:

 

<constant name="struts.i18n.encoding" value="GBK"/>

   在这种情况下,加上在tomcat serve.xml中修改URIEncoding=GBK,保证传送到服务器的数据都是GBK格式.实际测试中,这种方式是正确的,编码正确.
   然而好境不长,当运用到ajax时,问题出现了.我最先采用的是struts2的json插件,看它的要求,它要求工程编码应该为UTF-8,而我的工程编码实际为GBK,这是不可能改回去的事情.先不管它,在页面中配置完成,进行ajax调用.果然,数据乱码.在action中,对数据进行了测试,发现数据在进行action时已经是乱码.对数据进行转码操作,发现将数据按

x = new String(x.getBytes("GBK"),"UTF-8");

 时,数据正常了.这就表示数据是按照utf-8格式进行传送的,而在sturts中可能将数据又转回了gbk,导致乱码产生.一开始从js入手,因为我用的prototype.js采用post进行传送.设置的encoding为"UTF-8",修改js的encoding为"GBK",发现并没有按照想像的方向发展,仍然乱码.而采用get方式发送时,数据仍然是乱码.
     只有从java方向入手了,处理方向有两种,就像我在前面两篇有关jsp乱码中提到一样.第一种是加拦截器,拦截到ajax请求时,将编码重新转码操作.第二种就是像过滤器一样,在进行参数编码前设置正确的编码.在struts2中采用的是第二种方法.其实struts.i18n.encoding采用的也是这种方法.相应的代码如下:

public void prepare(HttpServletRequest request, HttpServletResponse response) { 
        String encoding = null; 
        if (defaultEncoding != null) { 
            encoding = defaultEncoding; 
        }

        Locale locale = null;

        if (defaultLocale != null) {
            locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
        }
        if (encoding != null) { 
            try { 
                request.setCharacterEncoding(encoding); 
            } catch (Exception e) { 
                LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e); 
            }
        } 
        if (locale != null) { 
            response.setLocale(locale); 
        } 
        if (paramsWorkaroundEnabled) { 
            request.getParameter("foo"); // simply read any parameter (existing or not) to "prime" the request 
        } 
    }

 这个方法这是org.apache.struts2.dispatcher.Dispatcher中而被FilterDispatcher调用,后都大家都知道吧,是struts2的标准过滤器.它调用的地方如下:

protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException { 
 
        Dispatcher du = Dispatcher.getInstance(); 
 
        // Prepare and wrap the request if the cleanup filter hasn't already, cleanup filter should be 
        // configured first before struts2 dispatcher filter, hence when its cleanup filter's turn, 
        // static instance of Dispatcher should be null. 
        if (du == null) { 
 
            Dispatcher.setInstance(dispatcher); 
 
            // prepare the request no matter what - this ensures that the proper character encoding 
            // is used before invoking the mapper (see WW-9127) 
            dispatcher.prepare(request, response); 
        } else { 
            dispatcher = du; 
        } 
         
        try { 
            // Wrap request first, just in case it is multipart/form-data 
            // parameters might not be accessible through before encoding (ww-1278) 
            request = dispatcher.wrapRequest(request, getServletContext()); 
        } catch (IOException e) { 
            String message = "Could not wrap servlet request with MultipartRequestWrapper!"; 
            LOG.error(message, e); 
            throw new ServletException(message, e); 
        } 
 
        return request; 
    }

 由上可以看出,filter在实例化dispatcher后,调用其的prepare方法,而prepare方法中,好像涉及到的其他相关操作不多,只是操作request 和 response的,在prepare方法中,判断encoding是不是空,如果不为空则将其设置编码入request中.而在defaultEncoding的设置上,可以看出这个参数是跟struts.i18n.encoding相关的,相关代码如下:

@Inject(StrutsConstants.STRUTS_I18N_ENCODING) 
    public static void setEncoding(String val) { 
        encoding = val; 
    }

 在上面这个方法中,将把struts.i18n.encoding注入到encoding中,也就是说,如果我们设置encoding为GBK,无论在何种条件下,它就是GBK编码了.
      尝试修改这种方式,因为直接影响的就是

prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) 

这个方法,于是直接修改如为如下:

public class TextFilter extends FilterDispatcher{
	private static final Log log = LogFactory.getLog(TextFilter.class);
	private FilterConfig filterConfig;

	private static String defaultEncoding;
	private static String defaultLocale;
	private static String paramsWorkaroundEnabled = "false";

	@Inject(org.apache.struts2.StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND)
	public static void setParamsWorkaroundEnabled(String enabled) {
		paramsWorkaroundEnabled = enabled;
	}

	@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
	public static void setEncoding(String encoding) {
		defaultEncoding = encoding;
	}

	@Inject(value = StrutsConstants.STRUTS_LOCALE, required = false)
	public static void setLocale(String locale) {
		defaultLocale = locale;
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		super.init(filterConfig);
		this.filterConfig = filterConfig;
	}

	protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
		Dispatcher du = Dispatcher.getInstance();

		if(du == null) {
			Dispatcher.setInstance(dispatcher);
			prepare(request, response);
		} else {
			dispatcher = du;
		}

		try {
			request = dispatcher.wrapRequest(request, getServletContext());
		} catch(IOException e) {
			String message = "Could not wrap servlet request with MultipartRequestWrapper!";
			log.error(message, e);
			throw new ServletException(message, e);
		}

		return request;
	}

	private void prepare(HttpServletRequest request, HttpServletResponse response) {
		String encoding = request.getCharacterEncoding();
		if(encoding == null) {
			encoding = defaultEncoding;
		}

		Locale locale = null;
		if(defaultLocale != null) {
			locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
		}

		if(encoding != null) {
			try {
				request.setCharacterEncoding(encoding);
			} catch(Exception e) {
				log.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
			}
		}

		if(locale != null) {
			response.setLocale(locale);
		}

		if(isParamsWorkaroundEnabled()) {
			request.getParameter("foo");
		}
	}

	public boolean isParamsWorkaroundEnabled() {
		ServletContext servletContext = filterConfig.getServletContext();
		return servletContext != null && servletContext.getServerInfo() != null && servletContext.getServerInfo().indexOf("WebLogic") >= 0 ||
				paramsWorkaroundEnabled.equalsIgnoreCase("true");
	}
}
 

 可以看出,整个就是继承filterDispatcher,再修改其中的一个方法.将dispatcher.prepare()这一名改成filter.prepare的形式,实际上效果是一样的.惟一让人感觉不爽的就是,由于在filter中设置的各种变量都是私有而且是是静态的(我尝试用反射都不能得到它的值),导致直接不能得到父类的属性值,没办法,只有再加变量了.在上面的prepare中,判断request中的编码是不是为空,一般来说,从jsp页面传送的编码都是空的.当由js进行传送时,由于已经设置传送编码为UTF-8,故getCharacterEncoding()不为空,则不再进行设置编码了.其他由设置传送编码为defaultEncoding(即sturts.i18n.encoding).
在上面的有一句

if(isParamsWorkaroundEnabled()) { 			request.getParameter("foo"); 		}

专为weblogic设置,由于没有接触过,略过.值得不提的是,request.getParamter("foo").这一句,在tomcat里面是直接将编码固定化,即只要调用了这一句,都将使得request(在tomcat的实现中)不能再接受其他编码(参数已经被转化了).
最后,将filter设置在struts.xml中,以便窗口将参数@inject注入到filter中.

<bean class="m_ylf.cs.sicau.struts2.TextFilter" static="true"/>

 上面一句必须要,不然相应的静态参数都没有被注入,是会产生NullPointerException的哦.
先解决这一个问题,下一个问题将介绍struts2的json插件,及改进方法.

分享到:
评论
7 楼 橄榄绿 2010-10-14  
chengkun 写道
你好,我的情况更你说的一样,但是设置了textfilter后,还是老问题,中文到action后台就变乱码了。

6 楼 czllfy 2009-09-11  
兄弟呀,要怎么弄才能起效果呀!
我把TextFilter做struts2的过滤器也不起效果呀
5 楼 Fly_m 2009-02-12  
waterdh 写道

不错,struts2怎么那么傻,request的charactorEncoding和response的就由一个配置来设定,为某些应用的开发带来巨大的不便利。

呵呵,对于一些应用来说,本来就只为java这些开发来确定的.我们只需要控制这一层的解码就行了,就相当于一个层来专门控制编码一样.
4 楼 waterdh 2009-02-11  
不错,struts2怎么那么傻,request的charactorEncoding和response的就由一个配置来设定,为某些应用的开发带来巨大的不便利。
3 楼 chengkun 2008-07-31  
你好,我的情况更你说的一样,但是设置了textfilter后,还是老问题,中文到action后台就变乱码了。
2 楼 chengkun 2008-07-30  
感觉TextFilter没有被使用到,加入打印信息也没打印。需要在web.xml 里配置吗?
1 楼 chengkun 2008-07-30  
我加入工程后怎么没有效果呢?

相关推荐

Global site tag (gtag.js) - Google Analytics