springmvc
1 springmvc初识
1.1 第一个基于注解的 SpringMVC程序
所谓 SpringMVC 的注解式开发是指,在代码中通过对类与方法的注解,便可完成处理器在 springmvc 容器的注册。注解式开发是重点
完成功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息,在响应页面中显示该信息
1.1.1 新建maven项目导入web骨架支持
1.1.2 pom.xml
servlet依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
springmvc依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
插件
<build>
<plugins>
<!-- 编码和编译和JDK版本 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
1.1.3 注册中央调度器
在web.xml中配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--
1、声明和注册springmvc的核心对象DispatcherServlet
2、需要在tomcat服务器启动后,创建DispatcherServlet对象的实例。
3、为什么要创建DispatcherServlet对象的实例呢?
4、因为DispatcherServlet在他的创建过程中, 会同时创建springmvc容器对象,
读取springmvc的配置文件,把这个配置文件中的对象都创建好, 当用户发起
请求时就可以直接使用对象了。
servlet的初始化会执行init()方法。
DispatcherServlet在init()中{
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入到ServletContext中
getServletContext().setAttribute(key, ctx);
}
启动tomcat报错,读取这个文件 /WEB-INF/springmvc-servlet.xml(/WEB-INF/myweb-servlet.xml)
springmvc创建容器对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml
-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--自定义springmvc读取的配置文件的位置-->
<init-param>
<!--springmvc的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
在tomcat启动后,创建Servlet对象
load-on-startup:表示tomcat启动后创建对象的顺序。它的值是整数,数值越小,
tomcat创建对象的时间越早。 大于等于0的整数。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<!--
使用框架的时候, url-pattern可以使用两种值
1. 使用扩展名方式, 语法 *.xxxx , xxxx是自定义的扩展名。 常用的方式 *.do, *.action, *.mvc等等
不能使用 *.jsp
http://localhost:8080/myweb/some.do
http://localhost:8080/myweb/other.do
2.使用斜杠 "/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
1.1.3.1 全限定性类名
该中央调度器为一个 Servlet,名称为 DispatcherServlet。中央调度器的全限定性类名在导入的 Jar 文件 spring-webmvc-5.2.5.RELEASE.jar 的第一个包
org.springframework.web.servlet下可找到
1.1.3.2 <load-on-startup/>
在<servlet/>
中添加<load-on-startup/>
的作用是,标记是否在Web服务器(这里是Tomcat)启动时会创建这个 Servlet 实例,即是否在 Web 服务器启动时
调用执行该 Servlet 的 init()方法,而不是在真正访问时才创建。它的值必须是一个整数。
1、当值大于等于 0 时,表示容器在启动时就加载并初始化这个 servlet,数值越小,该 Servlet的优先级就越高,其被创建的也就越早;
2、当值小于 0 或者没有指定时,则表示该 Servlet 在真正被使用时才会去创建。
3、当值相同时,容器会自己选择创建顺序
1.1.3.3 <url-pattern/>
对于<url-pattern/>
,可以写为 / ,建议写为*.do 的形式
1.1.4 创建 SpringMVC 配置文件
在工程的类路径即 src/main/resources 目录下创建 SpringMVC 的配置文件 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--声明组件扫描器-->
<context:component-scan base-package="com.zwh.controller"/>
<!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/" />
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp" />
</bean>
</beans>
1.1.5 创建处理器
//@Controller:创建处理器对象,对象放在springmvc容器中。
@Controller
public class MyController {
/**
* 准备使用doSome方法处理some.do请求。
*
* @RequestMapping: 请求映射,作用是把一个请求地址和一个方法绑定在一起,一个请求指定一个方法处理。
* 属性: 1. value 是一个String,表示请求的uri地址的(some.do)。
* value的值必须是唯一的, 不能重复。 在使用时,推荐地址以“/”
* 位置:1.在方法的上面,常用的。 2.在类的上面
* <p>
* 说明: 使用RequestMapping修饰的方法叫做处理器方法或者控制器方法。
* 使用@RequestMapping修饰的方法可以处理请求的,类似Servlet中的doGet, doPost
* <p>
* 返回值:ModelAndView 表示本次请求的处理结果
* Model: 数据,请求处理完成后,要显示给用户的数据
* View: 视图, 比如jsp等等。
*/
@RequestMapping(value = "/hello.do")
public ModelAndView doSome() {
System.out.println("处理hello请求中");
// 调用service处理请求,把处理结果放入到返回值ModelAndView
ModelAndView mv = new ModelAndView();
// addObject()方法用于向其 Model 中添加数据。Model 的底层为一个 HashMap。
mv.addObject("msg", "使用注解的springMVC应用");
mv.setViewName("hello");
// Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图,本次请求结束,模型中的数据被销毁
return mv;
}
}
1.1.6 声明组件扫描器
<!--声明组件扫描器-->
<context:component-scan base-package="com.zwh.controller"/>
1.1.7 自定义目标页面
这里我们将目标jsp页面都放在web-inf下的view包中,目的是让用户不能直接访问
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>msg数据:${msg}</h1>
</body>
</html>
测试结果:msg数据:使用注解的springMVC应用
1.2 SpringMVC 执行 执行 流程 ( 理解)
流程图:
执行流程简单分析:
- 浏览器提交请求到中央调度器
- 中央调度器直接将请求转给处理器映射器。
- 处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后返回给中央调度器。
- 中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器
- 处理器适配器调用执行处理器。
- 处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器
- 处理器适配器直接将结果返回给中央调度器。
- 中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象
- 视图解析器将封装了的视图对象返回给中央调度器
- 中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
- 中央调度器响应浏览器。
2 SpringMVC注解式开发
2.1 @RequestMapping 定义请求规则
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
通俗讲就好比商品的增删改:都会有前缀,goods/add goods/delete goods/update
这时候就可以在类上添加@RequestMapping(value = “/goods”)
那么方法上就可以直接@RequestMapping(value = “/add”)@RequestMapping(value = “/update”),但是他们都同时具有了父路径/goods
对请求提交方式的定义:
对于@RequestMapping,其有一个属性 method,就是限制请求是采用post还是get方式
当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。
2.2 接收前端参数及post乱码问题
1、若表单的name属性值与方法参数一致直接取即可
2、若表单的name属性值与方法参数不一致,则在参数前添加@RequestParam(value = “aname”),进行指定name的属性值即可
post请求乱码问题(web.xml):
<!--注册声明过滤器,解决post请求乱码的问题-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置项目中使用的字符编码-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制应答对象(HttpServletResponse)使用encoding编码的值-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!--
/*:表示强制所有的请求先通过过滤器处理。
-->
<url-pattern>/*</url-pattern>
</filter-mapping>
2.3 处理器方法的返回值
- 1、 ModelAndView
若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好
- 2、String
返回内部资源逻辑视图名,这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI
- 3、 object
演示:返回学生对象到浏览器
-
- 导入 jackson 依赖
<!--Jackson应该是目前比较好的json解析工具了--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.0</version> </dependency>
-
- 引入 jQuery 库
<script src="js/jquery-3.4.1.js"></script>
-
- 定义 index 页面
<html> <head> <title>$Title$</title> </head> <script src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> $(function () { $("button").click(function () { $.ajax({ url: "/json1.do", success: function (data) { // JSON.stringify将json数据转换成json字符串 document.write(JSON.stringify(data)); } }) }) }) </script> <body> <button>提交ajax请求</button> </body> </html>
-
- 定义对象 Student
@Data public class Student { private String name; private Integer age; }
-
- 修改处理器类 MyController
//在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody @RestController public class MyController { //produces:指定响应体返回类型和编码 @RequestMapping(value = "/json1.do") public String json1() throws JsonProcessingException { //创建一个jackson的对象映射器,用来解析数据 ObjectMapper mapper = new ObjectMapper(); //创建一个对象 Student student = new Student("张三", 10); //将我们的对象解析成为json格式 String str = mapper.writeValueAsString(student); //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便 return str; } }
-
- springmvc配置文件
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!--注册mvc注解驱动以及处理JSON乱码问题配置--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <!--声明组件扫描器--> <context:component-scan base-package="com.zwh.controller"/> <!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀:视图文件的路径--> <property name="prefix" value="/WEB-INF/view/"/> <!--后缀:视图文件的扩展名--> <property name="suffix" value=".jsp"/> </bean> </beans>
-
- web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>myweb</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myweb</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!--注册声明过滤器,解决post请求乱码的问题--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--设置项目中使用的字符编码--> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <!--强制请求对象(HttpServletRequest)使用encoding编码的值--> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <!--强制应答对象(HttpServletResponse)使用encoding编码的值--> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <!-- /*:表示强制所有的请求先通过过滤器处理。 --> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
- 4、 void
对于处理器方法返回 void 的应用场景,AJAX 响应
jQuery.ajax:
jQuery.ajax(...)
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
这里就不做演示,和返回对象类型差不多,只是处理器方法返回值为void,不能表示数据,也没有视图。
所以可以通过httpServletResponse的输出对象,把数据输出到浏览器
-
5、json输出时间对象
-
默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
-
Jackson 默认是会把时间转成timestamps形式
解决方法:封装工具类
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object, "yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object, String dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//不使用时间差的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
2.4 FastJson
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
fastjson 的 pom依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三个主要的类:
- JSONObject 代表 json 对象
- JSONArray 代表 json 对象数组
- JSON 代表 JSONObject和JSONArray的转化
代码测试,我们新建一个MyTest类
public class MyTest {
public static void main(String[] args) {
//创建一个对象
Student Student1 = new Student("1号", 3);
Student Student2 = new Student("2号", 3);
Student Student3 = new Student("3号", 3);
Student Student4 = new Student("4号", 3);
List<Student> list = new ArrayList<Student>();
list.add(Student1);
list.add(Student2);
list.add(Student3);
list.add(Student4);
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>" + str1);
String str2 = JSON.toJSONString(Student1);
System.out.println("JSON.toJSONString(Student1)==>" + str2);
System.out.println("\n****** JSON字符串 转 Java对象*******");
Student jp_Student1 = JSON.parseObject(str2, Student.class);
System.out.println("JSON.parseObject(str2,Student.class)==>" + jp_Student1);
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(Student2);
System.out.println("(JSONObject) JSON.toJSON(Student2)==>" + jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象 ******");
Student to_java_Student = JSON.toJavaObject(jsonObject1, Student.class);
System.out.println("JSON.toJavaObject(jsonObject1, Student.class)==>" + to_java_Student);
}
}
2.5 解读<url-pattern/>
1、配置详解
-
*.do
在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 的常使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等
-
/
可以写为/,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、.js、.jpg、.png等资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误.
*保持<url-pattern/>
的值为 .do,扩展名方式,图片会正常显示,将<url-pattern/>
的值修改为 / ,则图片将无法显示。
2、静态资源访问
<url-pattern/>
的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。
方法一:
在web.xml中配置:
<!--处理静态资源访问-->
<mvc:default-servlet-handler/>
方法二:
在web.xml中配置:
<mvc:resources mapping="/img/**" location="/img/"/>
location 表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录
mapping 表示对该资源的请求
3 springmvc核心技术
3.1 请求重定向和转发
注意:
对于请求转发的页面,可以是WEB-INF中页面;
而重定向的页面,是不能为WEB-INF中页的。
因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。
1、请求转发
处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,
且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。
视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。
处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。
语法:setViewName("forward:视图完整路径")
特点:不和视图解析器一同工作,就当项目中没有视图解析器
@RequestMapping(value = "/form.do")
// 当表单的name属性值与参数名不一致使用@RequestParam,若一致,直接取即可
public ModelAndView form(@RequestParam(value = "aname") String name, Integer age) {
ModelAndView mv = new ModelAndView();
mv.addObject("myname", name);
mv.addObject("myage", age);
mv.setViewName("forward:/show.jsp");
return mv;
}
2、 请求重定向
语法:setViewName("redirect:视图完整路径")
特点:不和视图解析器一同工作,就当项目中没有视图解析器
@RequestMapping(value = "/form.do")
// 当表单的name属性值与参数名不一致使用@RequestParam,若一致,直接取即可
public ModelAndView form(@RequestParam(value = "aname") String name, Integer age) {
ModelAndView mv = new ModelAndView();
mv.addObject("myname", name);
mv.addObject("myage", age);
mv.setViewName("forward:/show.jsp");
return mv;
}
3.2 拦截器
概述:
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器:
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器:
- 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
3.2.1 自定义拦截器
- 自定义拦截器类:
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
- springmvc的配置文件中配置拦截器:
<?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
https://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.zwh.*"/>
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.zwh.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:annotation-driven/>
<!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
<!--处理静态资源访问-->
<mvc:default-servlet-handler/>
<!-- <mvc:resources mapping="/img/**" location="/img/"/>-->
</beans>
- 编写一个Controller,接收请求:
//测试拦截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor.do")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法执行了");
return "hello";
}
}
- 前端 index.jsp:
<a href="${pageContext.request.contextPath}/interceptor.do">拦截器测试</a>
测试结果:
------------处理前------------
控制器中的方法执行了
------------处理后------------
------------清理------------
3.3 文件上传和下载
3.3.1 文件的上传
- 1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
- 2、配置bean:multipartResolver,id必须为"multipartResolver",否则报错
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
CommonsMultipartFile 的 常用方法:
String getOriginalFilename():获取上传文件的原名
InputStream getInputStream():获取文件流
void transferTo(File dest):将上传文件保存到一个目录文件中
- 3、编写前端页面
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
- 4、Controller
@Controller
public class FileController {
方式一:
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
方式二:
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
}
- 5、测试上传文件
3.3.2 文件的下载
-
1、设置response响应头
-
2、读取文件–inputstream
-
3、写出文件–outputstream
-
4、执行操作
-
5、关闭流(先开后关)
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基础语法.jpg";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
- 前端:
<a href="/download">点击下载</a>