Using JSON-RPC in Struts2

2019-05-28 18:51发布

问题:

I use the following JavaScript/jQuery function to make a remote procedure call.

<script src="../js/jquery-1.8.0.min.js" type="text/javascript"></script>
<s:url var="testJsonUrl" action="testJsonAction"/>

var timeout;
var request;

$(document).ready(function(){
    $("#btnUser").click(function(){
        if(!request)
        {
            request = $.ajax({
                datatype:"json",
                type: "GET",
                data: JSON.stringify({jsonrpc:'2.0', method:'getUser', id:'jsonrpc'}),
                contentType: "application/json-rpc; charset=utf-8",
                url: "<s:property value='#testJsonUrl'/>",
                success: function(response)
                {
                    var user = response.result;
                    alert(JSON.stringify(user));  //Always alerts "undefined".
                },
                complete: function()
                {
                    timeout = request = null;
                },
                error: function(request, status, error)
                {
                    if(status!=="timeout"&&status!=="abort")
                    {
                        alert(status+" : "+error);
                    }
                }
            });
            timeout = setTimeout(function() {
                if(request)
                {
                    request.abort();
                    alert("The request has been timed out.");
                }
            }, 30000);
        }
    });
});

The above function is called, when a button is clicked as follows.

<s:form namespace="/admin_side" action="Test" validate="true" id="dataForm" name="dataForm">
    <input type="button" name="btnUser" id="btnUser" value="Click"/>
</s:form>

The action class in which the method is to be invoked is as follows.

import com.opensymphony.xwork2.ActionSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
import org.apache.struts2.json.annotations.SMDMethod;
import util.User;

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "json-default")
public final class TestAction extends ActionSupport
{
    private User user;

    public TestAction() {}

    @SMDMethod
    public User getUser()
    {
        user = new User();
        user.setName("Tiny");
        user.setLocation("India");

        try {
            user.setDob(new SimpleDateFormat("dd-MMM-YYYY").parse("29-Feb-2000"));
        } catch (ParseException ex) {
            Logger.getLogger(TestAction.class.getName()).log(Level.SEVERE, null, ex);
        }
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Action(value = "testJsonAction",
    results = {
        @Result(type = "json", params = {"enableSMD", "true", "excludeNullProperties", "true"})},
    interceptorRefs = {
        @InterceptorRef(value = "json", params = {"enableSMD", "true"})})
    public String executeAction() throws Exception {
        return SUCCESS;
    }

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "defaultStack", params = {"params.acceptParamNames", "", "params.excludeMethods", "load", "validation.validateAnnotatedMethodOnly", "true"})})
    public String load() throws Exception {
        //This method is just needed to return a view on page load.
        return ActionSupport.SUCCESS;
    }
}

The User class:

public class User
{
    private String name;
    private Date dob;
    private String location;

    //Setters & getters.
}

The getUser() method (in the action class TestAction) annotated with @SMDMethod is expected to be invoked, when the given button is clicked but it does not.

This line alert(JSON.stringify(user)); in the success handler of the jQuery function always alerts undefined.

Using a direct link in the address bar like,

http://localhost:8080/TestStruts/admin_side/testJsonAction.action

returns the following string.

{
    "methods": [{
        "name": "getUser",
        "parameters": []
    }],

    "serviceType": "JSON-RPC",
    "serviceUrl": "\/TestStruts\/admin_side\/testJsonAction.action",
    "version": ".1"
}

What is missing here? Why does not JSON-RPC work?

PS : I'm using Struts2-json-plugin-2.3.16 with same version of the framework.

回答1:

Is it mandatory to have only the POST request while using JSON-RPC?

yes, it only works with POST request

Also includeProperties has no effect

includeProperties has effect if it's a parameter to json interceptor. Don't confuse the name of parameter used with json result.

the field dob in this case, should have been excluded

In this case better to use excludeProperties parameter to interceptor, like this

@Action(value = "testJsonAction",
results = {
    @Result(type = "json", params = {"enableSMD", "true"})},
interceptorRefs = {
    @InterceptorRef(value = "json", params = {"enableSMD", "true", "excludeProperties", "result\\.dob"})})
public String executeAction() throws Exception {
    return SUCCESS;
}