POST-запрос к Struts2 с плагином REST, не получающим ответ
У меня есть приложение Struts2, которое использует Struts2-Rest-плагин v.2.2.3.
Все отлично работает, когда дело доходит до маршрутизации запросов к действиям и их методам, и я также использую ModelDriven, чтобы указать объект для сериализации при использовании расширений, таких как JSON и XML.
У меня проблема в том, что когда я отправляю запрос POST или PUT на слой Struts, я просто получаю пустой ответ.
Я отправляю запрос POST к действию следующим образом: http://localhost:8080/alert-settings!update.json
, У меня есть точка останова в этом методе, и он вызывается, и код выполняется и завершается. У меня есть ощущение, что проблема может заключаться в том, что я пытаюсь использовать интерфейс ModelDriven, чтобы отправить мне ответ, и по какой-то причине плагину rest это не нравится, но я не знаю, почему он будет себя так вести.
Известна ли проблема с получением ответов от запросов POST при использовании плагина rest? Я искал повсюду и ничего не могу найти по этому поводу.
Любая помощь приветствуется, и я могу предоставить более подробную информацию по запросу.
3 ответа
Я столкнулся с той же проблемой. Вы пытались установить в файле struts.xml:
struts.rest.content.restrictToGET = false
Смотрите последние настройки на остальных плагин документации
Я на самом деле понял, что это была строка в плагине отдыха, вызывающая это:
// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
target = null;
}
Это в org.apache.struts2.rest.RestActionInvocation
в selectTarget()
метод. Я нахожу это довольно раздражающим, так как он на самом деле не следует архитектуре REST, например, возможность в некоторых случаях возвращать объекты ответа для запросов POST, DELETE и PUT.
Я работал над этим, расширяя RestActionProxyFactory
а также RestActionInvocation
и указав использование этого в моих стояках xml, вот так:
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />
Это позволяет мне использовать плагин struts повсюду, возвращая объект по запросам 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;
// }
}
}
В прошлом я использовал действия Struts со смешанными типами результатов, например, возвращая json, xml и тайлы. Я не уверен, является ли это рекомендуемым способом сделать это, но он требует некоторой конфигурации с использованием struts.xml, даже если используются соглашения. Возможно, вы уже сделали это, но не уверены, что недостаточно информации, чтобы рассказать.
Настройки 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>
Я настроил дополнительные типы результатов, которые будут использоваться для определенных действий позже. В классе действий вы можете настроить типы результатов с помощью действия или метода.
Класс действий:
@Results({
@Result(name = "JsonSuccess", type = "json"),
@Result(name = "success", type = "tiles", location = "/tickets.tiles")
})
public class EventController extends RestActionSupport implements ModelDriven<EventBean>{
...
}
Что еще следует отметить в отношении результатов json, я заметил, что когда у меня есть возвращаемый в результате сериализуемый объект, если этот объект содержит другие сложные объекты с getter/setter, который возвращает внедренный объект, я часто получаю пустой результат или нет результата. Я часто заканчиваю тем, что пишу объекты-обертки json для использования с результатами json с помощью методов получения / установки, которые возвращают только типы java (String, int, Boolean и т. Д.), А не внедренные объекты. Я думаю, что это решено с использованием делегатов getter/setters, но мне придется вернуться и посмотреть на старый код.