一.文件上传(重要)
1.文件上传分析
2.步骤
2.1 浏览器端要求(通用浏览器的要求)
- 表单提交方式 post
- 提供文件上传框(组件) input type=“file”
- 表单的entype属性必须为
multipart/form-data
(没有这个属性值的话, 文件的内容是提交不过去的)
创建update.html
2.2 服务器端要求
-
获取客户端上传的文件
- 准备一个目录存储客户端上传的文件
- 将客户端上传的文件写入到准备好的目录中
注意:
- 若表单使用了 multipart/form-data ,使用原生request.getParameter()去获取参数的时候都为null
2.3 所需组件
我们做文件上传一般会借助第三方组件(jar, 框架 SpringMVC)实现文件上传.
2.3.1 常见的文件上传jar包和框架
serlvet3.0(原生的文件上传的API)
commons-fileupload : apache出品的一款专门处理文件上传的工具包 (我们肯定不会直接使用)
struts2(底层封装了:commons-fileupload)
SpringMVC(底层封装了:commons-fileupload)
<dependencies>
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.4 springmvc.xml中配置文件上传解析器
<!--5.配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件上传的最大尺寸为5MB-->
<property name="maxUploadSize" value="5242880"></property>
</bean>
2.5 FileController
//1.在springmvc的配置文件中配置文件解析器,将字节输入流解析成MultipartFile对象
//2.在控制器方法中添加MultipartFile类型的参数
@RestController
@RequestMapping("/file")
public class FileController {
@RequestMapping("/upload")
public String upload(MultipartFile upload, String pdesc, HttpSession session) throws IOException {
//在部署的项目路径下准备一个upload目录
//upload这个形参要和前端的名字保持一致
ServletContext servletContext = session.getServletContext();
String realPath = servletContext.getRealPath("upload");
File file=new File(realPath);
if(!file.exists()){
file.mkdirs();
}
//获取文件名
String filename = upload.getOriginalFilename();
//使用文件输出流将客户端上传的文件输出到指定目录
FileOutputStream fileOutputStream = new FileOutputStream(new File(file, filename));
//客户端上传文件的输入流
InputStream inputStream = upload.getInputStream();
IOUtils.copy(inputStream, fileOutputStream);
inputStream.close();
fileOutputStream.close();
return "success";
}
二. 跨服务器方式的文件上传(了解)
1.需求
- 了解使用springmvc 跨服务器方式的文件上传
2.分析
2.1分服务器的目的
在实际开发中,我们会有很多处理不同功能的服务器(注意:此处说的不是服务器集群)。 例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理高并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
2.2跨服务器方式的文件上传图解
- 准备两个服务器(默认情况下,tomcat是不允许其他服务器往它里面写入数据的), 修改tomcat的的conf目录下的web.xml, 添加readonly参数为false
3.实现
- 添jersey依赖 (跨服务器上传图片的代码)
<dependencies>
<!--引入文件上传的依赖-->
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!--跨服务器上传的文件的依赖-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
</dependencies>
- 前端页面
<h1>二,springmvc 跨服务器方式的文件上传</h1>
<form action="/file/upload" method="post" enctype="multipart/form-data">
图片: <input type="file" name="upload"/><br/>
图片描述:<input type="text" name="pdesc"/>
<input type="submit" value="上传"/>
</form>
- 控制器
package com.itheima.controller;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* 跨服务器文件上传:
* 1. 使用springmvc的方式获取客户端上传的文件
* 2. 使用跨服务器上传文件的API,将图片上传到文件服务器
*/
@RestController
@RequestMapping("/file")
public class FileController {
/**
* 改成跨服务器文件上传
* @param upload
* @param pdesc
* @return
* @throws IOException
*/
@RequestMapping("/upload")
public String upload(MultipartFile upload, String pdesc) throws IOException {
System.out.println(pdesc);
try {
//获取文件名
String originalFilename = upload.getOriginalFilename();
//上传文件的路径
String uploadPath = "http://localhost:8899/upload/"+originalFilename;
//创建一个文件上传的客户端
Client client = Client.create();
//建立与服务器的连接
WebResource resource = client.resource(uploadPath);
//将文件上传给服务器
resource.put(upload.getBytes());
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
}
三. SpringMVC中的异常处理(了解)
SpringMVC 中的异常处理
1.目标
- 掌握SpringMVC的统一异常处理
2.分析
系统中异常包括两类:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理.
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
3.代码实现
3.1自定义异常处理器
package com.wjs.handler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 全局异常处理器:
* 作用: 处理整个项目中所有的controller抛出的异常
* 步骤: 1. 编写一个类实现HandlerExceptionResolver接口
* 2. 重写resolveException方法
* 3. 在springmvc的配置文件中,配置异常解析器
*/
public class GlobalExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//ex表示这次的异常信息,使用它可以收集异常信息
ex.printStackTrace();//这句代码仅仅是在控制台打印文件
//返回ModelAndView对象就必然要走视图解析器
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;
}
}
3.2配置异常处理器
- 在springmvc.xml配置
<bean id="sysExceptionResolver" class="com.itheima.handler.GlobalExceptionHandler"></bean>
四. SpringMVC 中的拦截器(掌握)
1.拦截器概述
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器(自己编写的Controller)进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
类别 | 使用范围 | 拦截范围 |
---|---|---|
拦截器 | SpringMVC项目 | 只会拦截访问的控制器方法的请求 |
过滤器 | 任何web项目 | 任何资源(servlet,控制器,jsp,html等) |
我们要想自定义拦截器, 要求必须实现: HandlerInterceptor 接口。
2.自定义拦截器入门
- 编写一个普通类实现 HandlerInterceptor 接口
package com.wjs.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器:
* 作用: 在执行controller的方法之前做预处理,以及执行controller的方法之后做后处理
* 步骤:
* 1. 写一个类实现HandlerInterceptor接口
* 2. 选择实现其中的方法:
* 1. preHandle() 在处理器方法之前执行
* 2. postHandle() 在处理器方法之后、视图渲染之前执行
* 3. afterCompletion() 在视图渲染之后执行,官方建议可以在该方法中做一些资源清理操作
* 3. 在springmvc配置文件中进行拦截器的配置(配置拦截器的拦截路径)
*/
public class PermissionInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("PermissionInterceptor的preHandle方法执行了...");
//返回值为true就是放行
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("PermissionInterceptor的postHandle方法执行了...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("PermissionInterceptor的afterCompletion方法执行了...");
}
}
- 在springmvc.xml配置拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.wjs"/>
<!--配置拦截器-->
<mvc:interceptors>
<!--
里面可以配置多个拦截器,每一个interceptor就是一个拦截器
-->
<mvc:interceptor>
<!--
mapping表示这个拦截器的拦截范围
-->
<mvc:mapping path="/**" />
<!--
exclude-mapping
-->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<!--
bean标签表示对我们要进行配置的拦截器做IOC
-->
<bean id="permissionInterceptor" class="com.wjs.interceptor.PermissionInterceptor"> </bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
3.拦截器的其它方法
- afterCompletion 在目标方法完成视图层渲染后执行。3
- postHandle 在目标方法执行完毕获得了返回值后执行(一定要经过handle,2)。
- preHandle 被拦截的目标方法执行之前执行。1
- 如果拦截器都是放行状态则1–>2–>3执行
- 如果被被拦截返回,postHandle是肯定不能执行的,afterCompletion是会被执行的
4 多个拦截器执行顺序
回想多个过滤器的执行顺序:
-
如果采用配置文件方式配置过滤器,那么就按照过滤器的配置先后顺序执行
2. 如果采用注解方式配置过滤器,那么就按照类名的排序执行
我们可以配置多个拦截器, 所以就存在一个优先级问题了.多个拦截器的优先级是按照配置的顺序决定的。