/* * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.struts.taglib.bean; import org.apache.struts.taglib.TagUtils; import org.apache.struts.util.MessageResources; import org.apache.struts.util.RequestUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; import java.io.BufferedInputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Map; /** * Define the contents of a specified intra-application request as a page * scope attribute of type <code>java.lang.String</code>. If the current * request is part of a session, the session identifier will be included in * the generated request, so it will be part of the same session. <p> * <strong>FIXME</strong>: In a servlet 2.3 environment, we can use a wrapped * response passed to RequestDispatcher.include(). * * @version $Rev$ $Date: 2005-08-21 19:08:45 -0400 (Sun, 21 Aug 2005) * $ */ public class IncludeTag extends TagSupport { // ------------------------------------------------------------- Properties /** * Buffer size to use when reading the input stream. */ protected static final int BUFFER_SIZE = 256; /** * The message resources for this package. */ protected static MessageResources messages = MessageResources.getMessageResources( "org.apache.struts.taglib.bean.LocalStrings"); /** * The anchor to be added to the end of the generated hyperlink. */ protected String anchor = null; /** * The name of the global <code>ActionForward</code> that contains a path * to our requested resource. */ protected String forward = null; /** * The absolute URL to the resource to be included. */ protected String href = null; /** * The name of the scripting variable that will be exposed as a page scope * attribute. */ protected String id = null; /** * The context-relative URI of the page or servlet to be included. */ protected String page = null; /** * Include transaction token (if any) in the hyperlink? */ protected boolean transaction = false; protected boolean useLocalEncoding = false; protected String useEncodingName = null; public String getAnchor() { return (this.anchor); } public void setAnchor(String anchor) { this.anchor = anchor; } public String getForward() { return (this.forward); } public void setForward(String forward) { this.forward = forward; } public String getHref() { return (this.href); } public void setHref(String href) { this.href = href; } public String getId() { return (this.id); } public void setId(String id) { this.id = id; } public String getPage() { return (this.page); } public void setPage(String page) { this.page = page; } public boolean getTransaction() { return (this.transaction); } public void setTransaction(boolean transaction) { this.transaction = transaction; } public boolean isUseLocalEncoding() { return useLocalEncoding; } public void setUseLocalEncoding(boolean b) { useLocalEncoding = b; } public String getUseEncodingName() { return (this.useEncodingName); } public void setUseEncodingName(String useEncodingName) { this.useEncodingName = useEncodingName; } // --------------------------------------------------------- Public Methods /** * Define the contents returned for the specified resource as a page scope * attribute. * * @throws javax.servlet.jsp.JspException if a JSP error occurs */ public int doStartTag() throws JspException { // Set up a URLConnection to read the requested resource Map params = TagUtils.getInstance().computeParameters(pageContext, null, null, null, null, null, null, null, transaction); // FIXME - <html:link> attributes String urlString = null; URL url = null; try { urlString = TagUtils.getInstance().computeURLWithCharEncoding(pageContext, forward, href, page, null, null, params, anchor, false, useLocalEncoding); if (urlString.indexOf(':') < 0) { HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); url = new URL(RequestUtils.requestURL(request), urlString); } else { url = new URL(urlString); } } catch (MalformedURLException e) { TagUtils.getInstance().saveException(pageContext, e); throw new JspException(messages.getMessage("include.url", e.toString()), e); } URLConnection conn = null; try { // Set up the basic connection conn = url.openConnection(); conn.setAllowUserInteraction(false); conn.setDoInput(true); conn.setDoOutput(false); // Add a session id cookie if appropriate HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); addCookie(conn, urlString, request); // Connect to the requested resource conn.connect(); } catch (Exception e) { TagUtils.getInstance().saveException(pageContext, e); throw new JspException(messages.getMessage("include.open", url.toString(), e.toString()), e); } // Copy the contents of this URL StringBuffer sb = new StringBuffer(); try { BufferedInputStream is = new BufferedInputStream(conn.getInputStream()); //编码乱码问题的根源 InputStreamReader in = new InputStreamReader(is,useEncodingName); // FIXME- encodin char[] buffer = new char[BUFFER_SIZE]; int n = 0; while (true) { n = in.read(buffer); if (n < 1) { break; } sb.append(buffer, 0, n); } in.close(); } catch (Exception e) { TagUtils.getInstance().saveException(pageContext, e); throw new JspException(messages.getMessage("include.read", url.toString(), e.toString()), e); } // Define the retrieved content as a page scope attribute pageContext.setAttribute(id, sb.toString()); // Skip any body of this tag return (SKIP_BODY); } /** * Add a session id cookie if appropriate. Can be overloaded to support a * cluster. * * @param conn * @param urlString * @param request * @since Struts 1.2.0 */ protected void addCookie(URLConnection conn, String urlString, HttpServletRequest request) { if ((conn instanceof HttpURLConnection) && urlString.startsWith(request.getContextPath()) && (request.getRequestedSessionId() != null) && request.isRequestedSessionIdFromCookie()) { StringBuffer sb = new StringBuffer("JSESSIONID="); sb.append(request.getRequestedSessionId()); conn.setRequestProperty("Cookie", sb.toString()); } } /** * Release all allocated resources. */ public void release() { super.release(); anchor = null; forward = null; href = null; id = null; page = null; transaction = false; } }
大家可以看这个类的struts1 源码第234行,源代码上
InputStreamReader in = new InputStreamReader(is);//FIXME- encoding
默认写法是这样的(上面都写了fixme-encoding,我就想不通怎么没有修正),如果没有指定编码,将使用平台的默认编码
所以添加 protected String useEncodingName = null; 及其get set方法
传入我们额外增加的变量 ,InputStreamReader in = new InputStreamReader(is,useEncodingName);
完成修改之后,本地编译,然后将生成的class文件覆盖struts.jar中的原有IncludeTag.class,为了保险起见,请注意覆盖前请先备份
<tag> <name>include</name> <tagclass>org.apache.struts.taglib.bean.IncludeTag</tagclass> <teiclass>org.apache.struts.taglib.bean.IncludeTei</teiclass> <bodycontent>empty</bodycontent> <attribute> <name>anchor</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>forward</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>href</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>id</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>name</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>page</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>transaction</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>useEncodingName</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
修改struts-bean.tld 添加
<attribute>
<name>useEncodingName</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
这几行定义
<% if(StringUtils.isNotEmpty(zj_sjd_id)){ String page_url = "/bgSjdMgr.do?method=showBgShouyDetail&sjdid="+ zj_sjd_id; %> <bean:include id="showBgShouyDetail" page="<%=page_url%>" useEncodingName="utf-8"/> <bean:write name="showBgShouyDetail" filter="false"/> <% } %>
在调用的时候,补上目标页面使用的编码格式,如上,我的原页面和目标页面都是utf-8,问题解决。
我开始搜这个问题的时候,网上所说的使用目标页面编码改成gbk的不优雅解决方式其实就是和默认的平台编码匹配。
本人的愚见 欢迎各路同行不吝赐教,共同探讨