`

Struts2中获取请求中包含多个相同参数值会多一个空格的解决办法.

阅读更多

最近用struts2的时候发现一个小问题,当请求中包含多个相同的参数比如:http://localhost:8888/struts2/adduser.action?degree=1&degree=2&degree=3&degree=4
多个degree的情况,而在action中只是用的String来接收,会通过ognl转换成1, 2, 3, 4.中间会多一个空格. 我jsp中使用的是checkbox,在struts2中 会对应checkboxInterceptor拦截器来处理.当处理完后会调用ai.invoke().这个方法中会调用interceptors中的拦截器,继续往下执行下一个拦截器.看源码:

checkboxInterceptor:

public String intercept(ActionInvocation ai) throws Exception {


        Map parameters = ai.getInvocationContext().getParameters();


        Map<String, String> newParams = new HashMap<String, String>();


        Set<String> keys = parameters.keySet();


        for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {


            String key = iterator.next();





            if (key.startsWith("__checkbox_")) {


                String name = key.substring("__checkbox_".length());





                iterator.remove();





                // is this checkbox checked/submitted?


                if (!parameters.containsKey(name)) {


                    // if not, let's be sure to default the value to false


                    newParams.put(name, uncheckedValue);


                }


            }


        }





        parameters.putAll(newParams);





        return ai.invoke();





    }

DefaultActionInvocation:

public String invoke
() throws Exception {
    	String profileKey = "invoke: ";
    	try {
    		UtilTimerStack.push(profileKey);
    		
    		if (executed) {
    			throw new IllegalStateException("Action has already executed");
    		}

    		if (interceptors
.hasNext()) {
    			final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
    			UtilTimerStack.profile("interceptor: "+interceptor.getName(), 
    					new UtilTimerStack.ProfilingBlock<String>() {
							public String doProfiling() throws Exception {
				    			resultCode = interceptor.getInterceptor().intercept
(DefaultActionInvocation.this);//执行拦截器
				    			return null;
							}
    			});
    		} else {
    			resultCode = invokeActionOnly();
    		}

    		// this is needed because the result will be executed, then control will return to the Interceptor, which will
    		// return above and flow through again
    		if (!executed) {
    			if (preResultListeners != null) {
    				for (Iterator iterator = preResultListeners.iterator();
    					iterator.hasNext();) {
    					PreResultListener listener = (PreResultListener) iterator.next();
    					
    					String _profileKey="preResultListener: ";
    					try {
    						UtilTimerStack.push(_profileKey);
    						listener.beforeResult(this, resultCode);
    					}
    					finally {
    						UtilTimerStack.pop(_profileKey);
    					}
    				}
    			}

    			// now execute the result, if we're supposed to
    			if (proxy.getExecuteResult()) {
    				executeResult();
    			}

    			executed = true;
    		}

    		return resultCode;
    	}
    	finally {
    		UtilTimerStack.pop(profileKey);
    	}
    }

 接下来调用parameterInterceptor:

 

 

public String doIntercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        if (!(action instanceof NoParameters)) {
            ActionContext ac = invocation.getInvocationContext();
            final Map parameters = retrieveParametersFromContext(ac);

            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting params " + getParameterLogMap(parameters));
            }

            if (parameters != null) {
            	Map contextMap = ac.getContextMap();
                try {
                	ReflectionContextState.setCreatingNullObjects(contextMap, true);
                	ReflectionContextState.setDenyMethodExecution(contextMap, true);
                	ReflectionContextState.setReportingConversionErrors(contextMap, true);

                    ValueStack stack = ac.getValueStack();

                    setParameters(action, stack, parameters);


                } finally {
                	ReflectionContextState.setCreatingNullObjects(contextMap, false);
                	ReflectionContextState.setDenyMethodExecution(contextMap, false);
                	ReflectionContextState.setReportingConversionErrors(contextMap, false);
                }
            }
        }
        return invocation.invoke();
    }
 

 

会调用ognl中ValueStack的setParameter方法给action中parameter设值,通过setValue方法,

最后会调用 :

OgnlRunTime中的callappropriateMethod方法

public static Object callAppropriateMethod( OgnlContext context, Object source, Object target, String methodName, String propertyName, List methods, Object[] args ) throws MethodFailedException
    {
        Throwable   reason = null;
        Object[]    actualArgs = objectArrayPool.create(args.length);

        try {
            Method      method = getAppropriateMethod( context, source, target, methodName, propertyName, methods, args, actualArgs );

            if ( (method == null) || !isMethodAccessible(context, source, method, propertyName) )
            {
                StringBuffer        buffer = new StringBuffer();

                if (args != null) {
                    for (int i = 0, ilast = args.length - 1; i <= ilast; i++) {
                        Object      arg = args[i];

                        buffer.append((arg == null) ? NULL_STRING : arg.getClass().getName());
                        if (i < ilast) {
                            buffer.append(", "); //

主要原来自这里.在对args进行转换成strting的时候使用的是逗号加空格,
所以才导致转换后的集合中间会多一个空格.
                        }
                    }
                }

                throw new NoSuchMethodException( methodName + "(" + buffer + ")" );
            }
            return invokeMethod(target, method, actualArgs);
          }
        catch (NoSuchMethodException e)
          { reason = e; }
        catch (IllegalAccessException e)
          { reason = e; }
        catch (InvocationTargetException e)
          { reason = e.getTargetException(); }
        finally {
            objectArrayPool.recycle(actualArgs);
        }
        throw new MethodFailedException( source, methodName, reason );
    }

 终于找到问题的根源了.怎么来修改呢.我采取的方法是在setXXX方面中进行修改.

public void setDegree(String degree) {
        //1, 2, 3, 4   converte to 1,2,3,4
        String result = "";
        if(null != degree && !"".equals(degree)){
            String [] params = degree.split(",");
            if(params.length > 1){
                for(int i=0 ; i<params.length ; i++){
                    result += params[i].trim();

 //通过trim()方法来处理.
                    if( i < params.length - 1){
                        result += ",";
                    }
                }
            }
        }
        this.degree = result;
    }
 

总结:其实这样转换很麻烦,最好的解决办法是在属性中使用数组或者集合来接收请求中传递的多个相同的参数值.

分享到:
评论

相关推荐

    struts笔记

    类型转换是Struts2框架中的一个重要特性,它能够自动地将用户输入的数据转换为对应的Java数据类型。Struts2支持自定义类型转换器,可以实现更复杂的类型转换逻辑。 1. **全局配置**:可以在`xwork-conversion....

    struts2jar包和阿里巴巴开发手册

    Struts2是一个非常流行的开源MVC框架,它在Java Web开发中被广泛使用,用于构建高效、可扩展的Web应用程序。阿里巴巴,作为中国乃至全球知名的互联网企业,有着一套严格的开发规范,即阿里巴巴Java开发手册,这是一...

    struts-api.rar_struts api_字符 截取

    1. **substring()**:这是最常用的截取方法,接受两个参数,第一个参数是起始位置(包含),第二个参数是结束位置(不包含)。例如,`String str = "Hello, World!"; String subStr = str.substring(7, 12);` 结果为...

    Struts2验证框架的配置及validation.xml常用的验证规则

    Struts2是一款基于MVC设计模式的开源Java框架,它为Web应用开发提供了丰富的功能,包括请求处理、视图渲染以及表单验证等。在Struts2中,表单验证是一项重要的功能,它确保了用户输入的数据符合预期的格式和范围,...

    maven.docx教程

    它遵循“最接近原则”,即如果多个模块引用了相同依赖的不同版本,Maven会选择最近项目的依赖。此外,Maven还支持排除特定依赖,以解决具体问题。 3. Maven的项目构建: Maven提供了统一的项目构建生命周期,包括...

    JAVA-JSP学习笔记.doc

    2. **JSP页面间参数传递**:在多个JSP页面间传递参数,常用的方式是通过请求(request)或会话(session)对象。例如,`&lt;jsp:forward page="newPage.jsp"&gt;&lt;jsp:param name="paramName" value="paramValue"/&gt;&lt;/jsp:...

    Java工程师考试题(答案).pdf

    2. **接口实现**:一个类可以实现多个接口,语法为"class A implements B,C"。 3. **接口内容**:Java接口中可以定义常量和静态方法,但不能定义构造方法和抽象方法(因为所有接口方法默认都是抽象的)。 4. **构造...

    java 实现国际化 中英文语言切换

    Java 实现国际化是一种重要的软件开发技术,特别是在构建多语言支持的应用程序时。国际化(i18n)使得软件能够适应不同国家和地区的语言环境,包括中文和英文。在这个主题中,我们将深入探讨如何使用Java和JSP进行...

    Java工程师考试题(答案)文.pdf

    2. **接口实现**:在Java中,一个类可以实现多个接口,正确的语法是`class A implements B, C`。 3. **接口内容**:接口可以包含常量和抽象方法,但不能有静态方法、构造方法或实例方法。 4. **构造方法调用**:在...

    struts logic:iterater 换行

    3. 在迭代过程中,使用`&lt;logic:equal&gt;`标签根据当前迭代索引(由`indexId="i"`设置)进行判断,当索引`i`等于0时,添加多个空格作为水平间隔;当`i`等于1时,则插入换行符` `,从而实现每两个元素一行的布局效果...

    Java工程师考试题.docx

    2. **接口实现**:一个类可以实现多个接口,用逗号分隔,如`class A implements B, C`。 3. **接口内容**:接口中可以定义常量和静态方法,但不能包含构造方法和抽象方法。 4. **构造方法调用**:在类的构造方法中...

    Java工程师考试题答案.doc

    8. **Struts框架**:在Struts应用中,Action类的`execute`方法处理业务逻辑并返回一个字符串,控制权随后返回到result组件。 9. **多线程**:创建Java多线程有两种方式,即继承Thread类或实现Runnable接口。 10. *...

    JavaEE新开发规范文档

    - 当多个子模块需要调用相同的Action时,可以通过配置文件或依赖注入等方式进行管理。 **6. 关于Struts的forward配置** - Struts框架支持配置不同的forward来决定Action处理完成后转向哪个页面。 **7. 方法类中的...

    Java工程师考试题(答案)借鉴.pdf

    8. **Struts框架**:在Struts中,Action类的execute方法处理业务逻辑,返回一个String对象,控制权交给Result组件。 9. **多线程实现**:创建Java多线程有两种方式:继承Thread类或实现Runnable接口。 10. **JSP与...

    03-Form-Data-Chinese.pdf

    如果需要读取多个参数,可以使用`getParameterValues`方法: ```java String[] hobbies = request.getParameterValues("hobbies"); ``` ### 特殊情况处理 #### 数据缺失或异常 在实际应用中,可能会遇到用户未...

    java 常见的面试题

    22. **果冻问题**:至少需要抓3个果冻,因为前2个可能是不同颜色,第3个无论是什么颜色都会与前2个中的一个匹配。 以上就是Java面试中可能出现的一些常见问题及其详细解答。这些问题涵盖了语言基础、并发、框架、...

Global site tag (gtag.js) - Google Analytics