1. SpringMVC的文件上传
1.1 文件上传的必要前提
1.2 SpringMVC实现文件上传
- 添加maven依赖坐标
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
|
- springmvc.xml中配置文件解析器
需要注意的是,这里的id必须叫做multipartResolver,不能自己乱改
1 2 3
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760" /> </bean>
|
- html
注意这里的
method=”post”
enctype=”multipart/form-data”
不能变
name=”upload”可以改,但是要和下面的controller层接收方法的参数名一致
1 2 3 4
| <form action="user/fileUpload2" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload" /><br /> <input type="submit" value="上传"> </form>
|
- controller
注意这里的参数名upload要和html表单的文件的name属性名一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @RequestMapping("/fileUpload2") public String fileUpload2(HttpServletRequest request, MultipartFile upload) thro String path = request.getSession().getServletContext().getRealPath("/uploads File file = new File(path); //如果不存在,就创建 if (!file.exists()){ //创建文件夹 file.mkdirs(); } //获取上传文件名称 String fileName = upload.getOriginalFilename(); //为了两次上传导致文件名相同而冲突,所以我们用uuid设置filename String uuid = UUID.randomUUID().toString().replace("-", ""); // 完成文件上传 fileName = uuid + "_" + fileName; upload.transferTo(new File(path, fileName)); return "success"; }
|
1.3 jersey跨服务器上传
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
1.3.1 步骤
- 新增pom坐标
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.19.4</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.19.4</version> </dependency>
|
- 创建新的module或者project作为图片服务器,并配置好tomcat(详情略),要注意在target中手动创建文件夹,tomcat两个端口不能冲突
- html同上
1 2 3 4
| <form action="user/fileUpload3" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload" /><br /> <input type="submit" value="上传"> </form>
|
- controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @RequestMapping("/fileUpload3") public String fileUpload3(MultipartFile upload) throws Exception { String path = "http://localhost:9090/uploads/"; String fileName = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replace("-", ""); fileName = uuid + "_" + fileName; Client client = Client.create(); WebResource webResources = client.resource(path + fileName); webResources.put(upload.getBytes()); return "success"; }
|
1.3.2 常见错误的解决:
403错误
权限问题
打开tomcat安装目录apache-tomcat-8.5.46\conf\web.xml,ctrl+F搜索<servlet-name>default</servlet-name>
找到如下图所示的位置,在如下图位置加入
1 2 3 4
| <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>
|
效果如下
404错误
目录问题,fileupload的tomcat配置改为根目录即可
或者你不想改虚拟目录,那就要在应用服务器这边把上传的图片服务器的路径中加入刚刚的虚拟目录也是可以的
405错误
同403错误
409错误
文件夹为空问题,因为上传图片的目录是uploads,所以手动在图片服务器的target目录创建uploads文件夹
500错误
原因复杂
2. SpringMVC异常处理
为了避免浏览器直接弹出错误
让界面友好一点(比如页面提示系统正在维护中),我们可以通过异常处理器来跳转错误页面
springmvc.xml中
id只能是这个名字sysExceptionResolver,不能乱改
1 2
| <bean id="sysExceptionResolver" class="com.wjw.exception.SysExceptionResolver"/>
|
接下来我们创建并完成这两个类
自定义一个异常类SysException,继承Exception(像实体类那样的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class SysException extends Exception { private String message;
public SysException(String message) { this.message = message; }
@Override public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; } }
|
SysExceptionResolver类
实现HandlerExceptionResolver接口,异常处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class SysExceptionResolver implements HandlerExceptionResolver {
@Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { SysException ex = null; if (e instanceof SysException){ ex = (SysException)e; }else { ex = new SysException("系统正在维护"); } ModelAndView mv = new ModelAndView(); mv.addObject("errorMsg", e.getMessage()); mv.setViewName("error"); return mv; } }
|
使用方法如下
3. SpringMVC拦截器
跟servlet中的过滤器filter一样,改名拦截器。有一丢丢不同,拦截器不会拦jsp,html,css,images等静态资源,但是过滤器如果配置了/*,全部都会拦下来。
3.1 xml方式
- springmvc.xml中
1 2 3 4 5 6 7 8 9 10 11
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/*"/> <bean class="com.wjw.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
|
- 自定义拦截器类
- 实现HandlerInterceptor接口
- preHandle:预处理 controller方法前执行
- postHandle:后处理 controller方法后,jsp/html执行之前
- afterCompletion:最后处理 页面执行后执行的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| 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("afterCompletion方法"); } }
|
实现HandlerInterceptor接口需要实现三个方法,为了偷懒,可以
extends HandlerInterceptorAdapter
HandlerInterceptorAdapter是HandlerInterceptor接口的默认实现类,那么你需要哪个方法就overwrite哪个方法就行,其他写法上是一样的。
不使用xml的方式
spring当然也支持java配置类的方式,何况如果使用了springboot使用java配置类就更多了
- 拦截器还是跟上面一样实现HandlerInterceptor接口或者继承HandlerInterceptorAdapte类,但是要在类上方加上@Component注解
- xml不需要了,创建一个java配置类,实现WebMvcConfigurer接口,复写addInterceptors方法,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11
| @Configuration public class WjwMvcConfiguration implements WebMvcConfigurer {
@Autowired private LoginInterceptor loginInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); } }
|