1. 程式人生 > >spring boot 自定義引數解析器實現form表單型別請求或位址列請求引數下劃線轉駝峰屬性

spring boot 自定義引數解析器實現form表單型別請求或位址列請求引數下劃線轉駝峰屬性

一、定義引數解析註解

@Target(value = ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParameterModel {
}

二、定義抽象類AbstractCustomizeResolver繼承HandlerMethodArgumentResolver

public abstract class AbstractCustomizeResolver implements HandlerMethodArgumentResolver {
	//校驗
	protected void valid(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory, Object arg) throws Exception {
		String name = Conventions.getVariableNameForParameter(parameter);
		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
			}
		}
		mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
	}

	/**
	 * Validate the binding target if applicable.
	 * <p>The default implementation checks for {@code @javax.validation.Valid},
	 * Spring's {@link Validated},
	 * and custom annotations whose name starts with "Valid".
	 * @param binder the DataBinder to be used
	 * @param parameter the method parameter descriptor
	 * @since 4.1.5
	 * @see #isBindExceptionRequired
	 */
	protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
		Annotation[] annotations = parameter.getParameterAnnotations();
		for (Annotation ann : annotations) {
			Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
			if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
				Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
				Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
				binder.validate(validationHints);
				break;
			}
		}
	}

	protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
		int i = parameter.getParameterIndex();
		Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
		boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
		return !hasBindingResult;
	}
}

三、定義UnderlineToCamelArgumentResolver繼承AbstractCustomizeResolver

public class UnderlineToCamelArgumentResolver extends AbstractCustomizeResolver {


	/**
	 * Whether the given {@linkplain MethodParameter method parameter} is
	 * supported by this resolver.
	 * @param parameter the method parameter to check
	 * @return {@code true} if this resolver supports the supplied parameter;
	 * {@code false} otherwise
	 */
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(ParameterModel.class);
	}

	/**
	 * 裝載引數
	 *
	 * @param methodParameter       方法引數
	 * @param modelAndViewContainer 返回檢視容器
	 * @param nativeWebRequest      本次請求物件
	 * @param webDataBinderFactory  資料繫結工廠
	 * @return the resolved argument value, or {@code null}
	 * @throws Exception in case of errors with the preparation of argument values
	 */
	@Override
	public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
		Object org=handleParameterNames(methodParameter, nativeWebRequest);
		valid(methodParameter,modelAndViewContainer,nativeWebRequest,webDataBinderFactory,org);
		return org;
	}

	//處理引數
	private Object handleParameterNames(MethodParameter parameter, NativeWebRequest webRequest) {
		Object obj = BeanUtils.instantiate(parameter.getParameterType());
		BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
		Iterator<String> paramNames = webRequest.getParameterNames();
		while (paramNames.hasNext()) {
			String paramName = paramNames.next();
			Object o = webRequest.getParameter(paramName);
			wrapper.setPropertyValue(StringHelpers.underLineToCamel(paramName), o);
		}
		return obj;
	}
}

4、定義工具類StringHelpers處理駝峰與下劃線的互換

public class StringHelpers {
	/**
	 * 匹配_加任意一個字元
	 */
	private static final Pattern UNDER_LINE_PATTERN = Pattern.compile("_(\\w)");


	/***
	 * 下劃線命名轉為駝峰命名
	 *
	 * @param source
	 *        下劃線命名的字串
	 */

	public static String underlineToHump(String source) {
		StringBuffer result = new StringBuffer();
		String a[] = source.split("_");
		for (String s : a) {
			if (result.length() == 0) {
				result.append(s.toLowerCase());
			} else {
				result.append(s.substring(0, 1).toUpperCase());
				result.append(s.substring(1).toLowerCase());
			}
		}
		return result.toString();
	}


	/***
	 * 駝峰命名轉為下劃線命名
	 *
	 * @param source
	 *        駝峰命名的字串
	 */

	public static String humpToUnderline(String source) {
		StringBuffer sb = new StringBuffer(source);
		int temp = 0;//定位
		for (int i = 0; i < source.length(); i++) {
			if (Character.isUpperCase(source.charAt(i))) {
				sb.insert(i + temp, "_");
				temp += 1;
			}
		}
		return sb.toString().toUpperCase();
	}

	/**
	 * Create by lrt<br/>
	 * Date:2018/10/10
	 * Description: 下劃線轉為駝峰格式
	 *
	 * @param source 原字串
	 * @return java.lang.String 返回轉換後的駝峰格式字串
	 */
	public static String underLineToCamel(String source) {
		//用Pattern類的matcher()方法生成一個Matcher物件
		Matcher matcher = UNDER_LINE_PATTERN.matcher(source);

		StringBuffer result = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(result, matcher.group(1).toUpperCase());
		}
		matcher.appendTail(result);
		return result.toString();
	}
}