主流框架三:SpringMVC(4)文件上传异常处理及拦截器
一、SpringMVC实现文件上传
1、原理分析
<form action="/user/fileupload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload" /><br/>
<input type="submit" value="上传" />
</form>
在jsp页面使用form表单进行文件的上传,使用 文件选择域< input type=”file” name=“upload”/>
2、上传的必要前提
1 form表单的enctype取值必须是:multipart/form-data (默认值是:application/x-www-form-urlencoded) enctype:是表单请求正文的类型
2 method属性取值必须是Post
3 提供一个文件选择域< input type=”file” />
3、传统的文件上传
传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上。 并且上传完成之后,浏览器可能跳转。
(1)前端文件上传页面
<form action="/user/fileupload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload" /><br/>
<input type="submit" value="上传" />
</form>
(2)写后端的控制器Controller
/**
* SpringMVC文件上传
* @return
*/
@RequestMapping("/fileupload2")
public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("springmvc文件上传...");
// 使用fileupload组件完成文件上传
// 上传的位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
// 判断,该路径是否存在
File file = new File(path);
if(!file.exists()){
// 创建该文件夹
file.mkdirs();
}
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}
(3)配置文件上传解析器
<!--配置文件上传解析器-->
id的值multipartResolver是固定的,文件上传的解析器id是固定的,不能起别的名称,否则无法实现请求参数的绑定。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760" />
</bean>
4、跨服务器方式的文件上传
在实际开发中,我们会有很多处理不同功能的服务器。
例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
编写前端上传的jsp页面
<h3>跨服务器文件上传</h3>
<form action="/user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload" /><br/>
<input type="submit" value="上传" />
</form>
/**
* 跨服务器文件上传
* @return
*/
@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/fileuploadserver/uploads/";
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 创建客户端的对象
Client client = Client.create();
// 和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
二、SpringMVC中的异常处理
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器HandlerExceptionResolver进行异常处理,如下图:
(1)先写一个异常类(对象)以及 自定义异常处理器
/**
* 自定义的异常类
*/
public class SysException extends Exception {
//存储提示信息的
private String message;
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message) {
this.message = message;
}
}
/**
* 异常的处理器
*/
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常的页面逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//获取到异常对象
SysException sysException = null;
if(e instanceof SysException) {
sysException = (SysException) e;
}else {
sysException = new SysException("系统正在维护...");
}
//创建modelandview对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",sysException.getMessage());
mv.setViewName("error");
return mv;
}
}
(2)错误页面和 在springmvc的配置文件中配置异常处理器
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>执行错误</h3>
${errorMsg}
</body>
</html>
<!-- 配置异常处理器-->
<bean id="sysExceptionResolver" class="com.itheima.exception.SysExceptionResolver"></bean>
当用户访问到/testException此路径时,就会抛出异常错误对象给异常处理器,异常处理器再跳转到错误页面。
/**
*
* @author Mango
*/
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testException")
public String testException() throws SysException {
System.out.println("方法执行");
try {
//模拟一个异常(由server的方法返回)
int i = 10/0;
} catch (Exception e) {
//打印异常信息
e.printStackTrace();
//向上抛出异常的信息
throw new SysException("查询用户出现了错误...");
}
return "success";
}
}
三、SpringMVC中的拦截器
Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。拦截器链(多个拦截器)就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
过滤器与拦截器他们的区别:
(1)过滤器是servlet规范中的一部分,任何java web工程都可以使用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
(2)过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的。 它也是AOP思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor接口。
(1)新建拦截器
/**
* 自定义的拦截器1
* @author Mango
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 预处理,Controller方法执行前
* @param request
* @param response
* @param handler
* @return true放行,执行下一个拦截器,直到执行方法,false不放行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...前111");
return true;
}
/**
* 后处理的方法:controller方法执行后,success.jsp执行之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后111");
}
/**
* success.jsp页面执行后,该方法执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后111");
}
}
(2)配置拦截器
<!-- 配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 你要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!-- 你不要拦击的具体方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置拦截器的对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
1、拦截器的放行
放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
2、拦截器方法的说明
/** * 如何调用:
* 按拦截器定义顺序调用
* 何时调用:
* 只要配置了都会调用
* 有什么用:
* 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去
* 进行处理,则返回true。
*
* 如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
* */
*
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
3、多个拦截器的执行顺序
多个拦截器是按照配置的顺序决定的。
流程测试:编写两个拦截器1和2
/**
* 自定义的拦截器1
* @author Mango
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 自定义的拦截器1
* @author Mango
*/
public class MyInterceptor2 implements HandlerInterceptor {
配置好拦截器
<!-- 配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 你要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!-- 你不要拦击的具体方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置拦截器的对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 你要拦截的具体方法-->
<mvc:mapping path="/**/"/>
<!-- 你不要拦击的具体方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置拦截器的对象-->
<bean class="com.itheima.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>