DataTables: ajax request/response的服务端建模(java)

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

}


Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.