分享
 
 
 

Turbine表单处理中的中文

王朝java/jsp·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

Turbine是apache 项目中的server-side java技术,位于jakarta子项目,是基于servlet的web应用框架.它提供了很多基础服务:访问控制,页面个性化,服务调度,表单确认,xml-rpc格式的web服务等等.可以做为开发面向服务架构应用的基础,因为turbine很容易开发其它服务,并在其服务管理框架下运行.其下一个版本为2.4,它明确使用亚瑟王神剑项目(该项目实现了IOC模式)来管理服务组件。

本文描述的场景是:turbine2.31+velocity-1.4+torque-3.1。要解决在该场景下提交编码模式为multipart/form-data的表单不能正确处理中文的问题,虽然application/x-www-form-urlencoded编码下可以正确处理中文.

纠正本问题需要提供:Maven,Ant两个工具以及Turbine源码.

首先,看Turbine的入口servlet Turbine.java中的代码片段,是doGet方法:

目的是看原始的web服务器请求对象(request)是如何被传递入Turbine中的,以及Turbine如何处理request对象.

public final void doGet(HttpServletRequest req, HttpServletResponse res)

throws IOException, ServletException

{

// set to true if the request is to be redirected by the page

boolean requestRedirected = false;

// Placeholder for the RunData object.

RunData data = null;

try

{

// Check to make sure that we started up properly.

if (initFailure != null)

{

throw initFailure;

}

// Get general RunData here...

// Perform turbine specific initialization below.

data = rundataService.getRunData(req, res, getServletConfig());

// If this is the first invocation, perform some

// initialization. Certain services need RunData to initialize

// themselves.

if (firstDoGet)

{

init(data);

}

// set the session timeout if specified in turbine's properties

// file if this is a new session

if (data.getSession().isNew())

{

int timeout = configuration.getInt(SESSION_TIMEOUT_KEY,

SESSION_TIMEOUT_DEFAULT);

if (timeout != SESSION_TIMEOUT_DEFAULT)

{

data.getSession().setMaxInactiveInterval(timeout);

}

}

// Fill in the screen and action variables.

data.setScreen(data.getParameters().getString(URIConstants.CGI_SCREEN_PARAM));

data.setAction(data.getParameters().getString(URIConstants.CGI_ACTION_PARAM));

// Special case for login and logout, this must happen before the

// session validator is executed in order either to allow a user to

// even login, or to ensure that the session validator gets to

// mandate its page selection policy for non-logged in users

// after the logout has taken place.

if (data.hasAction())

{

String action = data.getAction();

log.debug("action = " + action);

if (action.equalsIgnoreCase(

configuration.getString(ACTION_LOGIN_KEY,

ACTION_LOGIN_DEFAULT)))

{

loginAction(data);

}

else if (action.equalsIgnoreCase(

configuration.getString(ACTION_LOGOUT_KEY,

ACTION_LOGOUT_DEFAULT)))

{

logoutAction(data);

}

}

// This is where the validation of the Session information

// is performed if the user has not logged in yet, then

// the screen is set to be Login. This also handles the

// case of not having a screen defined by also setting the

// screen to Login. If you want people to go to another

// screen other than Login, you need to change that within

// TurbineResources.properties...screen.homepage; or, you

// can specify your own SessionValidator action.

ActionLoader.getInstance().exec(

data, configuration.getString(ACTION_SESSION_VALIDATOR_KEY,

ACTION_SESSION_VALIDATOR_DEFAULT));

// Put the Access Control List into the RunData object, so

// it is easily available to modules. It is also placed

// into the session for serialization. Modules can null

// out the ACL to force it to be rebuilt based on more

// information.

ActionLoader.getInstance().exec(

data, configuration.getString(ACTION_ACCESS_CONTROLLER_KEY,

ACTION_ACCESS_CONTROLLER_DEFAULT));

// Start the execution phase. DefaultPage will execute the

// appropriate action as well as get the Layout from the

// Screen and then execute that. The Layout is then

// responsible for executing the Navigation and Screen

// modules.

//

// Note that by default, this cannot be overridden from

// parameters passed in via post/query data. This is for

// security purposes. You should really never need more

// than just the default page. If you do, add logic to

// DefaultPage to do what you want.

String defaultPage = (templateService == null)

? null :templateService.getDefaultPageName(data);

if (defaultPage == null)

{

/*

* In this case none of the template services are running.

* The application may be using ECS for views, or a

* decendent of RawScreen is trying to produce output.

* If there is a 'page.default' property in the TR.props

* then use that, otherwise return DefaultPage which will

* handle ECS view scenerios and RawScreen scenerios. The

* app developer can still specify the 'page.default'

* if they wish but the DefaultPage should work in

* most cases.

*/

defaultPage = configuration.getString(PAGE_DEFAULT_KEY,

PAGE_DEFAULT_DEFAULT);

}

PageLoader.getInstance().exec(data, defaultPage);

// If a module has set data.acl = null, remove acl from

// the session.

if (data.getACL() == null)

{

try

{

data.getSession().removeAttribute(

AccessControlList.SESSION_KEY);

}

catch (IllegalStateException ignored)

{

}

}

// handle a redirect request

requestRedirected = ((data.getRedirectURI() != null)

&& (data.getRedirectURI().length() > 0));

if (requestRedirected)

{

if (data.getResponse().isCommitted())

{

requestRedirected = false;

log.warn("redirect requested, response already committed: " +

data.getRedirectURI());

}

else

{

data.getResponse().sendRedirect(data.getRedirectURI());

}

}

if (!requestRedirected)

{

try

{

if (data.isPageSet() == false && data.isOutSet() == false)

{

throw new Exception("Nothing to output");

}

// We are all done! if isPageSet() output that way

// otherwise, data.getOut() has already been written

// to the data.getOut().close() happens below in the

// finally.

if (data.isPageSet() && data.isOutSet() == false)

{

// Modules can override these.

data.getResponse().setLocale(data.getLocale());

data.getResponse().setContentType(

data.getContentType());

// Set the status code.

data.getResponse().setStatus(data.getStatusCode());

// Output the Page.

data.getPage().output(data.getOut());

}

}

catch (Exception e)

{

// The output stream was probably closed by the client

// end of things ie: the client clicked the Stop

// button on the browser, so ignore any errors that

// result.

log.debug("Output stream closed? ", e);

}

}

}

catch (Exception e)

{

handleException(data, res, e);

}

catch (Throwable t)

{

handleException(data, res, t);

}

finally

{

// Return the used RunData to the factory for recycling.

rundataService.putRunData(data);

}

}

以及org.apache.turbine.services.rundata.TurbineRunDataService中的:

public RunData getRunData(HttpServletRequest req,

HttpServletResponse res,

ServletConfig config)

throws TurbineException

{

return getRunData(DEFAULT_CONFIG, req, res, config);

}

/**

* Gets a RunData instance from a specific configuration.

*

* @param key a configuration key.

* @param req a servlet request.

* @param res a servlet response.

* @param config a servlet config.

* @return a new or recycled RunData object.

* @throws TurbineException if the operation fails.

* @throws IllegalArgumentException if any of the parameters are null.

*/

public RunData getRunData(String key,

HttpServletRequest req,

HttpServletResponse res,

ServletConfig config)

throws TurbineException,

IllegalArgumentException

{

// The RunData object caches all the information that is needed for

// the execution lifetime of a single request. A RunData object

// is created/recycled for each and every request and is passed

// to each and every module. Since each thread has its own RunData

// object, it is not necessary to perform syncronization for

// the data within this object.

if ((req == null)

|| (res == null)

|| (config == null))

{

throw new IllegalArgumentException("HttpServletRequest, "

+ "HttpServletResponse or ServletConfig was null.");

}

// Get the specified configuration.

String[] cfg = (String[]) configurations.get(key);

if (cfg == null)

{

throw new TurbineException("RunTime configuration '" + key + "' is undefined");

}

TurbineRunData data;

try

{

data = (TurbineRunData) pool.getInstance(cfg[0]);

data.setParameterParser((ParameterParser) pool.getInstance(cfg[1]));

data.setCookieParser((CookieParser) pool.getInstance(cfg[2]));

}

catch (ClassCastException x)

{

throw new TurbineException("RunData configuration '" + key + "' is illegal", x);

}

// Set the request and response.

data.setRequest(req);

data.setResponse(res);

// Set the servlet configuration.

data.setServletConfig(config);

// Set the ServerData.

data.setServerData(new ServerData(req));

return data;

}

在 org.apache.turbine.services.rundata.DefaultTurbineRunData中的:

/**

* Sets the servlet request.

*

* @param req a request.

*/

public void setRequest(HttpServletRequest req)

{

this.req = req;

}

/**

* Sets the servlet response.

*

* @param res a response.

*/

public void setResponse(HttpServletResponse res)

{

this.res = res;

}

在该类中request对象被不加修改的传递到了ParameterParser:

/**

* Gets the parameters.

*

* @return a parameter parser.

*/

public ParameterParser getParameters()

{

// Parse the parameters first, if not yet done.

if ((this.parameters != null) &&

(this.parameters.getRequest() != this.req))

{

this.parameters.setRequest(this.req);

}

return this.parameters;

}

/**

* Gets the parameter parser without parsing the parameters.

*

* @return the parameter parser.

*/

public ParameterParser getParameterParser()

{

return parameters;

}

/**

* Sets the parameter parser.

*

* @param parser a parameter parser.

*/

public void setParameterParser(ParameterParser parser)

{

parameters = parser;

}

以上类中展示的代码都涉及到了Request对象,从这些代码中看出在Turbine中,实际上并没有对Request对象做任何修改,这样就可以按照通常的方法,加入对Request对象的处理代码.最后, 这里是关键的地方:在类DefaultParameterParser中对Request对象的处理,也就是通过对该处的修改,问题得到了解决:

/**

* Sets the servlet request to be parser. This requires a

* valid HttpServletRequest object. It will attempt to parse out

* the GET/POST/PATH_INFO data and store the data into a Map.

* There are convenience methods for retrieving the data as a

* number of different datatypes. The PATH_INFO data must be a

* URLEncoded() string.

* <p>

* To add name/value pairs to this set of parameters, use the

* <code>add()</code> methods.

*

* @param request An HttpServletRequest.

*/

public void setRequest(HttpServletRequest request)

{

clear();

uploadData = null;

//String enc = request.getCharacterEncoding();

原来是:

enc = request.getCharacterEncoding();

setCharacterEncoding(enc != null ? enc : "US-ASCII");

修改后:

if(enc==null) enc=org.apache.turbine.Turbine.getConfiguration().getString(CharacterEncoding_Key,"US-ASCII");

setCharacterEncoding(enc);

// String object re-use at its best.

String tmp = null;

tmp = request.getHeader("Content-type");

if (uploadServiceIsAvailable

&& uploadService.getAutomatic()

&& tmp != null

&& tmp.startsWith("multipart/form-data"))

{

log.debug("Running the Turbine Upload Service");

try

{

TurbineUpload.parseRequest(request, this);

}

catch (TurbineException e)

{

log.error("File upload failed", e);

}

}

for (Enumeration names = request.getParameterNames();

names.hasMoreElements();)

{

tmp = (String) names.nextElement();

add(convert(tmp),

request.getParameterValues(tmp));

}

// Also cache any pathinfo variables that are passed around as

// if they are query string data.

try

{

StringTokenizer st =

new StringTokenizer(request.getPathInfo(), "/");

boolean isNameTok = true;

String pathPart = null;

while (st.hasMoreTokens())

{

if (isNameTok)

{

tmp = URLDecoder.decode(st.nextToken());

isNameTok = false;

}

else

{

pathPart = URLDecoder.decode(st.nextToken());

if (tmp.length() > 0)

{

add(convert(tmp), pathPart);

}

isNameTok = true;

}

}

}

catch (Exception e)

{

// If anything goes wrong above, don't worry about it.

// Chances are that the path info was wrong anyways and

// things that depend on it being right will fail later

// and should be caught later.

}

this.request = request;

if (log.isDebugEnabled())

{

log.debug("Parameters found in the Request:");

for (Iterator it = keySet().iterator(); it.hasNext();)

{

String key = (String) it.next();

log.debug("Key: " + key + " -> " + getString(key));

}

}

}

同时在配置文件TurbineResources.properties中加入一项:

CharacterEncoding=gb2312.可以根据需要修改该值.

完成以上修改后,用Maven工具重新构建Turbine并得到了新的turbine.jar把它放入你的应用环境中,中文问题即得到正确显示.

注意:以上代码片段来自Turbine源码.黑体字表示要关注的部分,代码中修改部分则给出了说明.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有