Spring扩展点

Spring扩展点

1.IOC生成类全名

<!-- 自动扫描且只扫描@Controller -->
<context:component-scan base-package="cn.com.demo.**.controller" 
	name-generator="cn.com.demo.framework.spring.context.annotation.FullNameBeanNameGenerator"  use-default-filters="false">
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
public class FullNameBeanNameGenerator extends AnnotationBeanNameGenerator{

	@Override
	protected String buildDefaultBeanName(BeanDefinition definition) {
		return definition.getBeanClassName();
	}

}

2.转换生成映射的URL大小写

<!-- 通过 @Controller 和 @RequestMapping 从url定位到类的方法, 自定义CoC实现, 不要再配置annotation-driven -->
<bean class="cn.com.demo.framework.web.springmvc.support.CocRequestMappingHandlerMapping">
	<property name="basePackage" value="cn.com.demo" />
</bean>
public class CocRequestMappingHandlerMapping extends RequestMappingHandlerMapping{
	
	/** Controller类的后缀 */
	private static final String CONTROLLER_SUFFIX = "Controller";
	
	/** 映射url路径的根 */
	private String basePackage;
	
	//父类的属性
	private boolean useSuffixPatternMatch = true;
	private boolean useTrailingSlashMatch = true;
	private final List<String> fileExtensions = new ArrayList<String>();
	
	/**
	 * Look for handler methods in a handler.
	 * @param handler the bean name of a handler or a handler instance
	 */
	protected void detectHandlerMethods(final Object handler) {
		//Assert.notNull(this.basePackage, "must config basePackage!");
		super.detectHandlerMethods(handler);
	}
	
	/**
	 * 这个只改了createRequestMappingInfo的调用,增加了参数
	 * Uses method and type-level @{@link RequestMapping} annotations to create
	 * the RequestMappingInfo.
	 *
	 * @return the created RequestMappingInfo, or {@code null} if the method
	 * does not have a {@code @RequestMapping} annotation.
	 *
	 * @see #getCustomMethodCondition(Method)
	 * @see #getCustomTypeCondition(Class)
	 */
	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;
		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodAnnotation != null) {
			RequestCondition<?> methodCondition = getCustomMethodCondition(method);
			info = createRequestMappingInfo(methodAnnotation, methodCondition, method, handlerType);
			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeAnnotation != null) {
				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
				info = createRequestMappingInfo(typeAnnotation, typeCondition, method, handlerType).combine(info);
			}
			
		}
		return info;
	}
	
	/**
	 * 将父类同名方法加入controller的类型和方法参数
	 */
	private RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition, Method method, Class<?> handlerType) {
		
		String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
		
		//@RequestMapping没有配置value, 加入coc部分
		if( patterns.length==0 ){
			StringBuilder p = new StringBuilder();
			if (this.basePackage != null) {
				String packageName = ClassUtils.getPackageName(handlerType);
				if (packageName.startsWith(this.basePackage)) {
					String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/');
					if( subPackage.endsWith("/controller") ){
						//去掉/backup/controller的 /controller
						subPackage = subPackage.substring(0,subPackage.indexOf("/controller"));
					}
					p.append(subPackage.toLowerCase());
					p.append("/");
				}
			}
			
			//类名去掉后缀小写
			String className = handlerType.getSimpleName();
			className = (className.endsWith(CONTROLLER_SUFFIX) ?
					className.substring(0, className.lastIndexOf(CONTROLLER_SUFFIX)) : className);
			
			p.append(className.toLowerCase()).append("/");//类名小写
			p.append(method.getName().toLowerCase());//方法名小写
			patterns = new String[]{p.toString()};
		}
		
		return new RequestMappingInfo(
				new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
						this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
				new RequestMethodsRequestCondition(annotation.method()),
				new ParamsRequestCondition(annotation.params()),
				new HeadersRequestCondition(annotation.headers()),
				new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
				new ProducesRequestCondition(annotation.produces(), annotation.headers(), getContentNegotiationManager()),
				customCondition);
	}

	//----------------------set get
	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

	public void setUseSuffixPatternMatch(boolean useSuffixPatternMatch) {
		this.useSuffixPatternMatch = useSuffixPatternMatch;
	}

	public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
		this.useTrailingSlashMatch = useTrailingSlashMatch;
	}
	
	
}

3.参数自定义类型转换

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="webBindingInitializer">
		<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
			<property name="conversionService">
				<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
					<property name="converters">
						<list>
							<bean class="cn.com.demo.framework.spring.core.convert.converter.StringToDateConverter"/>
						</list>
					</property>
				</bean>
			</property>
		</bean>
	</property>
	<property name="customArgumentResolvers">
		<list>
			<bean class="cn.com.demo.framework.web.springmvc.support.method.support.crud.CrudHandlerMethodArgumentResolver"/>
		</list>
	</property>
	<property name="messageConverters">
		<list>
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<constructor-arg value="UTF-8" />
			</bean>
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
				<property name="objectMapper">
					<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
						<property name="serializers">
							<array>
								<bean class="cn.com.demo.canyin.common.springmvc.converter.json.LongToStringJsonSerializer" />
							</array>
						</property>
						<property name="dateFormat">
							<bean class="java.text.SimpleDateFormat">
								<constructor-arg value="yyyy-MM-dd'T'HH:mm:ss.SSS" />
							</bean>
						</property>
					</bean>
				</property>
			</bean>
			<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
		</list>
	</property>
</bean>
public class StringToDateConverter implements Converter<String, Date>{
	
	@Override
	public Date convert(String source) {
		
		if( source==null || source.length()==0 )
			return null;
		
		int length = source.length();
		
		switch (length) {
			case 5:
				return parse("HH:mm", source);
			case 10:
				return parse("yyyy-MM-dd", source);
				
			case 19:
			case 21:
			case 22:
				return parse("yyyy-MM-dd HH:mm:ss", source);
				
			case 23:
				return parse("yyyy-MM-dd'T'HH:mm:ss.SSS", source);
			case 28:
			try {
				return new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy", Locale.US).parse(source);
			} catch (ParseException e) {
				throw new RuntimeException("时间转换格式异常,datestr:" + source, e);
			}
			default:
				throw new RuntimeException("Unsupport Date Format: " + source);
		}
	}
	
	/**
	 * 解析date
	 */
	private Date parse(String format, String date){
		try {
			return new SimpleDateFormat(format).parse(date);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}
}

public class CrudHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver{

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType();
		return QueryParam.class.isAssignableFrom(paramType);
	}

	@Override
	public Object resolveArgument(MethodParameter parameter,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
			WebDataBinderFactory binderFactory) throws Exception {
		
		Class<?> paramType = parameter.getParameterType();
		
		//查询参数
		QueryParam p = parseQueryParam(parameter, webRequest);
		return p;
	}
	
	/**
	 * <b>功能描述:</b>解析查询参数<br>
	 */
	@SuppressWarnings("serial")
	private QueryParam parseQueryParam(MethodParameter parameter, NativeWebRequest webRequest){
		QueryParam p = new QueryParam();
		//分页参数
		p.setStart(getInteger(webRequest, "start"));
		p.setLimit(getInteger(webRequest, "limit"));
		String sort = webRequest.getParameter("sort");
		if(StringUtils.isNotBlank(sort)){
			SortExpression[] orderBy = JsonConverterUtils.getJc().fromJson(sort, SortExpression[].class);
			DefaultConvertName dcn = new DefaultConvertName();
			orderBy[0].setProperty(dcn.convertToColumnName(orderBy[0].getProperty()));
			p.setSort(orderBy[0].toSqlString());
		}
		return p;
	}
	
	/**
	 * 获取整数参数
	 */
	private Integer getInteger(NativeWebRequest webRequest, String name){
		String p = webRequest.getParameter(name);
		
		if( p==null || p.length()==0 )
			return null;
		
		return Integer.valueOf(p);
	}
	
	/**
	 * 如果是get方法, 编码参数
	 */
	private String encodeParameter(NativeWebRequest webRequest, String paramName){
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		String p = webRequest.getParameter(paramName);
		if( "GET".equalsIgnoreCase(request.getMethod())){
			return RequestUtil.encodeParameter(p);
		}
		return p;
	}
	
}

public class LongToStringJsonSerializer extends JsonSerializer<Long> {
	
	@Override
	public Class<Long> handledType() {
		return Long.class;
	}

	@Override
	public void serialize(Long value, JsonGenerator jgen, SerializerProvider provider) 
			throws IOException, JsonProcessingException {
		jgen.writeString(value.toString());
	}
	
}

4.自定义异常拦截器

<!-- mvc exception handler -->
<bean id="handlerExceptionResolver" class="cn.com.demo.framework.enterprise.spring.web.ProjectHandlerExceptionResolver"></bean>
public class ProjectHandlerExceptionResolver implements HandlerExceptionResolver{
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	/** json 转换 */
	@Resource private JsonConverter jsonConverter;

	@Resource private LogManageService logManageService;
	
	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, 
				Object handler, Exception ex) {
		
		return null;
	}

	/**
	 * <b>功能描述:</b>
	 * 是否ExtForm的StandardSubmit模式<br>
	 * 前台需要额外传入X-Requested-With的参数来说明本次提交为StandardSubmit
	 */
	private boolean isExtFormStandardSubmit(HttpServletRequest request){
		return request.getParameter("X-Requested-With")!=null;
	}
}

相关推荐