Spring MVC 实践 - Component
2016-07-05 15:26
459 查看
Spring MVC 实践
标签 : Java与WebConverter
Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: Spring总是试图用默认的语言区域将日期输入绑定到java.util.Data, 如果想要使用不同的日期格式(format),就需要
Converter的协助.
Spring提供了
Converter接口来供开发者自定义
Converter类:
/** * @since 3.0 * @param <S> the source type * @param <T> the target type */ public interface Converter<S, T> { T convert(S source); }
自定义
Converter:
/** * @author jifang. * @since 2016/6/19 7:23. */ public class StringDateConverter implements Converter<String, Date> { 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:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.fq.mvc.converter.StringDateConverter"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd hh:mm:ss"/> </bean> </set> </property> </bean>
然后为
<annotation-driven/>配置
conversion-service属性:
<mvc:annotation-driven conversion-service="conversionService"/>
注: 还可以使用
FormattingConversionServiceFactoryBean来加载
Converter, 由于其配置方法与
ConversionServiceFactoryBean, 故在此就不再赘述.
Controller
@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执行耗时.
自定义
Interceptor
/** * @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); } }
配置
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.fq.mvc.interceptor.HandleTimeInterceptor"/> </mvc:interceptor> </mvc:interceptors>
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. |
@MultipartConfig注解和
Part接口,处理上传文件的Servlet必须以
@MultipartConfig注解标注, 但
DispatcherServlet是Spring jar包已经编译好的类, 无法进行修改,值得庆幸的是Servlet 3.0还可以使用部署描述符web.xml将一个Servlet变为MultipartConfig Servlet:
<servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/mvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <multipart-config> <max-file-size>20848820</max-file-size> <file-size-threshold>1048576</file-size-threshold> </multipart-config> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
此外, 在mvc-servlet.xml文件中配置一个MultipartResolver:
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
此时就可以进行文件上传编程了:
@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); } }
error.vm
<html> <head> <title>错误信息</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> </head> <body> ${message} </body> </html>
注册异常处理器
<bean class="com.fq.mvc.exception.MVCExceptionResolver"/>
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; }
fastjson
Spring MVC默认使用jackson对
request/
response进行JSON转换,而在此我们选用性能更高的fastjson, 因此需要在
<annotation-driven/>中另做配置.
首先, 使用fastjson需要在pom.xml中添加如下依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency>
然后在mvc-servlet.xml中做如下配置:
<mvc:annotation-driven> <mvc:message-converters register-defaults="false"> <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> <property name="features"> <array value-type="com.alibaba.fastjson.serializer.SerializerFeature"> <value>DisableCircularReferenceDetect</value> </array> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
Other
1. POST Encoder
在web.xml配置一个编码Filter可以解决POST乱码问题:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2. GET Encoder
对于GET乱码, 由于Tomcat 8.0之前版本默认使用ISO-8859-1编码, 因此有两种解决方案:
修改tomcat配置文件
修改tomcat配置文件server.xml设置编码与工程编码一致:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
重新编码
将经Tomcat编码的内容解码后再重新编码为UTF-8:
String name = new String(request.getParamter("name").getBytes("ISO8859-1"),"utf-8");
注: Tomcat 8.0及更高版本的容器不用此配置.
3. Static Resources Mapping
如果将DispatherServlet配置成拦截所有请求
<url-pattern>/</url-pattern>, 则必须额外配置静态资源的映射规则, 否则Spring MVC会对像js/css之类的文件也做转发.
Spring MVC使用
<mvc:resources/>元素配置对静态资源的映射:
<mvc:resources location="/js/" mapping="/js/**"/>
相关文章推荐
- upload上传单张图片
- 三种禁用FileSystemObject组件的方法
- 用vbs列出机器上所有能调用的组件
- extjs 为某个事件设置拦截器
- 剖析ASP.NET MVC的DependencyResolver组件
- asp水印组件之AspJpeg的结合代码实例
- Node.js编写组件的三种实现方式
- Bootstrap表单组件教程详解
- JS上传组件FileUpload自定义模板的使用方法
- 适用于WebForm Mvc的Pager分页组件C#实现
- js组件SlotMachine实现图片切换效果制作抽奖系统
- Android搜索框组件SearchView的基本使用方法
- 浅析Bootstrap缩略图组件与警示框组件
- 第九章之路径分页标签与徽章组件
- JS组件Bootstrap ContextMenu右键菜单使用方法
- JavaScript资源预加载组件和滑屏组件的使用推荐
- 浅谈Sticky组件的改进实现
- 编写轻量ajax组件01-与webform平台上的各种实现方式比较
- Ajax核心XMLHTTP组件资料第1/2页
- JS组件系列之Bootstrap Icon图标选择组件