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