使用 REST 插件向 Struts2 发出 POST 请求未收到响应

发布于 2024-12-08 12:48:59 字数 494 浏览 0 评论 0原文

我有一个使用 struts2-rest-plugin v.2.2.3 的 struts2 应用程序。

当涉及到将请求路由到操作及其方法时,一切都运行良好,并且在使用 JSON 和 XML 等扩展时,我还使用 ModelDriven 来指定要序列化的对象。

我遇到的问题是,当我向 struts 层发送 POST 或 PUT 请求时,我只得到一个空响应。

我正在向操作发送 POST 请求,如下所示:http://localhost:8080/alert-settings!update.json。我在该方法中有一个断点,它被调用并且代码运行并完成。我有一种感觉,问题可能是我正在尝试使用 ModelDriven 接口向我发回响应,并且由于某种原因,rest-plugin 不喜欢这样,但我不知道为什么它会有这样的行为。

使用其余插件时接收 POST 请求的响应是否存在已知问题?我到处都找过了,但确实找不到任何相关信息。

感谢任何帮助,我可以根据要求提供更多详细信息。

I have a struts2 application which uses the struts2-rest-plugin v.2.2.3.

Everything is working great when it comes to the routing of the requests to the actions and its methods and I'm also using ModelDriven to specify the object to serialise when using extensions like JSON and XML.

The problem I'm having is that when I send a POST or PUT request to the struts layer I just get an empty response.

I am sending a POST request to the action like so: http://localhost:8080/alert-settings!update.json. I have a breakpoint in that method and it gets called and the code runs and completes. I have a feeling the issue might be that I am trying to use the ModelDriven interface to send me back the response and for some reason the rest-plugin doesn't like this but I don't know why it would behave like that.

Is there a known issue with receiving responses from POST requests while using the rest plugin? I have looked everywhere and can't find anything about it really.

Any help appreciated and I can provide any more details on request.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

時窥 2024-12-15 12:48:59

我遇到了同样的问题。您是否尝试在 struts.xml 文件中进行设置:

struts.rest.content.restrictToGET = false

请参阅 上的最后一个设置其余插件文档

I encountered the same issue. Have you tried to set in the struts.xml file:

struts.rest.content.restrictToGET = false

See the last setting on the rest plugin docs

沙沙粒小 2024-12-15 12:48:59

我实际上发现这是rest插件中的一行导致了这个:

// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
  target = null;
}

这是在selectTarget()方法中的org.apache.struts2.rest.RestActionInvocau中。我发现这很烦人,因为它并没有真正遵循 REST 架构,我喜欢在某些情况下能够为 POST、DELETE 和 PUT 请求返回响应对象的选项。

我通过扩展 RestActionProxyFactoryRestActionInvocation 并在我的 struts xml 中指定它的使用来解决这个问题,如下所示:

<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />

这允许我在 POST 上返回对象时始终使用 struts 插件请求。

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);
        }
    }

}

RestActionInspiration

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;
//      }
    }

}

I actually figured out that it was a line in the rest plugin causing this:

// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
  target = null;
}

This is in org.apache.struts2.rest.RestActionInvocation in the selectTarget() method. I find this to be quite annoying as it doesn't really follow the REST architecture, id like the option to be able to return response objects for POST, DELETE and PUT requests in some cases.

I worked around this by extending RestActionProxyFactory and RestActionInvocation and specifying the use of this in my struts xml like so:

<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />

This allows me to use the struts plugin throughout while returning object on POST requests.

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;
//      }
    }

}
夜未央樱花落 2024-12-15 12:48:59

我过去使用过具有混合结果类型的 struts 操作,例如返回 json、xml 和tiles。我不确定这是否是推荐的方法,但它需要使用 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>

我已经设置了稍后用于特定操作的额外结果类型。在操作类中,您可以通过操作或方法设置结果类型。

Action 类:

@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 结果,其 getter/setter 只返回 java 类型(String、int、Boolean 等),而不返回嵌入对象。我认为已经使用委托 getter/setter 解决了这个问题,但我必须回去查看一些旧代码。

I've used struts actions with mixed result types in the past, returning json, xml, and tiles for instance. I'm not sure if it's the recommended way to do it but it requires some configuration using struts.xml even though conventions are being used. Maybe you've already done this, not sure there isn't enough info provided to tell.

Struts.xml settings:

<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>

I have setup the extra result types to be used on specific actions later. In the action class you can then setup your result types by action or method.

Action Class:

@Results({
    @Result(name = "JsonSuccess", type = "json"),
    @Result(name = "success", type = "tiles", location = "/tickets.tiles")
})

public class EventController extends RestActionSupport implements ModelDriven<EventBean>{
     ...
}

Something else to note about json results, I've noticed that when I have a serializable object being returned as a result, if that object contains other complex objects with a getter/setter that returns the embedded object, I will often receive an empty result or no result. I often end up writing json wrapper objects to use for my json results with getters/setters that only return java types (String, int, Boolean, etc) and not the embedded objects. I think that've solved this using delegate getters/setters but I'll have to go back and look at some old code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文