Intentando algo sencillo como cargar un formulario de Spring MVC y haciendo uso de etiquetas de Spring (documentación aquí). El código Java que accedía a la página es este:
@RequestMapping( value = "/goToJsp", method = RequestMethod.GET )
public String goToJsp( ) {
return "pageToGo";
}
Bastante sencillo todo, pero por alguna razón al intentar cargar la página daba la siguiente excepción:
SEVERE: Neither BindingResult nor plain target object for bean name ‘exampleForm’ available as request attribute
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name ‘exampleForm’ available as request attribute
¿Donde esta el problema? En la configuración de la etiqueta Spring form. En ella se indica cual es el modelo que esta detrás del formulario y en el cual se recogerán los campos del mismo. Por tanto, cuando hacemos esta asociación antes de acceder a la página debemos asociar este objeto. Ya que de otra forma desconoce la clase asociada a los campos del formulario. Por tanto la solución estaría en el código Java y se implementaría así:
@RequestMapping( value = "/goToJsp", method = RequestMethod.GET )
public String goToJsp(final Model model ) {
model.addAttribute( "exampleForm", new ExampleForm() );
return "pageToGo";
}
Un component en Struts 2 no es más que la propia API con la que cuentan ellos para la creación de taglibs. Esto nos servirá para poder hacer cierta lógica en las JSP evitando el uso de scriptlets.
Este ejemplo sencillo pintará 'checked' o '' según el valor de una variable booleana pasada.
Para empezar creamos la clase que heredará de Component. En esta clase realizaremos la lógica dentro del método start y con el objeto Writer mandaremos a la capa de vista los valores deseados.
package es.home.example.component;
import java.io.IOException;
import java.io.Writer;
import org.apache.struts2.components.Component;
import es.home.example.constants.GeneralConstants;
import com.opensymphony.xwork2.util.ValueStack;
public class CheckField extends Component {
protected String value;
public CheckField(final ValueStack stack) {
super(stack);
}
public boolean end(final Writer writer) {
return true;
}
public final String getValue() {
return value;
}
public final void setValue(final String value) {
this.value = value;
}
@Override
public boolean start(final Writer writer) {
try {
if (Boolean.TRUE.toString().equals(value)) {
writer.write(GeneralConstants.CHECKED);
} else {
writer.write(GeneralConstants.BLANK);
}
} catch (IOException except) {
except.printStackTrace();
}
return true;
}
@Override
public boolean usesBody() {
return false;
}
}
Por otro lado creamos una clase que extienda de ComponentTagSupport, esto nos permitirá usar la lógica antes indicada como taglib. Los dos métodos esenciales a implementar son getBean y populateParams.
package es.home.example.component.tag;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ComponentTagSupport;
import es.home.example.component.CheckField;
import com.opensymphony.xwork2.util.ValueStack;
public class CheckFieldTag extends ComponentTagSupport {
private static final long serialVersionUID = 1L;
protected String value;
@Override
public Component getBean(final ValueStack stack, final HttpServletRequest req, final HttpServletResponse res) {
return new CheckField(stack);
}
public final String getValue() {
return value;
}
@Override
protected void populateParams() {
super.populateParams();
((CheckField) component).setValue(value);
}
public final void setValue(final String value) {
this.value = value;
}
}
Si queremos usar el taglib necesitamos crear su fichero tld específico. Este fichero debe ser incluido dentro de la carpeta META-INF/ para que sea reconocido automáticamente por la aplicación.
2.2.31.2customComponentes/home/example/customComponentCustom Components<![CDATA["cc"]]>checkFieldes.home.example.component.tag.CheckFieldTagJSP<![CDATA[Render a checked string]]>valuetruetrue
<![CDATA[Value of the field]]>
Por último ya solo queda utilizarlo en nuestra página JSP, tal y como vemos en el ejemplo