DataTables的Ajax Http Request的结构非常奇葩,比如
引用
columns[0][data]:id
columns[0][name]:id
columns[0][searchable]:true
columns[0][orderable]:false
columns[0][search][value]:174940
columns[0][search][regex]:false
columns[1][data]:sex
columns[1][name]:sex
columns[1][searchable]:true
columns[1][orderable]:false
columns[1][search][value]:
columns[1][search][regex]:false
服务端的正常API不可能接受这种参数。相反它更愿意接受id, sex这种参数。 所以我们要有一个通用的解析器(parser), 从上面的奇葩中解析出id=174940, sex=male这种参数; 通用的解析器必定会有一个通用的结果,我们需要建模这个结果类。
另外,Data Tables的ajax http response也必须遵守一定规范。我们也应该在后端专门建一个通用的response 对象。
我在网上搜了很久,都没搜到现在的。所以我只好自己写。
一个依赖
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
Request
package player.kent.chen.demo.datatables; import java.util.LinkedHashMap; import java.util.Map; /** * datatables ajax 请求建模. 见 http://datatables.net/manual/server-side <br/> * 注:1.不支持regex search <br/> * 2.只支持单一维度排序 <br/> * * @author chenjianjx * */ public class DtRequest { /** * please check dataTables' document */ private int draw; /** * recordIndex, 0-based */ private int start; /** * num of records wanted. (e.g. pageSize) */ private int length; /** * columns */ private Map<String, DtColumn> columns = new LinkedHashMap<String, DtColumn>(); /** * 用于排序的列名 */ private String orderColumn; /** * 排序是否为升序。如果{@link #orderColumn}为空,则此字段的字将被忽略 */ private boolean orderAsc; /** * 加一个column * * @param name * @param searchValue */ public void addColumn(String name, String searchValue) { DtColumn column = DtColumn.createInstance(name, searchValue); columns.put(name, column); } /** * 根据column name拿到search value * * @param name * @return */ public String getColumnSearchValue(String name) { DtColumn column = columns.get(name); if (column == null) { return null; } return column.getSearchValue(); } public int getDraw() { return draw; } public void setDraw(int draw) { this.draw = draw; } public int getStart() { return start; } public void setStart(int start) { this.start = start; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public int getPageSize() { return getLength(); } public int getPageIndexOneBased() { if (this.getPageSize() <= 0) { return 1; } return this.getStart() / this.getPageSize() + 1; } public String getOrderColumn() { return orderColumn; } public void setOrderColumn(String orderColumnName) { this.orderColumn = orderColumnName; } public boolean isOrderAsc() { return orderAsc; } public void setOrderAsc(boolean orderAsc) { this.orderAsc = orderAsc; } }
Column
package player.kent.chen.demo.datatables; import java.util.regex.Pattern; /** * @see http://datatables.net/manual/server-side . 暂不支持regex search. * @author chenjianjx * */ public class DtColumn { private String name; private String searchValue; public static final Pattern COLUMN_NAME_PATTERN = Pattern.compile("columns\\[(\\d+)\\]\\[name\\]"); public static final DtColumn createInstance(String name, String searchValue) { DtColumn instance = new DtColumn(); instance.name = name; instance.searchValue = searchValue; return instance; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSearchValue() { return searchValue; } public void setSearchValue(String searchValue) { this.searchValue = searchValue; } }
Request Parser
package player.kent.chen.demo.datatables; import java.text.MessageFormat; import java.util.Map; import java.util.regex.Matcher; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; /** * dataTables request的解析器 * * @author chenjianjx * */ public class DtRequestParser { /** * 从http request中解析dt request * @param httpRequest * @param defaultLength * 如果未指定默认页大小,则应该是? * @return */ public static DtRequest fromHttpRequest( HttpServletRequest httpRequest, int defaultLength) { DtRequest dtRequest = new DtRequest(); dtRequest.setStart(getIntParam(httpRequest, "start", 0)); dtRequest.setLength(getIntParam(httpRequest, "length", defaultLength)); dtRequest.setDraw(getIntParam(httpRequest, "draw", 1)); // parse columns @SuppressWarnings("unchecked") Map<String, String[]> paramMap = httpRequest.getParameterMap(); fillColumns(dtRequest, paramMap); // parse sorting fillOrdering(dtRequest, paramMap); return dtRequest; } private static void fillOrdering(DtRequest dtRequest, Map<String, String[]> paramMap) { String orderColumnIndexStr = StringUtils .trimToNull(getFirstElement(paramMap.get("order[0][column]"))); int orderColumnIndex = NumberUtils.toInt(orderColumnIndexStr, -1); if (orderColumnIndex < 0) { return; } String columnNameParamKey = MessageFormat.format("columns[{0}][name]", String.valueOf(orderColumnIndex)); String columnName = StringUtils.trimToNull(getFirstElement(paramMap .get(columnNameParamKey))); if (columnName == null) { return; } boolean orderAsc = "asc".equals(getFirstElement(paramMap.get("order[0][dir]"))); dtRequest.setOrderColumn(columnName); dtRequest.setOrderAsc(orderAsc); } private static void fillColumns(DtRequest dtRequest, Map<String, String[]> paramMap) { for (String paramName : paramMap.keySet()) { Matcher matcher = DtColumn.COLUMN_NAME_PATTERN .matcher(paramName); if (!matcher.find()) { continue; } String columnIndexStr = matcher.group(1); if (!NumberUtils.isNumber(columnIndexStr)) { continue; } int columnIndex = NumberUtils.toInt(columnIndexStr); if (paramMap.get(paramName) == null || paramMap.get(paramName).length == 0 || StringUtils.isBlank(paramMap.get(paramName)[0])) { continue; } String columnName = StringUtils .trimToNull(paramMap.get(paramName)[0]); if (columnName == null) { continue; } String columnSearchValueParamName = MessageFormat.format( "columns[{0}][search][value]", String.valueOf(columnIndex)); String columnSearchValue = StringUtils .trimToNull(getFirstElement(paramMap .get(columnSearchValueParamName))); dtRequest.addColumn(columnName, columnSearchValue); } } private static String getFirstElement(String[] array) { if (array == null) { return null; } if (array.length == 0) { return null; } return array[0]; } private static int getIntParam(HttpServletRequest request, String paramName, int defaultValue) { return NumberUtils.toInt( StringUtils.trimToNull(request.getParameter(paramName)), defaultValue); } }
Response
package player.kent.chen.demo.datatables; import java.util.List; /** * datatables ajax 响应建模. 见 http://datatables.net/manual/server-side * * @author chenjianjx * */ public class DtResponse<T> { /** * data */ protected List<T> data; /** * Do not include this if there is no error. */ protected String error; /** * please check dataTables' document */ private int draw; /** * Total records, before filtering */ private int recordsTotal; /** * Total records, after filtering. */ private int recordsFiltered; public int getDraw() { return draw; } public void setDraw(int draw) { this.draw = draw; } public int getRecordsTotal() { return recordsTotal; } public void setRecordsTotal(int recordsTotal) { this.recordsTotal = recordsTotal; } public int getRecordsFiltered() { return recordsFiltered; } public void setRecordsFiltered(int recordsFiltered) { this.recordsFiltered = recordsFiltered; } }