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;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值