SPR-7943 Add interface for HDIV integration and delegate to it from JSP form tags.
This commit is contained in:
@@ -20,12 +20,14 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.jsp.jstl.core.Config;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
@@ -80,6 +82,12 @@ public class RequestContext {
|
||||
*/
|
||||
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = RequestContext.class.getName() + ".CONTEXT";
|
||||
|
||||
/**
|
||||
* The name of the bean to use to look up in an implementation of
|
||||
* {@link RequestDataValueProcessor} has been configured.
|
||||
*/
|
||||
private static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor";
|
||||
|
||||
protected static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config",
|
||||
RequestContext.class.getClassLoader());
|
||||
|
||||
@@ -99,6 +107,8 @@ public class RequestContext {
|
||||
|
||||
private UrlPathHelper urlPathHelper;
|
||||
|
||||
private RequestDataValueProcessor requestDataValueProcessor;
|
||||
|
||||
private Map<String, Errors> errorsMap;
|
||||
|
||||
/**
|
||||
@@ -212,8 +222,16 @@ public class RequestContext {
|
||||
this.defaultHtmlEscape = WebUtils.getDefaultHtmlEscape(this.webApplicationContext.getServletContext());
|
||||
|
||||
this.urlPathHelper = new UrlPathHelper();
|
||||
}
|
||||
|
||||
try {
|
||||
this.requestDataValueProcessor = this.webApplicationContext.getBean(
|
||||
REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME, RequestDataValueProcessor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the fallback locale for this context. <p>The default implementation checks for a JSTL locale attribute
|
||||
* in request, session or application scope; if not found, returns the <code>HttpServletRequest.getLocale()</code>.
|
||||
@@ -347,6 +365,15 @@ public class RequestContext {
|
||||
return this.urlPathHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RequestDataValueProcessor instance to use obtained from the
|
||||
* WebApplicationContext under the name {@code "requestDataValueProcessor"}.
|
||||
* Or {@code null} if no matching bean was found.
|
||||
*/
|
||||
public RequestDataValueProcessor getRequestDataValueProcessor() {
|
||||
return this.requestDataValueProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context path of the original request, that is, the path that indicates the current web application.
|
||||
* This is useful for building links to other resources within the application. <p>Delegates to the UrlPathHelper
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.web.servlet.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* A contract for inspecting and potentially modifying request data values such
|
||||
* as URL query parameters or form field values before they are rendered by a
|
||||
* view or before a redirect.
|
||||
*
|
||||
* <p>Implementations may use this contract for example as part of a solution
|
||||
* to provide data integrity, confidentiality, protection against cross-site
|
||||
* request forgery (CSRF), and others or for other tasks such as automatically
|
||||
* adding a hidden field to all forms and URLs.
|
||||
*
|
||||
* <p>View technologies that support this contract can obtain an instance to
|
||||
* delegate to via {@link RequestContext#getRequestDataValueProcessor()}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface RequestDataValueProcessor {
|
||||
|
||||
/**
|
||||
* Invoked when a new form action is rendered.
|
||||
* @param request the current request
|
||||
* @param action the form action
|
||||
* @return the action to use, possibly modified
|
||||
*/
|
||||
String processAction(HttpServletRequest request, String action);
|
||||
|
||||
/**
|
||||
* Invoked when a form field value is rendered.
|
||||
* @param request the current request
|
||||
* @param name the form field name
|
||||
* @param value the form field value
|
||||
* @param type the form field type ("text", "hidden", etc.)
|
||||
* @return the form field value to use, possibly modified
|
||||
*/
|
||||
String processFormFieldValue(HttpServletRequest request, String name, String value, String type);
|
||||
|
||||
/**
|
||||
* Invoked after all form fields have been rendered.
|
||||
* @param request the current request
|
||||
* @return additional hidden form fields to be added, or {@code null}
|
||||
*/
|
||||
Map<String, String> getExtraHiddenFields(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Invoked when a URL is about to be rendered or redirected to.
|
||||
* @param request the current request
|
||||
* @param url the URL value
|
||||
* @return the URL to use, possibly modified
|
||||
*/
|
||||
String processUrl(HttpServletRequest request, String url);
|
||||
|
||||
}
|
||||
@@ -22,12 +22,15 @@ import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.util.ExpressionEvaluationUtils;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
import org.springframework.web.util.JavaScriptUtils;
|
||||
@@ -168,6 +171,13 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
|
||||
@Override
|
||||
public int doEndTag() throws JspException {
|
||||
String url = createUrl();
|
||||
|
||||
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
||||
ServletRequest request = this.pageContext.getRequest();
|
||||
if ((processor != null) && (request instanceof HttpServletRequest)) {
|
||||
url = processor.processUrl((HttpServletRequest) request, url);
|
||||
}
|
||||
|
||||
if (this.var == null) {
|
||||
// print the url to the writer
|
||||
try {
|
||||
|
||||
@@ -44,7 +44,8 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
|
||||
* bound value.
|
||||
*/
|
||||
protected void renderFromValue(Object item, Object value, TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeAttribute("value", convertToDisplayString(value));
|
||||
String displayValue = convertToDisplayString(value);
|
||||
tagWriter.writeAttribute("value", processFieldValue(getName(), displayValue, getInputType()));
|
||||
if (isOptionSelected(value) || (value != item && isOptionSelected(item))) {
|
||||
tagWriter.writeAttribute("checked", "checked");
|
||||
}
|
||||
@@ -64,7 +65,7 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
|
||||
* <code>true</code>.
|
||||
*/
|
||||
protected void renderFromBoolean(Boolean boundValue, TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeAttribute("value", "true");
|
||||
tagWriter.writeAttribute("value", processFieldValue(getName(), "true", getInputType()));
|
||||
if (boundValue) {
|
||||
tagWriter.writeAttribute("checked", "checked");
|
||||
}
|
||||
@@ -87,4 +88,10 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
|
||||
@Override
|
||||
protected abstract int writeTagContent(TagWriter tagWriter) throws JspException;
|
||||
|
||||
/**
|
||||
* Return the type of the HTML input element to generate:
|
||||
* "checkbox" or "radio".
|
||||
*/
|
||||
protected abstract String getInputType();
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
package org.springframework.web.servlet.tags.form;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
|
||||
@@ -24,6 +27,7 @@ import org.springframework.beans.PropertyAccessor;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.support.BindStatus;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.servlet.tags.EditorAwareTag;
|
||||
import org.springframework.web.servlet.tags.NestedPathTag;
|
||||
|
||||
@@ -227,6 +231,18 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
|
||||
return getDisplayString(value, editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given form field through a {@link RequestDataValueProcessor}
|
||||
* instance if one is configured or otherwise returns the same value.
|
||||
*/
|
||||
protected final String processFieldValue(String name, String value, String type) {
|
||||
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
||||
ServletRequest request = this.pageContext.getRequest();
|
||||
if (processor != null && (request instanceof HttpServletRequest)) {
|
||||
value = processor.processFormFieldValue((HttpServletRequest) request, name, value, type);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of the {@link BindStatus} instance.
|
||||
|
||||
@@ -291,10 +291,4 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
|
||||
tagWriter.endTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the HTML input element to generate:
|
||||
* "checkbox" or "radio".
|
||||
*/
|
||||
protected abstract String getInputType();
|
||||
|
||||
}
|
||||
|
||||
@@ -55,8 +55,9 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag {
|
||||
// Write out the 'field was present' marker.
|
||||
tagWriter.startTag("input");
|
||||
tagWriter.writeAttribute("type", "hidden");
|
||||
tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName());
|
||||
tagWriter.writeAttribute("value", "on");
|
||||
String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName();
|
||||
tagWriter.writeAttribute("name", name);
|
||||
tagWriter.writeAttribute("value", processFieldValue(name, "on", getInputType()));
|
||||
tagWriter.endTag();
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag {
|
||||
|
||||
@Override
|
||||
protected void writeTagDetails(TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeAttribute("type", "checkbox");
|
||||
tagWriter.writeAttribute("type", getInputType());
|
||||
|
||||
Object boundValue = getBoundValue();
|
||||
Class valueType = getBindStatus().getValueType();
|
||||
@@ -89,4 +90,9 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInputType() {
|
||||
return "checkbox";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ public class CheckboxesTag extends AbstractMultiCheckedElementTag {
|
||||
// Write out the 'field was present' marker.
|
||||
tagWriter.startTag("input");
|
||||
tagWriter.writeAttribute("type", "hidden");
|
||||
tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName());
|
||||
tagWriter.writeAttribute("value", "on");
|
||||
String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName();
|
||||
tagWriter.writeAttribute("name", name);
|
||||
tagWriter.writeAttribute("value", processFieldValue(name, "on", getInputType()));
|
||||
tagWriter.endTag();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
package org.springframework.web.servlet.tags.form;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
@@ -25,6 +29,7 @@ import org.springframework.beans.PropertyAccessor;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
/**
|
||||
@@ -393,7 +398,8 @@ public class FormTag extends AbstractHtmlElementTag {
|
||||
protected String resolveAction() throws JspException {
|
||||
String action = getAction();
|
||||
if (StringUtils.hasText(action)) {
|
||||
return getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
|
||||
action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
|
||||
return processAction(action);
|
||||
}
|
||||
else {
|
||||
String requestUri = getRequestContext().getRequestUri();
|
||||
@@ -406,7 +412,7 @@ public class FormTag extends AbstractHtmlElementTag {
|
||||
}
|
||||
}
|
||||
if (StringUtils.hasText(requestUri)) {
|
||||
return requestUri;
|
||||
return processAction(requestUri);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Attribute 'action' is required. " +
|
||||
@@ -415,6 +421,18 @@ public class FormTag extends AbstractHtmlElementTag {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the action through a {@link RequestDataValueProcessor} instance
|
||||
* if one is configured or otherwise returns the action unmodified.
|
||||
*/
|
||||
private String processAction(String action) {
|
||||
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
||||
ServletRequest request = this.pageContext.getRequest();
|
||||
if ((processor != null) && (request instanceof HttpServletRequest)) {
|
||||
action = processor.processAction((HttpServletRequest) request, action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the '<code>form</code>' block tag and removes the form object name
|
||||
@@ -422,10 +440,28 @@ public class FormTag extends AbstractHtmlElementTag {
|
||||
*/
|
||||
@Override
|
||||
public int doEndTag() throws JspException {
|
||||
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
||||
ServletRequest request = this.pageContext.getRequest();
|
||||
if ((processor != null) && (request instanceof HttpServletRequest)) {
|
||||
writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request));
|
||||
}
|
||||
this.tagWriter.endTag();
|
||||
return EVAL_PAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given values as hidden fields.
|
||||
*/
|
||||
private void writeHiddenFields(Map<String, String> hiddenFields) throws JspException {
|
||||
if (hiddenFields != null) {
|
||||
for (String name : hiddenFields.keySet()) {
|
||||
this.tagWriter.appendValue("<input type=\"hidden\" ");
|
||||
this.tagWriter.appendValue("name=\"" + name + "\" value=\"" + hiddenFields.get(name) + "\" ");
|
||||
this.tagWriter.appendValue("</input>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the stored {@link TagWriter}.
|
||||
*/
|
||||
|
||||
@@ -44,9 +44,10 @@ public class HiddenInputTag extends AbstractHtmlElementTag {
|
||||
tagWriter.startTag("input");
|
||||
writeDefaultAttributes(tagWriter);
|
||||
tagWriter.writeAttribute("type", "hidden");
|
||||
tagWriter.writeAttribute("value", getDisplayString(getBoundValue(), getPropertyEditor()));
|
||||
String value = getDisplayString(getBoundValue(), getPropertyEditor());
|
||||
tagWriter.writeAttribute("value", processFieldValue(getName(), value, "hidden"));
|
||||
tagWriter.endTag();
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
package org.springframework.web.servlet.tags.form;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
|
||||
/**
|
||||
* Data-binding-aware JSP tag for rendering an HTML '<code>input</code>'
|
||||
* element with a '<code>type</code>' of '<code>text</code>'.
|
||||
@@ -158,7 +162,8 @@ public class InputTag extends AbstractHtmlInputElementTag {
|
||||
* when the value is written.
|
||||
*/
|
||||
protected void writeValue(TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeAttribute("value", getDisplayString(getBoundValue(), getPropertyEditor()));
|
||||
String value = getDisplayString(getBoundValue(), getPropertyEditor());
|
||||
tagWriter.writeAttribute("value", processFieldValue(getName(), value, getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -207,6 +207,7 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
|
||||
writeOptionalAttribute(tagWriter, "id", resolveId());
|
||||
writeOptionalAttributes(tagWriter);
|
||||
String renderedValue = getDisplayString(value, getBindStatus().getEditor());
|
||||
renderedValue = processFieldValue(getSelectTag().getName(), renderedValue, "option");
|
||||
tagWriter.writeAttribute(VALUE_ATTRIBUTE, renderedValue);
|
||||
if (isSelected(value)) {
|
||||
tagWriter.writeAttribute(SELECTED_ATTRIBUTE, SELECTED_ATTRIBUTE);
|
||||
@@ -238,6 +239,10 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
|
||||
private void assertUnderSelectTag() {
|
||||
TagUtils.assertHasAncestorOfType(this, SelectTag.class, "option", "select");
|
||||
}
|
||||
|
||||
private SelectTag getSelectTag() {
|
||||
return (SelectTag) findAncestorWithClass(this, SelectTag.class);
|
||||
}
|
||||
|
||||
private boolean isSelected(Object resolvedValue) {
|
||||
return SelectedValueComparator.isSelected(getBindStatus(), resolvedValue);
|
||||
|
||||
@@ -19,13 +19,19 @@ package org.springframework.web.servlet.tags.form;
|
||||
import java.beans.PropertyEditor;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.servlet.support.BindStatus;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
|
||||
/**
|
||||
* Provides supporting functionality to render a list of '<code>option</code>'
|
||||
@@ -222,6 +228,8 @@ class OptionWriter {
|
||||
|
||||
String valueDisplayString = getDisplayString(value);
|
||||
String labelDisplayString = getDisplayString(label);
|
||||
|
||||
valueDisplayString = processOptionValue(valueDisplayString);
|
||||
|
||||
// allows render values to handle some strange browser compat issues.
|
||||
tagWriter.writeAttribute("value", valueDisplayString);
|
||||
@@ -245,6 +253,14 @@ class OptionWriter {
|
||||
return ValueFormatter.getDisplayString(value, editor, this.htmlEscape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the option value before it is written.
|
||||
* The default implementation simply returns the same value unchanged.
|
||||
*/
|
||||
protected String processOptionValue(String resolvedValue) {
|
||||
return resolvedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the supplied values matched the selected value.
|
||||
* Delegates to {@link SelectedValueComparator#isSelected}.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.tags.form;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -145,26 +146,26 @@ public class OptionsTag extends AbstractHtmlElementTag {
|
||||
|
||||
@Override
|
||||
protected int writeTagContent(TagWriter tagWriter) throws JspException {
|
||||
assertUnderSelectTag();
|
||||
SelectTag selectTag = getSelectTag();
|
||||
Object items = getItems();
|
||||
Object itemsObject = null;
|
||||
if (items != null) {
|
||||
itemsObject = (items instanceof String ? evaluate("items", items) : items);
|
||||
} else {
|
||||
Class<?> selectTagBoundType = ((SelectTag) findAncestorWithClass(this, SelectTag.class))
|
||||
.getBindStatus().getValueType();
|
||||
Class<?> selectTagBoundType = selectTag.getBindStatus().getValueType();
|
||||
if (selectTagBoundType != null && selectTagBoundType.isEnum()) {
|
||||
itemsObject = selectTagBoundType.getEnumConstants();
|
||||
}
|
||||
}
|
||||
if (itemsObject != null) {
|
||||
String selectName = selectTag.getName();
|
||||
String itemValue = getItemValue();
|
||||
String itemLabel = getItemLabel();
|
||||
String valueProperty =
|
||||
(itemValue != null ? ObjectUtils.getDisplayString(evaluate("itemValue", itemValue)) : null);
|
||||
String labelProperty =
|
||||
(itemLabel != null ? ObjectUtils.getDisplayString(evaluate("itemLabel", itemLabel)) : null);
|
||||
OptionsWriter optionWriter = new OptionsWriter(itemsObject, valueProperty, labelProperty);
|
||||
OptionsWriter optionWriter = new OptionsWriter(selectName, itemsObject, valueProperty, labelProperty);
|
||||
optionWriter.writeOptions(tagWriter);
|
||||
}
|
||||
return SKIP_BODY;
|
||||
@@ -184,8 +185,9 @@ public class OptionsTag extends AbstractHtmlElementTag {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void assertUnderSelectTag() {
|
||||
private SelectTag getSelectTag() {
|
||||
TagUtils.assertHasAncestorOfType(this, SelectTag.class, "options", "select");
|
||||
return (SelectTag) findAncestorWithClass(this, SelectTag.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,9 +200,12 @@ public class OptionsTag extends AbstractHtmlElementTag {
|
||||
* Inner class that adapts OptionWriter for multiple options to be rendered.
|
||||
*/
|
||||
private class OptionsWriter extends OptionWriter {
|
||||
|
||||
private final String selectName;
|
||||
|
||||
public OptionsWriter(Object optionSource, String valueProperty, String labelProperty) {
|
||||
public OptionsWriter(String selectName, Object optionSource, String valueProperty, String labelProperty) {
|
||||
super(optionSource, getBindStatus(), valueProperty, labelProperty, isHtmlEscape());
|
||||
this.selectName = selectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,6 +218,12 @@ public class OptionsTag extends AbstractHtmlElementTag {
|
||||
writeOptionalAttribute(tagWriter, "id", resolveId());
|
||||
writeOptionalAttributes(tagWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String processOptionValue(String value) {
|
||||
return processFieldValue(this.selectName, value, "option");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class PasswordInputTag extends InputTag {
|
||||
if (this.showPassword) {
|
||||
super.writeValue(tagWriter);
|
||||
} else {
|
||||
tagWriter.writeAttribute("value", "");
|
||||
tagWriter.writeAttribute("value", processFieldValue(getName(), "", getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,14 @@ public class RadioButtonTag extends AbstractSingleCheckedElementTag {
|
||||
|
||||
@Override
|
||||
protected void writeTagDetails(TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeAttribute("type", "radio");
|
||||
tagWriter.writeAttribute("type", getInputType());
|
||||
Object resolvedValue = evaluate("value", getValue());
|
||||
renderFromValue(resolvedValue, tagWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInputType() {
|
||||
return "radio";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags.form;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -207,12 +208,17 @@ public class SelectTag extends AbstractHtmlInputElementTag {
|
||||
if (items != EMPTY) {
|
||||
Object itemsObject = evaluate("items", items);
|
||||
if (itemsObject != null) {
|
||||
final String selectName = getName();
|
||||
String valueProperty = (getItemValue() != null ?
|
||||
ObjectUtils.getDisplayString(evaluate("itemValue", getItemValue())) : null);
|
||||
String labelProperty = (getItemLabel() != null ?
|
||||
ObjectUtils.getDisplayString(evaluate("itemLabel", getItemLabel())) : null);
|
||||
OptionWriter optionWriter =
|
||||
new OptionWriter(itemsObject, getBindStatus(), valueProperty, labelProperty, isHtmlEscape());
|
||||
new OptionWriter(itemsObject, getBindStatus(), valueProperty, labelProperty, isHtmlEscape()) {
|
||||
protected String processOptionValue(String resolvedValue) {
|
||||
return processFieldValue(selectName, resolvedValue, "option");
|
||||
}
|
||||
};
|
||||
optionWriter.writeOptions(tagWriter);
|
||||
}
|
||||
}
|
||||
@@ -238,8 +244,9 @@ public class SelectTag extends AbstractHtmlInputElementTag {
|
||||
if (isMultiple()) {
|
||||
tagWriter.startTag("input");
|
||||
tagWriter.writeAttribute("type", "hidden");
|
||||
tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName());
|
||||
tagWriter.writeAttribute("value", "1");
|
||||
String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName();
|
||||
tagWriter.writeAttribute("name", name);
|
||||
tagWriter.writeAttribute("value", processFieldValue(name, "1", "hidden"));
|
||||
tagWriter.endTag();
|
||||
}
|
||||
}
|
||||
@@ -305,5 +312,5 @@ public class SelectTag extends AbstractHtmlInputElementTag {
|
||||
this.tagWriter = null;
|
||||
this.pageContext.removeAttribute(LIST_VALUE_PAGE_ATTRIBUTE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -96,7 +96,8 @@ public class TextareaTag extends AbstractHtmlInputElementTag {
|
||||
writeOptionalAttribute(tagWriter, ROWS_ATTRIBUTE, getRows());
|
||||
writeOptionalAttribute(tagWriter, COLS_ATTRIBUTE, getCols());
|
||||
writeOptionalAttribute(tagWriter, ONSELECT_ATTRIBUTE, getOnselect());
|
||||
tagWriter.appendValue(getDisplayString(getBoundValue(), getPropertyEditor()));
|
||||
String value = getDisplayString(getBoundValue(), getPropertyEditor());
|
||||
tagWriter.appendValue(processFieldValue(getName(), value, "textarea"));
|
||||
tagWriter.endTag();
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,9 @@ import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.SmartView;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
@@ -228,6 +230,14 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* An ApplicationContext is not strictly required for RedirectView.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isContextRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert model to request parameters and redirect to the given URL.
|
||||
* @see #appendQueryProperties
|
||||
@@ -240,6 +250,14 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView {
|
||||
|
||||
String targetUrl = createTargetUrl(model, request);
|
||||
|
||||
if (getWebApplicationContext() != null) {
|
||||
RequestContext requestContext = createRequestContext(request, response, model);
|
||||
RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor();
|
||||
if (processor != null) {
|
||||
targetUrl = processor.processUrl(request, targetUrl);
|
||||
}
|
||||
}
|
||||
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
|
||||
if (!CollectionUtils.isEmpty(flashMap)) {
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build();
|
||||
|
||||
Reference in New Issue
Block a user