SpringMVC基础(二)_文件上传、异常处理、拦截器
实现文件上传
实现文件上传,需要借助以下两个第三方 jar 包对上传的二进制文件进行解析:
form表单的 enctype 取值必须为:multipart/form-data(默认为:application/x-www-form-urlencoded);enctype为表单请求正文的类型;method 属性必须取值为 post 方式;提供一个文件选择域: <input type="file"/>
;
<form action="fileUpload/fileUploadOld" method="post" enctype="multipart/form-data"> <input type="file" name="fileUpload"/><br/> <input type="submit" value="上传"/> </form>
1、传统文件上传方式
@RequestMapping(value = "/fileUploadOld", method = RequestMethod.POST) public String fileUploadOld(HttpServletRequest request) throws Exception { //获取上传文件存放位置:绝对路径 String path = request.getServletContext().getRealPath("/uploads/"); //判断文件是否存在 File file = new File(path); if (!file.exists()) { file.mkdirs();//不存在则创建文件 } //解析request对象,获取文件上传项 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items = upload.parseRequest(request); //遍历 for (FileItem item : items) { //判断item对象是否表单项 if (item.isFormField()) { //true,表明是普通表单 } else { //false,表明是上传文件项 //获取上传文件名称 String fileName = item.getName(); //把文件名称设置为唯一值 String uuid = UUID.randomUUID().toString().replace("-", ""); fileName = uuid + "_" + fileName; request.setAttribute("fileName", fileName); //完成文件上传 item.write(new File(path, fileName)); //删除临时文件 item.delete(); } } return "succeed"; }
2、Spring MVC 文件上传
原理:文件上传请求发送到前端控制器时,会转给文件解析器并返回文件上传项,然后前端控制器将文件上传项发送到控制器方法,最后完成上传操作;
注意:
- 控制器方法中使用 MultipartFile 对象;
- MultipartFile 对象名称必须要与请求参数名称一致;
- 配置文件解析器 CommonsMultipartResolver 时,ID值必须为 multipartResolver;
代码实现
@RequestMapping(value = "/fileUploadMvc", method = RequestMethod.POST) public String fileUploadMvc(HttpServletRequest request, MultipartFile fileUpload) { //获取上传文件存放位置:绝对路径 String path = request.getServletContext().getRealPath("/uploads/"); //判断文件是否存在 File file = new File(path); if (!file.exists()) { file.mkdirs();//不存在则创建文件 } //获取上传文件名 String filename = fileUpload.getOriginalFilename(); //把文件名称设置为唯一值 String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; //上传文件 try { fileUpload.transferTo(new File(path, filename)); } catch (IOException e) { e.printStackTrace(); } return "succeed"; }
Spring MVC配置文件中配置 CommonsMultipartResolver
<!--配置文件解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--设置最大上传文件的大小:10M--> <property name="maxUploadSize" value="10485760"/> </bean>
3、跨服务器实现文件上传
分服务器的目的:让服务器各司其职,从而提高项目的运行效率;在实际开发中,会有很多处理不同功能的服务器。例如:
- 应用服务器:负责部署我们的应用;
- 数据库服务器:运行我们的数据库;
- 缓存和消息服务器:负责处理大并发访问的缓存和消息;
- 文件服务器:负责存储用户上传文件的服务器;
部署多台服务器的操作
部署两台服务器,并创建一个用于存放图片的 Web 工程;
配置存放图片的服务器可以支持写入操作;
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
实现跨服务器文件上传
@RequestMapping(value = "/fileUploadMultiServer", method = RequestMethod.POST) public String fileUploadMultiServer(MultipartFile fileUpload) { //定义上传文件存放服务器位置:绝对路径 String path = "服务器域名/URI"; //声明上传文件项 //获取上传文件名称 String filename = fileUpload.getOriginalFilename(); //把文件名称设置为唯一值 String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; /* 完成文件上传,跨服务器上传 (1)创建客户端对象; (2)和FileServer服务器进行连接; (3)上传文件 */ //创建 sun 公司提供的 jersey 包中的 Client 对象 Client client= Client.create(); //指定上传文件的地址,该地址是 web 路径 WebResource webResource = client.resource(path + filename); try { webResource.put(fileUpload.getBytes()); } catch (IOException e) { e.printStackTrace(); } return "succeed"; }
Spring MVC配置文件中配置 CommonsMultipartResolver
<!--配置文件解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--设置最大上传文件的大小:10M--> <property name="maxUploadSize" value="10485760"/> </bean>
注意
- 图片上传不能包含特殊字符和中文;会报400或IllegalArgumentException错误;
- Spring MVC实现跨服务器文件上传可能出现的问题
异常处理
1、异常处理的思路
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试手段减少运行时异常的发生;
Spring MVC项目中的 dao、service、controller 出现的异常都通过 throws Exception 向上抛出,最后,要么由浏览器输出异常信息,要么在前端控制器中通过异常解析器进行异常处理;
2、异常解析器处理异常步骤
自定义异常类;
package spitter.exception; /** * 自定义异常类 */ public class SystemException extends Exception{ //存储异常信息 private String massage; public SystemException(String massage) { this.massage = massage; } public String getMassage() { return massage; } public void setMassage(String massage) { this.massage = massage; } }
定义异常处理器:该类实现HandlerExceptionResolver,并重写resolveException方法;
package spitter.exception; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 自定义异常处理器 */ public class SystemExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex ) { //获取异常对象 SystemException se=null; if (e instanceof SystemException){ se= (SystemException) ex; }else { se=new SystemException("系统正在维护..."); } ModelAndView mav=new ModelAndView(); mav.addObject("error",se.getMassage()); mav.setViewName("error"); return mav; } }
Spring MVC配置文件中配置异常处理器;
<!--装配异常处理器--> <bean id="systemExceptionResolver" class="spitter.exception.SystemExceptionResolver"/>
3、resolveException 方法
- HttpServletRequest:当前请求的请求对象;
- HttpServletResponse:当前请求的响应对象;
- Object:当前处理器的对象;
- Exception:当前抛出的异常对象;
- 返回值:ModelAndView 对象;可以进行数据传输和页面跳转;
拦截器
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能;
拦截器链(Interceptor Chain):拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用;
拦截器和过滤器的区别
- 过滤器:是 servlet 规范中的一部分,任何java web工程都可以使用;拦截器是 SpringMVC 框架独有,只有 SpringMVC 框架的工程才能使用;
- 过滤器:在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截;拦截器它是只会拦截访问的控制器方法,不拦截静态资源的访问(jsp,html,css等);
自定义拦截器步骤
自定义拦截器类,该类实现HandlerInterceptor接口;
preHandle()
:访问控制器前执行。返回true,访问控制器;false则不访问,此时,可使用请求对象和响应对象通过请求转发或重定向进行页面跳转;postHandle()
:访问控制器后执行。如果此处进行页面跳转,则控制器返回的视图名失效;afterCompletion()
:页面加载后执行;
package spitter.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 自定义拦截器 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器前置方法执行..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器后置方法执行..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("页面加载完成,拦截器方法执行..."); } }
配置拦截器:;配置元素:
<mvc:interceptors>
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--指定拦截的 URL--> <mvc:mapping path="/interceptor/myInterceptor"/> <!--指定不拦截的 URL <mvc:exclude-mapping path=""/>--> <!--配置拦截器对象--> <bean class="spitter.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
拦截器可配多个,执行顺序从上到下
此上,Spring MVC基础学习已经完成。