一、请求转发与重定向
1、请求转发是一次请求,转发之后地址栏不发生改变
2、重定向是两次请求,地址栏会发生改变
3、重定向时的网址可以是任何网址,转发的网址必须是本站点的网址
4、当两个资源文件之间需要传递数据的时候,使用转发
当两个资源文件不需要传递数据的时候,使用重定向
代码说明
//后端控制器
@Controller //该注解表明将当前类交给spring容器管理
@Scope("prototype")
@RequestMapping("/springmvc") //该注解起到限定范围的作用,类体的可以省略
public class MyController{
@RequestMapping("/hello")//方法体注解
public ModelAndView hello(@RequestParam("username")String name, int age){
ModelAndView mav = new ModelAndView();
mav.addObject("username",name);
mav.addObject("age", age);
//mav.setViewName("NewFile");请求转发
mav.setViewName("redirect:hello1");//重定向到另一个服务器方法
return mav;
}
二、文件上传:
导入jar包:
com.springsource.org.apache.commons.fileupload-1.2.0.jar
com.springsource.org.apache.commons.io-1.4.0.jar
修改jsp页面:
注意:
form表单中的enctype属性就是encodetype就是编码类型的意思
默认情况下,enctype的值是application/x-www-form-urlencoded,不能用于文件上传,只有使用了multipart/form-data,才能完整的传递文件数据。
<!-- 注册视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property><!-- 前缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
1、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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--注册后端控制器 -->
<!-- <bean id="/my.do" class="com.sxt.handlers.MyController"></bean> -->
<!-- 注册组件扫描器 base-package="所在包名"-->
<context:component-scan base-package="com.sxt.handlers"></context:component-scan>
<!-- 注册视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property><!-- 前缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 注解驱动 -->
<mvc:annotation-driven/>
<!-- 注册文件上传解析器 id名字不能随意起要用multipartResolver前端控制器会调用multipartResolver去查找bin -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/><!-- 解决乱码问题 -->
</bean>
<!-- 静态资源无法释放第二种解决方案 -->
<!-- <mvc:default-servlet-handler/> -->
<!-- 静态资源无法释放第二种解决方案 -->
<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
</beans>
2、单上传:
1)、jsp
<form action="springmvc/fileUpload" method="post" enctype="multipart/form-data">
名称:<input type="file" name="img"><br/>
<input type="submit" value="上传">
</form>
2)、controller
//后端控制器
@Controller //该注解表明将当前类交给spring容器管理
@Scope("prototype")
@RequestMapping("/springmvc") //该注解起到限定范围的作用,类体的可以省略
public class MyController{
@RequestMapping("/fileUpload")//方法体注解
public ModelAndView fileUpload(MultipartFile img){
ModelAndView mav = new ModelAndView();
String fileName = img.getOriginalFilename();//获取源文件名
String path = "D:/";//路径
File file = new File(path,fileName);
try {
img.transferTo(file);//文件上传
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mav.setViewName("NewFile");
return mav;
}
}
3、多文件上传
1)、jsp
<form action="springmvc/fileUpload" method="post" enctype="multipart/form-data">
<input type="file" name="imgs"><br/>
<input type="file" name="imgs"><br/>
<input type="file" name="imgs"><br/>
<input type="submit" value="上传">
</form>
2)、controller
//后端控制器
@Controller //该注解表明将当前类交给spring容器管理
@Scope("prototype")
@RequestMapping("/springmvc") //该注解起到限定范围的作用,类体的可以省略
public class MyController{
@RequestMapping("/fileUpload")//方法体注解
public String fileUpload(@RequestParam MultipartFile [] imgs,HttpSession session){
System.out.println("ok");
String path = session.getServletContext().getRealPath("/");//获取根路径
for (MultipartFile img : imgs) {
String fileName = img.getOriginalFilename();//获取源文件名
File file = new File(path,fileName);
try {
img.transferTo(file);//文件上传
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return "NewFile";
}
}
三、文件下载
1、流程
1)、指定下载文件
2)、获取流预估文件的字节数
3)、创建字节数组,并设置数组大小为流预估的文件字节数
4)、将输入流中字符存储到缓存数组中
5)、获取下载文件名,并解决中文乱码问题
6)、设置Http响应信息
7)、设置Http响应状态信息
2、代码实现
@RequestMapping("/fileDownload")//方法体注解
public ResponseEntity<byte []> download() throws Exception{
//指定下载文件
File file = new File("D:/Springmvc运行流程.png");
//获取流预估的文件字节数
FileInputStream is = new FileInputStream(file);
//创建字节数组,并设置数组大小为流预估的文件字节数
byte [] body= new byte[is.available()];
//将输入流中字符存储到缓存数组中
is.read(body);
//获取下载文件名,并解决中文乱码问题
String name = file.getName();
String downloadName = new String(name.getBytes("UTF-8"),"ISO-8859-1");
//设置Http响应信息,
HttpHeaders httpHandlers = new HttpHeaders();
httpHandlers.add("Content-Disposition","attchment;filename="+downloadName );
//设置Http响应状态信息
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<> (body,httpHandlers,status);
return entity;
}
四、自定义拦截器
1、创建前端控制器。
2、创建后端控制器。
3、创建jsp,form表单提交地址为后端控制器。
4、创建类,实现HandlerInterceptor接口,重写未实现方法。
接口内定义的方法:
preHandle,在处理器执行之前会触发这个postHandle拦截器的执行。该方法的返回值是boolean类型,如果返回结果为false,
则说明拦截,如果为true,则preHandle可以继续往下执行后端处理器方法。
postHandle,在处理器方法执行之后会触发这个preHandle拦截器的执行。该方法无返回值。
afterCompletion,在所有方法完成之后会触发afterCompletion拦截器的执行,
按SpringMVC流程来说应该是在要响应给浏览器的时候触发这个拦截器的执行。该方法无返回值。
5、在SpringMVC的配置文件中进行注册。
配置
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有-->
<mvc:mapping path="/**" />
<!-- 不包括/springmvc/hello2-->
<mvc:exclude-mapping path="/springmvc/hello2"/>
<!-- 只拦截/springmvc/hello2 -->
<!-- <mvc:mapping path="/springmvc/hello2" /> -->
<!-- 注册自定义拦截器 -->
<bean id="handelInterceptor" class="com.interceptor.HandelInterceptor"></bean>
</mvc:interceptor>
自定义拦截器类(注意需实现HandlerInterceptor接口)
//自定义拦截器
public class FirstInterceptor implements HandlerInterceptor {
//该方法执行时机,所有工作处理完成之后,响应给浏览器客户端之前
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("afterCompletion执行");
}
//该方法执行时机,处理器方法执行之后
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("postHandle执行");
}
//该方法执行时机,处理器方法执行之前
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("执行preHandle()方法");
return true;//返回false不能向下继续执行,返回true
}
}
多个自定义拦截器执行顺序(注意与在springmvc中的配置顺序有关)
代码:
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/><!-- 拦截所有 -->
<bean id="" class="com.sxt.interceptor.FirstInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/><!-- 拦截所有 -->
<bean id="" class="com.sxt.interceptor.SecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
结果
preHandle源码:
1、找到applyPreHandle方法。
2、方法内部,getInterceptors()获得所有的拦截器,然后判断拦截器是否为空,如果不为空,则执行循环。
目前是两个拦截器,那么执行for循环,for循环中i目前为0,小于2个拦截器的长度,执行for循环。
在for循环中将i=0赋值给interceptor。继续执行if语句。
if语句,第一个拦截器中的preHandle方法,目前返回为true,但是取反就是false,那么if语句就不再执行,跳出if语句,将i赋值给临时变量interceptorIndex。
当循环到i++=2的时候,判断条件就不成立了,就跳出循环,此时的interceptorIndex=1;
也就是说preHandle执行顺序,先执行第一个,然后执行第二个,最后返回为true。
Spring和SpringMVC关系:
在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的。
而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上下层关系。
目前最常见的一种场景就是在一个项目中引入Spring和SpringMVC这两个框架,那么它其实就是两个容器,Spring是父容器,SpringMVC是其子容器,
并且在Spring父容器中注册 的Bean对于SpringMVC容器中是可见的,而在SpringMVC容器中注册的Bean对于Spring父容器 中是不可见的,
也就是子容器可以看见父容器中的注册的Bean,反之就不行。