Article updated on

Struts2 with Annotations JSON and Datatables Example

This example uses Struts2 with annotations to provide a Datatable with JSON.

Features

  • Full JSON communication between JSON and the datatable.
  • The action is automatically parsed to JSON by Struts2.
  • A javascript callback error function is called from Struts2.
  • You can choose order in one column, ordering is disabled in the rest.

1 - Download the War File and Sources

WAR file and sources here

2 - Deploy your War and Test the Application

Once you have deployed your WAR file. (In tomcat start the server and move the war file under the folder webapps)

img/0/85/test.jpeg

  • Use FireBug or similar to check the JSON

img/0/85/test1.jpeg

 

TestJsonAction

package com.mdtel.autonoma.tribulete.action.json;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
@ParentPackage("json-default")
public class TestJSONAction extends ActionSupport{
    private static final long serialVersionUID = 634243322166735407L;    
    private List<TestView> data = new ArrayList<TestView>();
    private Integer draw=0, recordsTotal=1, recordsFiltered = 0, length = 0, start=0;
    private String error_custom;    
    private static final Logger logger = Logger.getLogger(TestJSONAction.class);
    @Action(value="testJSON", results = {
            @Result(name="success", type="json")
        })
    public String execute() {
        recordsTotal = 100;        
        recordsFiltered = recordsTotal;            
        logger.info("New JSON request");
        //print all parameters from the action context
        Map<String, Object> map = ActionContext.getContext().getParameters();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            System.out.println("key:"+ key +" value: " + Arrays.toString((String[])value));            
        }        
        //gets the order from the datatable
        String order = "";
        if(map.get("order[0][dir]")!=null){
            order =    ((String[]) map.get("order[0][dir]"))[0];
        }        
        //The arrayList will be turned into
        data = new ArrayList<TestView>();
        //creates a mock DAO
        int auxStart = 0, accu =1;
        if(order.indexOf("asc")>-1){
            auxStart = start;
        } else {
            auxStart = recordsTotal-start;
            accu=-1;
        }        
        for(int i = 0; i<length; i++){
            TestView rv = new TestView();
            rv.setName("Juan" + auxStart);
            rv.setSurname("Surname" + auxStart);
            rv.setAmount(10000+auxStart);
            rv.setId(auxStart);
            auxStart+=accu;
            data.add(rv);
        }
        //sends an random error to the JSON
        if((Math.random()*10>9)){
            error_custom = "Random Error test";
        }
        return SUCCESS;
    }
    public List<TestView> getData() {
        return data;
    }
    public void setData(List<TestView> data) {
        this.data = data;
    }
    public class TestView {
        private int id;
        private String name="";
        private String surname="";
        private Integer amount=0;        
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getSurname() {
            return surname;
        }
        public void setSurname(String surname) {
            this.surname = surname;
        }
        public Integer getAmount() {
            return amount;
        }
        public void setAmount(Integer amount) {
            this.amount = amount;
        }    
    }
    public Integer getDraw() {
        return draw;
    }
    public void setDraw(Integer draw) {
        this.draw = draw;
    }
    public Integer getRecordsTotal() {
        return recordsTotal;
    }
    public void setRecordsTotal(Integer recordsTotal) {
        this.recordsTotal = recordsTotal;
    }
    public Integer getRecordsFiltered() {
        return recordsFiltered;
    }
    public void setRecordsFiltered(Integer recordsFiltered) {
        this.recordsFiltered = recordsFiltered;
    }
    public Integer getLength() {
        return length;
    }
    public void setLength(Integer length) {
        this.length = length;
    }
    public Integer getStart() {
        return start;
    }
    public void setStart(Integer start) {
        this.start = start;
    }
    public String getError_custom() {
        return error_custom;
    }
    public void setError_custom(String error_custom) {
        this.error_custom = error_custom;
    }
}

 

TestAction

package com.mdtel.autonoma.tribulete.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionSupport;
public class TestAction extends ActionSupport{
    private static final long serialVersionUID = 9086900467866735407L;
    @Actions({
        @Action(value = "/", results = @Result(name = "success", location = "/test.jsp")),
        @Action(value = "/test", results = @Result(name = "success", location = "/test.jsp")) })
        public String execute() {
        return SUCCESS;
    }
}

 

Test.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="js/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="js/jquery-ui.min.js" type="text/javascript"></script>
<link href="addons/datatables/media/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<script src="addons/datatables/media/js/jquery.dataTables.min.js" type="text/javascript"></script>
<link href="addons/datatables/TableTools/css/dataTables.tableTools.min.css" rel="stylesheet" type="text/css" />
<script src="addons/datatables/TableTools/js/dataTables.tableTools.js" type="text/javascript"></script>
</head>
<body>
<p>
    <s:text name="com.welcome"/>
</p>
<table id="tablaprincipal" class="display" style="color: black;font-size: .8em;padding-left: 4px;table-layout: fixed;word-wrap: break-word;">
    <thead>
        <tr>
            <th>Id </th>
            <th>Name </th>
            <th>Surname</th>            
            <th>Salary</th>
        </tr>
    </thead>
</table>
<script>
function handleData( responseData ) {
    var value = responseData.json['error_custom'];  
    if(value!=null){
        alert(value);
    }
}
$(document).ready(function() {
/* Datatables with fullnumbers, no bFilter(Search Field)
 * only the first column is orderable */        
    $('#tablaprincipal').dataTable( {
        "processing": true,
        "serverSide": true,
        "ajax": "json/testJSON",
        "columnDefs": [ { orderable: false, targets: [1,2,3] }],
        "sPaginationType": "full_numbers",
        "bFilter": false,
        "columns": [
           { "data": "id" },
           { "data": "name" },
           { "data": "surname" },
           { "data": "amount" }           
           ],
        "fnDrawCallback" : function(data) {
               handleData(data);
         }           
    } );
} );
</script>
</body>
</html>

 

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <constant name="struts.action.extension" value="" />
    <constant name="struts.custom.i18n.resources" value="global" />
    <constant name="struts.devMode" value="false" />
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.convention.default.parent.package"
        value="default" />
    <constant name="struts.ognl.allowStaticMethodAccess" value="true" />
    <constant name="struts.action.excludePattern"
        value="/do/.*,/addons/.*?,/dt/.*?,.*?.jsp,.*?.png,.*?.css,.*?.js,.*?.gif,.*?.jpeg,.*?.jpg,.*?.ico,.*?.html" />
    <constant name="struts.multipart.maxSize" value="50000000" />
    <package name="default" extends="struts-default">
    </package>
</struts>

 

Notes

  • Tested with Apache Tomcat 1.6 and 1.7
  • Meant to be deployed in tomcat. Log4 is set in the tomcat logs folder log4j.appender.file.File=${catalina.base}/logs/Vivait-Tracker.log
  • Struts2 Version used is 2.3.14 the JSON plug in library is in the lib folder