12

I'm not getting response as JSON type data from server.

I'm using JSON plugin.

jQuery( "#dialog-form" ).dialog({ 
    autoOpen: false,
    height: 500,
    width: 750,
    modal: true,
    buttons :{
        "Search" : function(){
            jQuery.ajax({type : 'POST',
            dataType : 'json',
             url : '<s:url action="part" method="finder" />',
         success : handledata})
        }
    }
});
var handledata = function(data)
{
    alert(data);
}

If dataType = 'json' I am not getting any response, but if I don't mention any dataType, I'm getting the HTML format of the page.

public String list(){
    JSONObject jo = new JSONObject();
    try {
        Iterator it = findList.iterator();
        while(it.hasNext()){
             SearchResult part = (SearchResult) it.next();
             jo.put("col1",part.getcol1());
             jo.put("col2",part.getcol2());
        }
        log.debug("--------->:"+jo.toString());
    } catch (Exception e) {
        log.error(e);
    }
    return jo.toString();
}

struts.xml:

<package name="default" namespace="/ajax" extends="json-default">
  <action name="finder" 
       class="action.Part" method="finder" name="finder">
       <result type="json" />
  </action>
</package>

JSP page:

<div id="dialog-form" >
    <form action="" id="channelfinder">
        <textarea id="products" name="prodnbr"<s:property value='prodNbr'/>   
    </form>
</div>

Console error:

org.apache.struts2.dispatcher.Dispatcher - Could not find action or result No result defined for action action.Part and result {"col1":"col1","col2":"col2"}

web.xml:

    <?xml version="1.0" encoding="ISO-8859-1"?>
     <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      <display-name>/parts</display-name>
      <description>Parts List Web App</description>

    <filter>
          <filter-name>struts-cleanup</filter-name>
          <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
        </filter>

        <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
        </filter>

       <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        <init-param>
            <param-name>actionPackages</param-name>
            <param-value>com.action</param-value>
        </init-param>
    </filter>


    <filter-mapping>
        <filter-name>struts-cleanup</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/errorPage.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/errorPage.jsp</location>
    </error-page>

  <!-- Spring -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  </web-app>

I'm not getting data to jQuery success. Please correct me, whats wrong here?

Roman C
  • 49,761
  • 33
  • 66
  • 176
user2444474
  • 623
  • 8
  • 21
  • 40

2 Answers2

17

About Struts2-JSON Plugin

Struts2 JSON Plugin works in a particular way:

The JSON plugin provides a "json" result type that serializes actions into JSON.

It serializes the entire Action into JSON, except

  • transient properties
  • properties without the Getter

If you don't want the whole Action to be serialized, but only one object of your choice, you can specify a Root Object:

Use the "root" attribute(OGNL expression) to specify the root object to be serialized.

it can be done in struts.xml like this:

<result type="json">
    <param name="root">
        objectToBeSerialized
    </param>
</result>

while the Action should have:

private CustomObject objectToBeSerialized;

public CustomObject getObjectToBeSerialized(){
    return this.objectToBeSerialized;
}

Where CustomObject can be a Primitive, a String, an Array, etc...

Using it this way (the way it is built for), you can return SUCCESS and ERROR like in any other AJAX Struts2 Action, without breaking the framework conventions, and access the serialized JSON object from the callback function of the AJAX jQuery call like any other field (if using rootObject, the "data" of var handledata = function(data) would be your object, otherwise it would be your Action).


About your specific case

In your case, assuming your object structure looks like this

row1 [col1, col2], 
row2 [col1, col2], 
rowN [col1, col2]

you could create a List of an object with two columns:

Value Object

public class MyRow implements Serializable {
    private static final long serialVersionUID = 1L;

    private String col1; 
    private String col2;

    // Getters
    public String getCol1(){ 
        return this.col1; 
    }
    public String getCol2(){ 
        return this.col2; 
    }
}

Action class

public class PartAction implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private List<MyRow> rows;   

    // Getter
    public  List<MyRow> getRows() { 
        return this.rows; 
    } 

    public String finder() {
        String result = Action.SUCCESS;
        rows = new ArrayList<MyRow>();

        try {
            Iterator it = findList.iterator();
            while(it.hasNext()) {
                SearchResult part = (SearchResult) it.next();
                MyRow row = new MyRow();
                row.setCol1(part.getcol1());
                row.setCol2(part.getcol2());
                rows.add(row);
            }
        } catch (Exception e) {
            result = Action.ERROR;
            log.error(e);
        }
        return result;
    }  
} 

Struts.xml

<package name="default" namespace="/ajax" extends="json-default">
    <action name="finder" class="action.Part" method="finder" name="finder">
        <result type="json" >
            <param name="root">
                rows
            </param>
        </result>
  </action>
</package>

To test it in the AJAX Callback Function, simply use $.each :

var handledata = function(data) {
    $.each(data, function(index) {
        alert(data[index].col1);
        alert(data[index].col2);
    });     
}

Of course you can use a List<List<String>> instead of a Custom object, or any other object structure you like more than this: it was only to get you the idea.

Community
  • 1
  • 1
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
5

A dataType : 'json' is used by jQuery Ajax to specify a data type that is expected to return by the success callback function when the action and result is executed, and a response returned from the server.

dataType (default: Intelligent Guess (xml, json, script, or html))

Type: String

The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string).

The URL should correctly point to the action mapping. Assume it will be in the default namespace, otherwise you should modify URL and mapping to add the namespace attribute.

<script type="text/javascript">
  $(function() {
    $("#dialog-form").dialog ({
      autoOpen: true,
      height: 500,
      width: 750,
      modal: true,
      buttons : {
        "Search" : function() {
          $.ajax({
            url : '<s:url action="part" />',
            success : function(data) {
              //var obj = $.parseJSON(data);
              var obj = data;
              alert(JSON.stringify(obj));
            }
          });
        }
      }
    });
  });
</script>

Returning json result type is not needed if you build the JSONObject manually. You can return text as stream result then convert a string to JSON if needed.

struts.xml:

<package name="default" extends="struts-default">
  <action name="part" class="action.PartAction" method="finder">    
    <result type="stream">
      <param name="contentType">text/html</param>
      <param name="inputName">stream</param>
    </result>
  </action>
</package>

Action:

public class PartAction extends ActionSupport {

  public class SearchResult {
    private String col1;
    private String col2;

    public String getCol1() {
      return col1;
    }

    public void setCol1(String col1) {
      this.col1 = col1;
    }

    public String getCol2() {
      return col2;
    }

    public void setCol2(String col2) {
      this.col2 = col2;
    }

    public SearchResult(String col1, String col2) {
      this.col1 = col1;
      this.col2 = col2;
    }
  }

  private InputStream stream;

  //getter here
  public InputStream getStream() {
    return stream;
  }

  private List<SearchResult> findList = new ArrayList<>();

  public List<SearchResult> getFindList() {
    return findList;
  }

  public void setFindList(List<SearchResult> findList) {
    this.findList = findList;
  }

  private String list() {
    JSONObject jo = new JSONObject();
    try {
      for (SearchResult part : findList) {
        jo.put("col1", part.getCol1());
        jo.put("col2", part.getCol2());
      }
      System.out.println("--------->:"+jo.toString());
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println(e.getMessage());
    }
    return jo.toString();
  }

  @Action(value="part", results = {
    @Result(name="stream", type="stream", params = {"contentType", "text/html", "inputName", "stream"}),
    @Result(name="stream2", type="stream", params = {"contentType", "application/json", "inputName", "stream"}),
    @Result(name="json", type="json", params={"root", "findList"})
  })
  public String finder() {
    findList.add(new SearchResult("val1", "val2"));
    stream = new ByteArrayInputStream(list().getBytes());
    return "stream2";
  }
}

I have placed different results with result type and content type to better describe the idea. You could return any of these results and return JSON object either stringified or not. The stringified version requires to parse returned data to get the JSON object. You can also choose which result type better serializes to suit your needs but my goal was to show that if you need to serialize the simple object then json plugin is not necessary to get it working.

References:

Community
  • 1
  • 1
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • So, converting jsonarray to plaintext? if converting from jsonarray to jsonobject, will work ? – user2444474 Jun 13 '13 at 20:44
  • Do you already got the json string in the action? Then you could get it as data to success function. – Roman C Jun 13 '13 at 20:47
  • public String list() { JSONObject jo = new JSONObject(); String part; part = build(); jo.put("array",jo); return jo.toString();} - Still not working. – user2444474 Jun 13 '13 at 21:10
  • You didn't build a valid jo. Try this myString = new JSONObject().put("JSON", "Hello, World!").toString(); – Roman C Jun 13 '13 at 21:13
  • Thank you soo much for your effort. Whatever data coming from action class, i need to use to datatable to display.Thats reason i have trying to put into array or JSON data through ajax.but these text format data also can i use to datatable ? – user2444474 Jun 17 '13 at 04:35
  • Could you distinguish the JSON result type result with stream result type result that returns JSON data? Ofcause you can use it if the result returns a valid JSON format data. – Roman C Jun 17 '13 at 09:56
  • why did you remove the method="finder" from url. its not triggering the action url : ''. If i'm adding method in button,again getting the error Could not find action or result No result defined for action. – user2444474 Jun 17 '13 at 16:59
  • @user2444474 method finder is not necessary in the url, DMI option required to get such url working. Check the action in the browser applying url into its navigator. – Roman C Jun 17 '13 at 17:14
  • However list method is calling from finder method.After that its giving me error "Could not find action or result No result defined for action" – user2444474 Jun 17 '13 at 17:57
  • After this button click , its not going to forward to any page.just keep staying same form. – user2444474 Jun 17 '13 at 18:04
  • @user2444474 1. Don't you have a stream result type? Check the file `struts-default.xml`. 2. It's ajax thus page not refresh. – Roman C Jun 17 '13 at 18:36
  • @user2444474 What a version of struts2, jquery you treat with? – Roman C Jun 17 '13 at 18:39
  • Struts version is Struts2.3.1.1. – user2444474 Jun 17 '13 at 18:55
  • I have stream result type in struts-default xml. but we were using struts-plugin.xml , so we didn't include to war file. – user2444474 Jun 17 '13 at 18:58
  • Didn't you see in the `struts.xml` I configured the action mapping that has a result by default it's name "success" that name return the action, you should either include my configuration or ask another question how to resolve "no action or result found". – Roman C Jun 17 '13 at 21:26
  • I have included the your configuration in struts.xml file, but my application not taking i think, instead of struts-plugin.xml struts-default.xml...that why i'm stuggling here..Is there any other way to avoid Could not find action or result No result defined for action ? – user2444474 Jun 17 '13 at 21:54
  • Is this file on the classpath? Post `web.xml`. Another option is to use convention-plugin to map your action. But you state in the question that the action is executed, so how do you map the action to the configuration? And the method `finder` that is your action mapped to must return `Action.SUCCESS` not the result returned by the `list()`. – Roman C Jun 18 '13 at 08:39
  • I have posted my web.xml file , please look into question section. – user2444474 Jun 18 '13 at 14:06
  • You didn't answer my questions, regarding your web.xml: remove actionPackages init parameter. It doesn't needed actually, without package locators it will do nothing. – Roman C Jun 18 '13 at 14:41
  • Added annotation-based configuration to the action, so you should not worry about struts.xml now. – Roman C Jun 18 '13 at 14:53
  • However it's difficult to live without it. Do you have any struts.properties? – Roman C Jun 18 '13 at 15:00
  • In struts.properties file has nothing..just i18n properties defined. – user2444474 Jun 18 '13 at 15:19
  • @Result(name="success",type= ServletDispatcherResult.class,params={"contentType","text/html","inputName","inputStream"}) - The annotation is not working. – user2444474 Jun 18 '13 at 18:01
  • org.apache.struts2.dispatcher.Dispatcher - Could not find action or result /part!finder.xhtml No result defined for action action.PartAction and result success – user2444474 Jun 19 '13 at 14:44
  • Thank you soo much for your great effort.I apperciate it...I'm close to complete it. – user2444474 Jun 19 '13 at 14:52
  • In this project used Struts2-codebehind-plugin used , its taking care of all work action mapping based on file name.Thats reason struts.xml is not working. – user2444474 Jun 19 '13 at 15:08
  • @user2444474 codebehind plugin is too old, and it's replaced by the convention plugin, while you didn't mention it before in your question, anyway my answer is working with the convention plugin and the latest release. – Roman C Jun 19 '13 at 15:18
  • @user2444474 But I'm still don't understand why didn't you just download the struts 2.3.14 and play with the source code I've posted here. All you need is to create a project with maven and paste my code. It's 100% working in this version. – Roman C Jun 19 '13 at 15:24