来源:翡青 链接:blog.csdn.net/zjf280441589/article/details/51831979
Converter
Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: Spring总是试图用默认的语言区域将日期输入绑定到java.util.Data, 如果想要使用不同的日期格式(format),就需要Converter的协助.
Spring提供了Converter接口来供开发者自定义Converter类:
/** * @since 3.0 * @param the source type * @param the target type
*/
public interface Converter {
T convert(S source);
}
/**
* @author jifang.
* @since 2016/6/19 7:23.
*/
public class StringDateConverter implements Converter {
private String pattern;
public StringDateConverter(String pattern) {
this.pattern = pattern;
}
@Override
public Date convert(String source) {
try {
return new SimpleDateFormat(pattern).parse(source);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
为了能够让Spring MVC使用我们自定义的Converter, 需要在配置文件中配置一个ConversionServiceFactoryBean:
然后为配置conversion-service属性:
注: 还可以使用FormattingConversionServiceFactoryBean来加载Converter, 由于其配置方法与ConversionServiceFactoryBean, 故在此就不再赘述.
@RequestMapping('/add_user.do')
public String addUser(User user, BindingResult binding) {
if (binding.hasErrors()) {
FieldError error = binding.getFieldError();
// log ...
}
service.addUser(user);
return 'redirect: users.do';
}
BindingResult参数中放置了Spring的所有绑定错误.
Interceptor
Spring MVC的拦截器类似于Servlet中的Filter(关于Filter,详细可参考Servlet – Listener、Filter、Decorator),用于Controller进行预处理和后处理.
Spring提供了Interceptor接口来供开发者自定义Interceptor类:
public interface HandlerInterceptor {
/**
* 进入Controller方法前执行
* 应用场景: 身份认证、身份授权等
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
/**
* 进入Controller方法后, 返回ModelAndView前执行
* 应用场景: 将公共模型数据填充到ModelAndView、统一指定视图等
*/
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
/**
* 执行完Controller方法后执行
* 应用场景: 统一日志处理、统一异常处理等
*/
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
示例: 统计Controller执行耗时.
/**
* @author jifang
* @since 16/7/4 上午10:35.
*/
public class HandleTimeInterceptor implements HandlerInterceptor {
private static final String START_TIME = 'start_time';
private static final String HANDLE_TIME = 'handle_time';
private static final Logger LOGGER = LoggerFactory.getLogger(HandleTimeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute(START_TIME, System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long start = (long) request.getAttribute(START_TIME);
request.setAttribute(HANDLE_TIME, System.currentTimeMillis() - start);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String uri = request.getRequestURI();
long consume = (long) request.getAttribute(HANDLE_TIME);
LOGGER.info('uri: {} consume {}s', uri, consume / 1000);
}
}
Upload
Spring MVC提供了对Servlet 3.0文件上传的支持(关于Servlet 3.0文件上传可参考博客Servlet – Upload、Download、Async、动态注册).
Spring MVC提供了MultipartFile接口,上传到应用中的文件都被包装在一个MultipartFile对象中:
MultipartFile | 描述 |
---|
String getName() | Return the name of the parameter in the multipart form. | String getOriginalFilename() | Return the original filename in the client’s filesystem. | long getSize() | Return the size of the file in bytes. | boolean isEmpty() | Return whether the uploaded file is empty, that is, either no file has been chosen in the multipart form or the chosen file has no content. | String getContentType() | Return the content type of the file. | byte[] getBytes() | Return the contents of the file as an array of bytes. | InputStream getInputStream() | Return an InputStream to read the contents of the file from. | void transferTo(File dest) | Transfer the received file to the given destination file. |
在Servlet 3.0及更高版本的容器中进行文件上传编程,总是围绕着@MultipartConfig注解和Part接口,处理上传文件的Servlet必须以@MultipartConfig注解标注, 但DispatcherServlet是Spring jar包已经编译好的类, 无法进行修改,值得庆幸的是Servlet 3.0还可以使用部署描述符web.xml将一个Servlet变为MultipartConfig Servlet:
mvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/mvc-servlet.xml
1
20848820
1048576
mvc
*.do
此外, 在mvc-servlet.xml文件中配置一个MultipartResolver:
此时就可以进行文件上传编程了:
@RequestMapping('/upload.do')
public String upload(MultipartFile file) throws IOException {
String name = file.getOriginalFilename();
String fileName = String.format('/data/file/%s', name);
file.transferTo(new File(fileName));
return 'file_upload';
}
Exception
系统异常包含两类: 预期异常、运行时异常RuntimeException.前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生.
基于Spring MVC的DAO、Service、Controller的异常都可以通过throw向上层抛出,最后统一由DispatcherServlet的异常处理器进行处理.
如果Controller/Service/DAO抛出此类异常说明是预期异常:
/**
* @author jifang.
* @since 2016/6/21 16:28.
*/
public class MVCException extends Exception {
private String message;
public MVCException(String message) {
super(message);
this.message = message;
}
@Override
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
}
/**
* @author jifang.
* @since 2016/6/21 16:33.
*/
public class MVCExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
String message;
if (ex instanceof MVCException) {
message = ex.getMessage();
} else {
message = '未知异常';
}
return new ModelAndView('error', 'message', message);
}
}
错误信息
${message}
JSON
JSON数据格式形式简单, 解析方便, 因此常用在接口调用、HTML页面中.
Spring MVC对其提供了如下支持:在Controller方法上添加@ResponseBody注解, Spring MVC会自动将Java对象转换成JSON字符串输出; 在方法形参上添加@RequestBody注解, Spring MVC会自动将JSON串转换成Java对象:
@ResponseBody
@RequestMapping('/user_json.do')
public User userJSON(@RequestBody User user) {
return user;
}
Spring MVC默认使用jackson对request/response进行JSON转换,而在此我们选用性能更高的fastjson, 因此需要在中另做配置.
首先, 使用fastjson需要在pom.xml中添加如下依赖:
com.alibaba
fastjson
1.2.7
然后在mvc-servlet.xml中做如下配置:
class='com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter'>
text/html;charset=UTF-8
application/json;charset=UTF-8
DisableCircularReferenceDetect
Other
1. POST Encoder
在web.xml配置一个编码Filter可以解决POST乱码问题:
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encodingFilter
/*
2. GET Encoder
对于GET乱码, 由于Tomcat 8.0之前版本默认使用ISO-8859-1编码, 因此有两种解决方案:
修改tomcat配置文件server.xml设置编码与工程编码一致:
将经Tomcat编码的内容解码后再重新编码为UTF-8:
String name = new String(request.getParamter('name').getBytes('ISO8859-1'),'utf-8');
注: Tomcat 8.0及更高版本的容器不用此配置.
3. Static Resources Mapping
如果将DispatherServlet配置成拦截所有请求/, 则必须额外配置静态资源的映射规则, 否则Spring MVC会对像js/css之类的文件也做转发.
Spring MVC使用元素配置对静态资源的映射:
|