Spring MVC
Spring MVC数据类型转换
Spring3引入了更加通用的类型转换系统,其定义了SPI接口(Converter等)和相应的运行时执行类型转换的API(ConversionService等)。该类型转换系统是Spring通用的,其定义在org.springframework.core.convert包中,提供无状态、强类型且可以在任意类型之间转换的类型转换系统,可以用于任何需要的地方,如SpEL、数据绑定。
类型转换器有如下三种接口
(1 )、Converter:类型转换器,用于转换S类型到T类型,此接口的实现必须是线程安全的且可以被共享。
package org.springframework.core.convert.converter;
public interface Converter<S, T> { //① S是源类型 T是目标类型
T convert(S source); //② 转换S类型的source到T目标类型的转换方法
}
Converter接口实现只能转换一种类型到另一种类型,不能进行多类型转换,如将一个数组转换成集合,如(String[] ----> List<String>、String[]----->List<PhoneNumberModel>等)
- 1
- 2
- 3
- 4
- 5
- 6
(2 )、GenericConverter和ConditionalGenericConverter:GenericConverter接口实现能在多种类型之间进行转换,ConditionalGenericConverter是有条件的在多种类型之间进行转换。
package org.springframework.core.convert.converter;
public interface GenericConverter {
//getConvertibleTypes:指定了可以转换的目标类型对;
Set<ConvertiblePair> getConvertibleTypes();
//convert:在sourceType和targetType类型之间进行转换
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
package org.springframework.core.convert.converter;
public interface ConditionalGenericConverter extends GenericConverter {
//matches:用于判断sourceType和targetType类型之间能否进行类型转换
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
对于我们大部分用户来说一般不需要自定义GenericConverter, 如果需要可以参考内置的GenericConverter来实现类型转换。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
(3 )、ConverterFactory:工厂模式的实现,用于选择将一种S源类型转换为R类型的子类型T的转换器的工厂接口。
package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
S:源类型;R目标类型的父类型;T:目标类型,且是R类型的子类型;
getConverter:得到目标类型的对应的转换器。
如org.springframework.core.convert.support.NumberToNumberConverterFactory用于在Number类型子类型之间进行转换,如Integer--->Double, Byte---->Integer, Float--->Double等。
对于我们大部分用户来说一般不需要自定义ConverterFactory,如果需要可以参考内置的ConverterFactory来实现类型转换。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
类型转换器注册器、类型转换服务有如下两种接口
类型转换器注册器、类型转换服务:提供类型转换器注册支持,运行时类型转换API支持。
(1 )、ConverterRegistry:类型转换器注册支持,可以注册/删除相应的类型转换器
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
可以注册:Converter实现,GenericConverter实现,ConverterFactory实现。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
(2 )、ConversionService:运行时类型转换服务接口,提供运行期类型转换的支持。
package org.springframework.core.convert;
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
convert:将源对象转换为目标类型的目标对象。
Spring提供了两个默认实现(其都实现了ConverterRegistry、ConversionService接口):
DefaultConversionService:默认的类型转换服务实现;
DefaultFormattingConversionService:带数据格式化支持的类型转换服务实现,一般使用该服务实现即可。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Spring内建的类型转换器
自定义类型转换
我们将页面传递的字符串转换为标准化日期格式。
1.先实现类型转换器
public class DateConverter implements Converter<String, Date> {
//将传入的字符串转换为日期
public Date convert(String source) {
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = format.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2.在springmvc配置文件中注册ConversionService实现和自定义的类型转换器
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!--可以自定义很多类型转换器-->
<property name="converters">
<list>
<bean class="cn.cad.converter.DateConverter"></bean>
</list>
</property>
</bean>
FormattingConversionServiceFactoryBean:是FactoryBean实现,默认使用DefaultFormattingConversionService转换器服务实现;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3.通过ConfigurableWebBindingInitializer注册ConversionService
<bean id="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
</bean>
- 1
- 2
- 3
- 4
- 5
4.注册ConfigurableWebBindingInitializer到RequestMappingHandlerAdapte
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上面的方法看起来太过繁琐,SpringMVC提供了如下更简单的配置。
<!--前面说过使用<mvc:annotation-driven>就不用再配置映射器和适配器-->
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.cad.converter.DateConverter"></bean>
</list>
</property>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如上就完成了类型转换,我们程序页面输入的日期一定要符合format的格式,才能完成转换,否则就会出异常。
Controller返回类型
ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
- 1
- 2
void
有的时候我们并不需要返回值,例如ajax请求时。不过我们也可以在方法参数列表上添加request等来进行页面跳转等操作。
- 1
- 2
String
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
至于数据,我们可以通过默认的Model或者ModelMap来传递参数。
通过 return "redirect:/xxx.jso" 来重定向或者转发
- 1
- 2
- 3
- 4
SpringMVC异常处理
在SpringMVC中,系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
这里有篇关于SpringMVC异常处理的文章写的很棒,我就不再重复。
http://blog.csdn.net/eson_15/article/details/51731567
SpringMVC文件上传
1.首先需要加入jar包
- 1
2.配置上传解析器
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件上传大小 -->
<property name="maxUploadSize" value="5000000" />
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3.表单一定要设置enctype="multipart/form-data"
然后接收文件的方法 添加一个参数
//通过MultipartFile 接收上传的文件
public ModelAndView updateItem(Items item,MultipartFile pictureFile) throws IllegalStateException, Exception {
String picName = UUID.randomUUID().toString();
// 获取文件名
String oriName = pictureFile.getOriginalFilename();
System.out.println(oriName);
// 开始上传文件
pictureFile.transferTo(new File("F:\\upload\\" + picName + extName));
itemService.updateItemById(item);
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("forward:/itemEdit");
return modelAndView;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
这篇博客详细介绍了SpringMVC的上传下载。
http://blog.csdn.net/evankaka/article/details/45826697/
SpringMVC拦截器
Spring Web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
拦截器接口
package org.springframework.web.servlet;
public interface HandlerInterceptor {
boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)
throws Exception;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
preHandle:处理器前执行的方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现);
返回值:true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
postHandle:处理器后回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,不管你需不需要,此时spring提供了一个HandlerInterceptorAdapter适配器,允许我们只实现需要的回调方法。
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
//省略代码 此处所以三个回调方法都是空实现,preHandle返回true。
}
- 1
- 2
- 3
案例
1.编写拦截器
public class HandlerInterceptor1 extends HandlerInterceptorAdapter {//此处一般继承HandlerInterceptorAdapter适配器即可
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===========拦截器 preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===========拦截器 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===========拦截器 afterCompletion");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
2.编写处理器
@Controller
public class TestController {
@RequestMapping("/test")
public ModelAndView test() {
System.out.println("===========TestController");
return new ModelAndView("test");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.配置拦截器
<mvc:interceptors>
<!--可以配置很多拦截器-->
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.cad.HandlerInterceptor1" />
</mvc:interceptor>
</mvc:interceptors>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
然后进行检测即可。可以用来做登录检测、性能检测等。