😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
使用ResponseEntity实现下载文件的功能
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
System.out.println(realPath);
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组
//is.available() 获取输入流所对应文件的所有字节数
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字 固定格式
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
/*
三个参数
bytes:需要下载文件的所有字节(响应体)
headers:响应头
statusCode:响应状态码(200,404….)
*/
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
文件上传要求:不可以用get请求,
post请求
enctype=“multipart/from-data” ,当前form表单中数据,就不是name=value的方式传输到服务器,而是通过二进制的方式
SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//获取上传的文件的后缀名
// 截取最后一次出现 . 的位置 到最后
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//将UUID作为文件名 // replaceAll("-",""); - 替换为 空
String uuid = UUID.randomUUID().toString().replaceAll("-","");
//将uuid和后缀名拼接后的结果作为最终的文件名
fileName = uuid + suffixName;
//通过ServletContext获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
//判断photoPath所对应路径是否存在
if(!file.exists()){
//若不存在,则创建目录
file.mkdir();
}
// 拼接全路径 File.separator 文件分割符
//(没有文件服务器,传入到tomcat中)上传 到 部署服务器 的photo目录下(不存在新创建)
// [E:\tomcat\apache-tomcat-9.0.56\webapps\ROOT\photo\5aa04da74d3d4c5dbe14475bfd5c6d52.png]
String finalPath = photoPath + File.separator + fileName;
//上传文件
photo.transferTo(new File(finalPath));
return "success";
}
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
<!--配置方式一: bean-->
<mvc:interceptors>
<!--所写的拦截器 路径-->
<!--一个bean就是IOC的组件(对象) 表示某一个类型的对象就是一个拦截器-->
<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>
<!--配置方式二: ref-->
<!--ref引用IOC容器中的某个bean的id,引用某一个拦截器的id-->
<mvc:interceptors>
<!--所写的拦截器 类名 需要使用普通组件注解@Component 表示为IOC容器 + 扫描 -->
<ref bean="firstInterceptor"></ref>
</mvc:interceptors>
<!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截,没有办法设置拦截规则 -->
<!--配置方式三:--> (推荐)
<mvc:interceptors>
<mvc:interceptor>
<!--需要拦截的请求-->
<mvc:mapping path="/**"/>
<!--需要排除的请求,即不需要拦截的请求-->
<mvc:exclude-mapping path="/testRequestEntity"/>
<!--和上面的两种写法一样 bean 或者 ref-->
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
<!--
以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求
-->
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJFkBx9b-1656212021942)(文件上传和下载.assets/image-20220625123321996.png)]](https://1000bd.com/contentImg/2022/06/27/192623994.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZF41yg3G-1656212021943)(文件上传和下载.assets/image-20220626105110870.png)]](https://1000bd.com/contentImg/2022/06/27/192624290.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6pxlv6l-1656212021943)(文件上传和下载.assets/image-20220625123433331.png)]](https://1000bd.com/contentImg/2022/06/27/192624546.png)
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 调用当前所有的拦截器的 PreHandle 方法
// mappedHandler 执行链 存放的是 执行的控制器方法 + 3个处理控制器方法的拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 控制器方法的执行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
// 调用当前所有的拦截器的 PostHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//processDispatchResult 里面有个 render方法 来渲染视图
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
this.render(mv, request, response); // 渲染视图来对 ModelAndView进行处理
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
// triggerAfterCompletion 拦截器的三个方法 在渲染视图完毕之后
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
postHandle:控制器方法执行之后执行postHandle()
afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3GWwVfCK-1656212021944)(文件上传和下载.assets/image-20220625123517430.png)]](https://1000bd.com/contentImg/2022/06/27/192624821.png)
preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
作用:在控制器方法执行时,出现异常,返回新的ModelAndView,跳转到制定页面
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
properties的键表示处理器方法执行过程中出现的异常
properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--
exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
error 页面
<body>
出现错误
<p th:text="${ex}"></p>
</body>
//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(ArithmeticException.class)
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}