Solicitud POST a Struts2 con el complemento REST sin respuesta
struts2-rest-plugin (3)
Tengo una aplicación struts2 que usa struts2-rest-plugin v.2.2.3.
Todo funciona muy bien cuando se trata de enrutar las solicitudes a las acciones y sus métodos, y también estoy usando ModelDriven para especificar el objeto a serializar cuando se usan extensiones como JSON y XML.
El problema que tengo es que cuando envío una solicitud POST o PUT a la capa de struts, obtengo una respuesta vacía.
Estoy enviando una solicitud POST a la acción de la siguiente manera: http://localhost:8080/alert-settings!update.json
. Tengo un punto de interrupción en ese método y se llama y el código se ejecuta y completa. Tengo la sensación de que el problema podría ser que estoy tratando de usar la interfaz ModelDriven para enviarme la respuesta y por alguna razón el resto del complemento no le gusta, pero no sé por qué se comportaría así.
¿Existe un problema conocido con la recepción de respuestas de solicitudes POST al usar el complemento de descanso? He buscado en todas partes y no puedo encontrar nada al respecto realmente.
Cualquier ayuda apreciada y puedo proporcionar más detalles a petición.
De hecho, descubrí que era una línea en el complemento de reposo que causaba esto:
// don''t return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
target = null;
}
Esto está en org.apache.struts2.rest.RestActionInvocation
en el método selectTarget()
. Encuentro esto bastante molesto ya que realmente no sigue la arquitectura REST, id como la opción de poder devolver los objetos de respuesta para las solicitudes POST, DELETE y PUT en algunos casos.
Trabajé alrededor de esto extendiendo RestActionProxyFactory
y RestActionInvocation
y especificando el uso de esto en my struts xml así:
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />
Esto me permite utilizar el plugin Struts en todo mientras devuelvo el objeto en las solicitudes POST.
RestActionProxyFactory
public class RPRestActionProxyFactory extends RestActionProxyFactory {
@Override
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
if (namespace.startsWith(this.namespace)) {
ActionInvocation inv = new RPRestActionInvocation(extraContext, true);
container.inject(inv);
return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
} else {
return super.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
}
}
}
RestActionInvocation
public class RPRestActionInvocation extends RestActionInvocation {
public RPRestActionInvocation(Map extraContext, boolean pushAction) {
super(extraContext, pushAction);
}
@SuppressWarnings("unchecked")
@Override
protected void selectTarget() {
// Select target (content to return)
Throwable e = (Throwable)stack.findValue("exception");
if (e != null) {
// Exception
target = e;
hasErrors = true;
} else if (action instanceof ValidationAware && ((ValidationAware)action).hasErrors()) {
// Error messages
ValidationAware validationAwareAction = ((ValidationAware)action);
Map errors = new HashMap();
if (validationAwareAction.getActionErrors().size() > 0) {
errors.put("actionErrors", validationAwareAction.getActionErrors());
}
if (validationAwareAction.getFieldErrors().size() > 0) {
errors.put("fieldErrors", validationAwareAction.getFieldErrors());
}
target = errors;
hasErrors = true;
} else if (action instanceof ModelDriven) {
// Model
target = ((ModelDriven)action).getModel();
} else {
target = action;
}
// don''t return any content for PUT, DELETE, and POST where there are no errors
// if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
// target = null;
// }
}
}
He utilizado acciones de struts con tipos de resultados mixtos en el pasado, y he devuelto json, xml y tiles, por ejemplo. No estoy seguro de si es la forma recomendada de hacerlo, pero requiere alguna configuración con struts.xml aunque se estén utilizando convenciones. Tal vez ya lo haya hecho, no estoy seguro de que no haya suficiente información para contar.
Configuración de Struts.xml:
<constant name="struts.convention.default.parent.package" value="restful"/>
<package name="restful" extends="rest-default, struts-default, json-default">
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
<result-type name="json" class="com.googlecode.jsonplugin.JSONResult"/>
</result-types>
....
</package>
He configurado los tipos de resultados adicionales para usar en acciones específicas más adelante. En la clase de acción, puede configurar sus tipos de resultados por acción o método.
Clase de acción:
@Results({
@Result(name = "JsonSuccess", type = "json"),
@Result(name = "success", type = "tiles", location = "/tickets.tiles")
})
public class EventController extends RestActionSupport implements ModelDriven<EventBean>{
...
}
Algo más que destacar sobre los resultados de json, me he dado cuenta de que cuando tengo un objeto serializable que se devuelve como resultado, si ese objeto contiene otros objetos complejos con un getter / setter que devuelve el objeto incrustado, a menudo recibiré un resultado vacío o sin resultado A menudo termino escribiendo objetos json wrapper para usar en mis resultados json con getters / setters que solo devuelven tipos java (String, int, boolean, etc.) y no los objetos incrustados. Creo que he resuelto esto utilizando deleters / setters delegados, pero tendré que volver atrás y mirar algún código antiguo.
Me encontré con el mismo problema. ¿Has intentado establecer en el archivo struts.xml:
struts.rest.content.restrictToGET = false
Ver la última configuración en el resto de los documentos del complemento