package cn.jeesoft.core.resolver;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.servlet.ServletRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.PropertyValues;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.bind.ServletRequestParameterPropertyValues;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.util.WebUtils;
import cn.jeesoft.core.model.PagerModel;
import cn.jeesoft.core.utils.StringUtils;
/**
* 数据绑定方法
*/
@SuppressWarnings("unchecked")
public class ArgumentsResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// return parameter.hasParameterAnnotation(FormBean.class);
return true;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
ServletRequest servletRequest = (ServletRequest) webRequest.getNativeRequest();
PropertyValues pvs = null;
Object bindObject = null;
String prefix = getPrefix(parameter);
Class<?> paramType = parameter.getParameterType();
if (Collection.class.isAssignableFrom(paramType) || paramType.isArray()) {
Class<?> genericClass = null;
if (paramType.isArray()) {
genericClass = paramType.getComponentType();
} else {
Type type = parameter.getGenericParameterType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
genericClass = (Class<?>) pt.getActualTypeArguments()[0];
}
}
if (genericClass != null) {
Map<String, Object> mappedValues = createMappedValues(genericClass, webRequest, parameter, prefix);
if (!mappedValues.isEmpty()) {
List<Object> targetObject = new ArrayList<Object>(mappedValues.values());
WebDataBinder binder = new WebDataBinder(null);
bindObject = binder.convertIfNecessary(targetObject, paramType);
}
}
} else if (Map.class.isAssignableFrom(paramType)) {
Class<?> genericClass = null;
Type type = parameter.getGenericParameterType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
genericClass = (Class<?>) pt.getActualTypeArguments()[1];
}
if (genericClass != null) {
Map<String, Object> mappedValues = createMappedValues(genericClass, webRequest, parameter, prefix);
if (!mappedValues.isEmpty()) {
Map<String, Object> targetObject = new HashMap<String, Object>();
for (Map.Entry<String, Object> entry : mappedValues.entrySet()) {
String key = entry.getKey();
key = key.substring(key.indexOf("['") + 2, key.indexOf("']"));
targetObject.put(key, entry.getValue());
}
WebDataBinder binder = new WebDataBinder(null);
bindObject = binder.convertIfNecessary(targetObject, paramType);
}
}
} else {
if (PagerModel.class.isAssignableFrom(paramType)) {
if (StringUtils.isEmpty(prefix)) {
prefix = "pager";
}
}
pvs = new ServletRequestParameterPropertyValues(servletRequest, prefix, separator);
bindObject = convertIfDomainClass(webRequest, pvs, paramType, prefix);
if (null == bindObject) {
bindObject = BeanUtils.instantiateClass(paramType);
}
WebDataBinder binder = new WebDataBinder(bindObject, prefix);
binder.registerCustomEditor(Date.class, new DateEditorSupport());
// binder.initDirectFieldAccess();
binder.bind(pvs);
}
return bindObject;
}
/**
* 获取参数前缀
* @param parameter
*/
private static String getPrefix(MethodParameter parameter) {
FormBean formBean = parameter.getParameterAnnotation(FormBean.class);
if (formBean != null) {
return formBean.value();
}
return null;
}
private static final String DEFAULT_SEPARATOR = ".";
private String separator = DEFAULT_SEPARATOR;
/**
* Setter to configure the separator between prefix and actual property value. Defaults to
* {@link #DEFAULT_SEPARATOR}.
*
* @param separator
* the separator to set
*/
public void setSeparator(String separator) {
this.separator = null == separator ? DEFAULT_SEPARATOR : separator;
}
/*
* 生成指定前缀的数据Map
*/
private Map<String, Object> createMappedValues(Class<?> genericClass, NativeWebRequest webRequest,
MethodParameter parameter, String prefix) {
ServletRequest servletRequest = (ServletRequest) webRequest.getNativeRequest();
Map<String, Object> resultMap = new LinkedHashMap<String, Object>();
WebDataBinder binderHelper = new WebDataBinder(null);
// 将数组提取为一个一个的KEY,这里是集合必须要有prefix + '['
Set<String> keySet = getSortedKeySet(servletRequest, prefix + '[');
for (String key : keySet) {
Object genericObj = null;
if (key.endsWith(separator)) {
ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(servletRequest,
key, StringUtils.EMPTY);
String realKey = key.substring(0, key.length() - 1);
genericObj = convertIfDomainClass(webRequest, pvs, genericClass, realKey);
if (null == genericObj) {
genericObj = BeanUtils.instantiateClass(genericClass);
}
WebDataBinder objectBinder = new WebDataBinder(genericObj, realKey);
objectBinder.bind(pvs);
} else {
Map<String, Object> paramValues = WebUtils.getParametersStartingWith(servletRequest, key);
if (!paramValues.isEmpty()) {
if (Collection.class.isAssignableFrom(genericClass)) {
genericObj = binderHelper.convertIfNecessary(paramValues.values(), genericClass);
} else {
genericObj = binderHelper.convertIfNecessary(paramValues.values().iterator().next(),
genericClass);
}
}
}
if (genericObj != null) {
resultMap.put(key, genericObj);
}
}
return resultMap;
}
/*
* 获取指定前缀的KEY值
*/
private Set<String> getSortedKeySet(ServletRequest request, String prefix) {
Assert.notNull(request, "Request must not be null");
Assert.notNull(prefix, "Prefix must not be null");
Enumeration<String> paramNames = request.getParameterNames();
Set<String> keySet = new TreeSet<String>(ComparatorImpl.INSTANCE);
while (paramNames != null && paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
if (paramName.startsWith(prefix)) {
String key = paramName;
int lastScopeIndex = paramName.indexOf(']');
int firstSeparator = paramName.indexOf(separator);
if (firstSeparator > lastScopeIndex) {
// 这里把separator也加上,用来判断是简单数据类型还是复杂类型
key = paramName.substring(0, firstSeparator + 1);
}
if (!keySet.contains(key)) {
keySet.add(key);
}
}
}
return keySet;
}
private static final class ComparatorImpl implements Comparator<String> {
public static final ComparatorImpl INSTANCE = new ComparatorImpl();
@Override
public int compare(String left, String right) {
int lengthCompare = left.length() - right.length();
return lengthCompare != 0 ? lengthCompare : left.compareTo(right);
}
}
/*
* 如果是Domain Class,则根据是否有ID属性来自动查询实体数据,再行绑定
*/
private Object convertIfDomainClass(WebRequest webRequest, PropertyValues pvs, Class<?> paramType, String prefix) {
// // 如果参数是Domain Class,则看看是否有ID,有就根据ID读取数据
// if (Persistable.class.isAssignableFrom(paramType)) {
// PropertyValue idValue = pvs.getPropertyValue("id");
// if (null != idValue) {
// String idString = (String) idValue.getValue();
// if (StringUtils.isNotEmpty(idString)) {
// WebDataBinder binder = new WebDataBinder(null, prefix + separator + "id");
// if (webBindingInitializer != null) {
// webBindingInitializer.initBinder(binder, webRequest);
// }
// return binder.convertIfNecessary(idString, paramType);
// }
// }
// }
return null;
}
// /**
// * @param tokenValidation
// * the tokenValidation to set
// */
// public void setTokenValidation(TokenValidation tokenValidation) {
// this.tokenValidation = tokenValidation;
// }
}