您的位置:首页 > 编程语言 > Java开发

Struts 2.1--随便写写

2010-01-24 03:30 141 查看
学习Struts 2.1有一阵了,本以为差不多了,今天拿起来练了练,几个问题却让我琢磨了好久。心血来潮写一写,给自己提个醒,也跟还没注意的朋友分享下,希望能帮你们在学习和工作中节省点时间。

1. parameters

在页面中可以使用Ognl表达式#parameters访问请求参数,Action可以实现ParameterAware接口让框架注入该Map,同样,也可以使用ActionContext.getContext().getParameters()得到请求参数Map。

今天尝试了一下,在Action中使用ActionContext.getContext().getParameters().put("test","hehe");

在页面中使用<s:property value="#parameters.test">,没有任何输出。

尝试实现ParameterAware接口,使用框架注入Map的,仍然没有。

折腾了3个小时,结论如下:

框架构造这一堆Map时(request,session,parameters,application等)有类似如下的代码:

xxx.put(ActionContext.PARAMETERS,new HashMap(parameterMap));

xxx.put("parameters",parameterMap);

对实现了ParameterAware接口的Action执行如下代码

if(action instanceof ParameterAware){

((ParameterAware)action).setParameters(context.getParameters());

}

ActionContext.getContext().getParameters()和上面的getParameters()方法如下

public Map<String,String[]> getParameters(){

return (Map<String,String[]>)get(PARAMETERS);

}

Ognl表达式#parameter访问与Map和ActionContext.getContext().getParameters()和接口注入的Map根本就不是一个对象,但要注意的是,以ActionContext.PARAMETERS为键的Map是由以"parameters"为键的Map构造的

仔细想了下,估计这种设计,为了保全原始请求参数,以至于在Action中,无论用户如何操作,都不会破坏原始请求参数Map 的结构。

2. 在使用token拦截器避免重复提交表单时,自定义错误信息。

这个问题可能是我低能了,都配置好后可以顺利的避免表单重复提交(<s:token />不能带name属性,否则会有Ognl异常,不知道为什么),只是错误信息一直是“The form has already been processed or no token was supplied, please try again.” 国际化信息是陪在Action同包里的,跟Action同名,就算加上“struts.messges.invalid.token=请不要重复提交”,也是无济于事。

解决:classes目录下建struts-message_zh_CN.properties和struts-message_en.properties两个文件,以struts.messges.invalid.token为键写上相应的中英文信息。在struts.xml中配置<constant name="struts.custom.i18n.resources" value="struts-message">实现国际化(文件名可以任意起),还可以把struts2核心文件中的struts-messages.properties里的内容全都拷过来,把一些日志信息也换成中文的,看着舒服,呵呵。

3. 控制文件下载

虽然可以在struts.xml中配置,但有时候也需要跟据情况改变下载文件的MIME类型,文件名等。

本来可以用拦截器,在下载前动态改变保存在ResultConfig中的配置信息

Map<String,ResultConfig> resultMap = invocation.getProxy().getConfig().getResults();

(如果使用注解拦截的话,invocation可以通过ActionContext.getContext().getActionInvocation()得到)

ResultConfig config = resultMap.get(invocation.getResultCode());

config.addParam()。。。

结果发现Struts 2.0中本有addParam方法,可是Struts 2.1中并没有

换了个方式,config.getParams.put(),结果更惨,unknown location异常

解决:换个方式绕着走,Action中加这样的方法

@BeforeResult

public void download(){

type = XXXXX

}

public String getContentType(){

return type; // type是Action中一个属性,在注解为@beforeResult的方法中设置其值,可达到动态修改MIME类型的效果

}

public String getFilename(){ // 这个方法名得注意一下,似乎不能为getContentDisposition,好像有冲突

try {

return new String("xxx".getBytes(),"ISO8859-1"); // 这样写是为了支持可以使用中文的文件名

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

return "xxx";

}

}

struts.xml文件中

......

<param name="contentType">${contentType}</param>

<param name="contentDisposition">attachment;filename="${filename}"</param>

......

这样就OK了,道理很简单,表达式都使用getter方法,忽忽!

4. FreeMarker中使用radio,select,doubleselect等带有那个list属性的一些标签

Struts 2对FreeMarker确实支持的很好,不过这几个标签让人摸不着门。在Freemarker模板文件中

<@s.radio name="xx" value="xx" list="#{'xx':'xx', 'xxx':'xxx'}" />

list属性这样取值是不行的,但如果用FreeMarker语法list={'xx':'xx', 'xxx':'xxx'},页面的输出绝对不是你想要的,是HashAdapter地址

确实想不通这是什么道理,不过除了去改Struts 2的模板,还有其他办法。

在Struts 2模板中,radio是这样处理的

<#if parameters.listKey??>

<#assign itemKey = stack.findValue(parameters.listKey)/>

<#else>

<#assign itemKey = stack.findValue('top')/>

</#if>

<#assign itemKeyStr = itemKey.toString() />

<#if parameters.listValue??>

<#assign itemValue = stack.findString(parameters.listValue)/>

<#else>

<#assign itemValue = stack.findString('top')/>

</#if>

这样就很明显了,页面会输出HashAdapter的地址也就正常了,因为解析标签的时候top就是那个对象

解决:给它加上listKey和listValue就好了,stack.findValue会查找listKey的值,listValue同理,这样就可以写成

<@s.radio name="xx" value="xx" list={'name':'zhangsan', 'age':'18'} listKey="top.key" listValue="top.value" />

虽说有点牛头不对马嘴,语法混用,但毕竟还是解决问题了,粗糙点而已。

解析这个标签时,栈顶对象就是那个list的值,而top.key会先被计算为name(第一次迭代,第二次迭代是age)

的确很乱,不过只要区分好FreeMarker语法和Ognl表达式就好了。比如说:输出国际化信息

<@s.property value="getText('name')" />

${action.getText('name')}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: