1. 搭建SpringMVC开发环境
1.1 创建项目,添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.azure</groupId>
<artifactId>day56project_SpringMVC_day2</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--导入spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--导入springMVC支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--servlet支持包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<!--日志包-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
1.2 web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--设置springMVC前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springMVC配置文件-->
<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>
<!--
拦截请求规则:
1. *.do:拦截作为.do后缀得请求
要求:请求路径后缀必须以.do结尾;
缺点:不方便,每个请求都要写上.do的后缀;不支持restful风格的请求
2./ 表示拦截所有的请求,但不包含jsp请求
注意:此时静态资源(如html、css等)无法访问。
-->
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
1.3 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">
<!--1. 开启注解扫描-->
<context:component-scan base-package="com.azure"></context:component-scan>
<!--2. 配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--3. 开启mvc注解-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
1.4 测试页面index.html
由于在web.xml中前端控制器的拦截规则是/
,动态资源(jsp)不会被拦截,而静态资源(如html、css、js等)默认不能访问。
1.4.1 拦截路径设为/时静态资源无法访问的原因分析
-
tomcat服务器访问任何资源都是通过servlet把资源返回到浏览器客户端。
-
而访问静态资源不是使用servlet程序,而是默认通过DefaultServlet(缺省servlet)把静态资源返回到客户端中。该缺省servlet在tomcat服务器启动时默认就建立:
-
而我们在项目中配置拦截的路径是
/
,则所有的资源都会进入我们项目新建的dispatcherServlet,而不会经过DefaultServlet,从而导致静态资源无法被返回。 -
所以解决方式有两种:修改放行资源路径,重新配置DefaultServlet.
1.4.2 指定放行路径对静态资源放行
- 将资源放入包中,然后在springMVC.xml中指定放行资源路径
- 也可以单独指定放行的资源,但是效率差
- 注意:
/pages/*
和/panges/**
两种写法的差别
1.4.2.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"
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">
<!--1. 开启注解扫描-->
<context:component-scan base-package="com.azure"></context:component-scan>
<!--2. 配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--3. 开启mvc注解-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--4. 设置放行的静态资源-->
<!--使用mvc:resources标签:
属性:
mapping:指定映射路径,即浏览器的访问路径
location:表示映射路径对应的实际物理路径
-->
<!--放行指定的单个资源-->
<mvc:resources mapping="/index.html" location="/index.html"/><!--表示放行根目录下的index.html,之所以会报错是idea不推荐这种配置方式-->
<!--放行指定目录下的所有资源-->
<!--/pages/* : 表示pages目录下的所有资源会被放行-->
<!--/pages/**: 表示pages目录及其子目录下的所有资源会被放行-->
<mvc:resources mapping="/pages/**" location="/pages/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/image/**" location="/image/"/>
</beans>
1.4.3 使用tomcat的DefaultServlet处理静态资源
- 重新配置使用缺省servlet处理静态资源
1.4.3.1 web.xml配置调整
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--设置springMVC前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springMVC配置文件-->
<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>
<!--
拦截请求规则:
1. *.do:拦截作为.do后缀得请求
要求:请求路径后缀必须以.do结尾;
缺点:不方便,每个请求都要写上.do的后缀;不支持restful风格的请求
2./ 表示拦截所有的请求,但不包含jsp请求
注意:此时静态资源(如html、css等)无法访问。
-->
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置缺省servlet处理指定静态资源-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
</web-app>
2. 往域中存放数据
2.1 Model和ModelMap类型
- 作用:作为方法参数时可以将数据存储到request域中
- 使用方法:Model和ModelMap作为控制器方法的参数
2.1.1 示例代码
2.1.1.1 控制类
@Controller
public class ModelController {
/*Model作为方法参数*/
@RequestMapping("/model")
public String model(Model model) {
model.addAttribute("JoJo","StarPlatinum" );
return "success";
}
/*ModelMap作为方法参数*/
@RequestMapping("/modelMap")
public String modelMap(ModelMap modelMap) {
modelMap.addAttribute("Dio","TheWorld" );
return "success";
}
}
2.1.1.2 success.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>success!!</h3>
${requestScope.JoJo}<%--从request域中获取数据--%>
${requestScope.Dio}
</body>
</html>
2.1.2 Model和ModelMap的异同
相同点:
- 由于ModelMap的一个子类ExtendedModelMap实现Model接口,所以Model和ModelMap都是通过Model接口的子实现类BindingAwareModelMap实现存储数据到域的功能;使用addAttribute方法时最终都是会调用
request.setAttribute()
方法; - 两者从将数据存储到request域中的角度上来看是一样的。
不同点:
- Model是接口,而ModelMap是类。它们有各自的功能,只是存储数据到request域的功能上一致
2.2 SessionAttributes注解
- 作用:自动把Model或ModelMap中的数据存储到session域中,用于多次执行控制器方法间的参数共享。
- 属性:
- names:用于存入Model或ModelMap中指定的属性名称的数据;
- type:用于存入Model或ModelMap中指定类型的数据。该类型的所有数据都会存入session中。如果是基本数据类型,要使用对应包装类的字节码对象
2.2.1 控制类
/**
* 注解@SessionAttributes
* 1.自动把Model或者ModelMap中的数据放入session
* 2.属性:
* names = {"JoJo","Dio"}, 把Model或者ModelMap中指定名称的key的数据,自动放入session
* types = Integer.class 把Model或者ModelMap中指定类型的数据,自动放入session
*/
@Controller
@SessionAttributes(names = {"JoJo","Dio"},types = Integer.class)
public class SessionAttributesController {
@RequestMapping("/sessionModel")
public String sessionModel(Model model) {
model.addAttribute("JoJo","StarPlatinum");
model.addAttribute("Dio","TheWorld");
model.addAttribute("num1",831143);
model.addAttribute("num2","12345");//不满足存入的条件,该条数据不会存入session
return "success";
}
@RequestMapping("/sessionModelMap")
public String sessionModelMap(ModelMap modelMap) {
modelMap.addAttribute("JoJo","StarPlatinum");
modelMap.addAttribute("Dio","TheWorld");
return "success";
}
/*清除session的数据
* 1.使用原始的session.setAttribute方法存入的,只能使用原始的方法清除;
* 2.使用springMVC提供的方法自动存入的(即上面代码),只能使用@SessionAttributes注解清除.
* 注意:方法的参数是SessionStatus,这个对象提供setComplete()方法清空自动存入session的数据,
* 而原始方法存入的不会被清除
*/
@RequestMapping("/del")
public String del(SessionStatus sessionStatus){
// 清空通过@SessionAttributes注解自动放入session中的数据
sessionStatus.setComplete();
return "success";
}
}
2.2.2 success.jsp页面
<body>
<h3>success!!</h3>
<h4>从request域中获取数据</h4>
${requestScope.JoJo}
${requestScope.Dio}
<h4>从session域中获取数据</h4>
${sessionScope.JoJo}
${sessionScope.Dio}
${sessionScope.num1}
${sessionScope.num2}
</body>
3. json数据的交互
3.1 使用的注解
3.1.1 @RequestBody
- 作用:在处理器方法的形参上使用。把请求的json格式数据转换为java对象
3.1.2 @ResponseBody
- 在处理器方法返回值上使用,或在方法上使用。需要jackson支持包
- 作用:将响应的java对象转换为json格式的数据
3.2 添加依赖
- 需要在pom.xml中导入jackson支持包
<!--jackson支持包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
3.3 引入jquery文件,在springMVC.xml中配置
- 由于上面已经在springMVC中设置放行
/js/**
的资源
3.4 在pages目录下新建测试用html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax</title>
<script src="../js/jquery-3.3.1.min.js" type="text/javascript"></script>
<script>
$(function(){
$("#ajaxPost").click(function(){
$.ajax({
// 请求类型,这里必须为post,否则无法使用requestBody
type : "post",
// 请求地址
url : "/responseBodyJson",
// 发送给后台的ajax请求数据
data:'{"id":100,"name":"jack","money":9.9}',
dataType:"json",
// 请求格式与编码,避免乱码
contentType:"application/json;charset=utf-8",
success : function(jsn){
alert("jsn="+jsn+"; jsn.id="+jsn.id+"; jsn.name="+jsn.name+"; jsn.money="+jsn.money);
}
});
});
});
</script>
</head>
<body>
<h2>RequestBody获取请求JSON格式数据 & ResponseBody自动把对象转json并响应</h2>
<button id="ajaxPost">测试ajax请求json与响应json</button>
</body>
</html>
3.5 创建Account实体类用来封装数据
public class Account {
private int id;
private String name;
private double money;
3.6 控制器类
@Controller
public class JsonController {
@RequestMapping("/responseBodyJson") //注意与页面的ajax中的url保持一致
@ResponseBody //表示方法返回json格式(自动把返回对象转json格式)
public Account json(@RequestBody Account account) { //作用在方法参数中用以获取请求体的数据封装到形参中
System.out.println("请求的数据为:" + account);
//返回的数据
account.setId(11);
account.setName("JoJo");
account.setMoney(10086);
return account;
}
}
4. Restful风格的url
- 一种架构样式的设计风格,核心价值在于设计出符合REST风格的网络接口
- 更加简洁、更有层次,更易于实现缓存等机制。
4.1 优点和特性
- 优点:结构清晰、符合标准、易于理解、 扩展方便
4.1.1 特性
资源(Resources):URI是每个资源独一无二的标识符;
表现层(Representation) : 把资源具体呈现出来的形式;
状态转化(State Transfer):简单而言:是表现层状态转化,有四种操作。GET:用来获取资源,POST:用来新建资源,PUT:用来更新资源,DELETE:用来删除资源;
4.2 HTTP请求的提交方式
共7种:
- doGet、doPost、doDelete、doPut、doHead、doOptions、doTrace
而jsp、html仅支持其中的get,post方式。如果要使用其他方式,需要使用特定方法开启。
4.3 Restful风格与非Restful风格的区别
如果使用同一个地址表示crud方法:
-
非restful方法:需要在访问路径中表明crud的方法,eg:
http://localhost:8080/Order?type=add/update/delete/find
-
restful方法:不需要在访问路径中表明crud的方法,只需要在提交表单的时候使用不同的提交方式,而不同crud方法可以使用同一个地址,eg:
http://localhost:8080/Order
4.4 基于HidderHttpMethodFilter开启请求方式
- 使用Spring3.0提供的过滤器HidderHttpMethodFilter开启GET、POST、PUT与DELETE请求方式
- 使用步骤:
- web.xml配置过滤器
- 请求方式必须使用post请求
- 按照要求提供
_metheod
请求参数,即我们需要的请求方式
4.4.1 web.xml配置过滤器
<!--配置过滤器HiddenHttpMethodFilter-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern><!--对所有请求都会过滤-->
</filter-mapping>
4.4.2 测试页面restful.html
- 注意使用隐藏域提交
_method
参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>restful_test</title>
</head>
<body>
<form action="http://localhost:8080/restful/100" method="post">
<!--隐藏域中指定提交方式-->
<input type="hidden" name="_method" value="post">
<input type="submit" value="post提交(添加)">
</form>
<form action="http://localhost:8080/restful/200" method="post">
<!--隐藏域中指定提交方式-->
<input type="hidden" name="_method" value="get">
<input type="submit" value="get提交(查询)">
</form>
<form action="http://localhost:8080/restful/300" method="post">
<!--隐藏域中指定提交方式-->
<input type="hidden" name="_method" value="put">
<input type="submit" value="put提交(修改)">
</form>
<form action="http://localhost:8080/restful/400" method="post">
<!--隐藏域中指定提交方式-->
<input type="hidden" name="_method" value="delete">
<input type="submit" value="delete提交(删除)">
</form>
</body>
</html>
4.4.3 控制器类
- 使用
@PathVariable
获取占位符值 - 注意:使用put请求或者delete请求时,不能通过返回值跳转页面。解决方法:转为json字符串返回,不过跳转的页面只会显示返回值字符串。
@Controller
public class restfulController {
/**
* 1.处理post请求
* 2.请求地址:http://localhost:8080/restful/100,id不能在代码中写死,需要使用占位符
* 占位符的写法{占位符名}
* 3.在控制类的方法参数中使用@PathVariable注解获取占位符的值,并赋值到被注解的参数中
*/
@RequestMapping(value = "/restful/{id}",method = RequestMethod.POST)
public String save(@PathVariable("id") int id) {
System.out.println("save:" + id);
return "success";
}
/**
* 1.处理get请求
* 2.请求地址:http://localhost:8080/restful/100,id不能在代码中写死,需要使用占位符
* 占位符的写法{占位符名}
*/
@RequestMapping(value = "/restful/{id}",method = RequestMethod.GET)
public String get(@PathVariable("id") int id) {
System.out.println("get:" + id);
return "success";
}
/**
* 1.处理put请求
* 2.注意:put请求不能使用跳转,需要返回json格式的字符串
* 否则会报405:JSPs only permit GET POST or HEAD
* 为何会报错?
* 因为返回的字符串是以put方式,而返回的页面jsp不支持put方式,导致无法识别而报错
*/
@RequestMapping(value = "/restful/{id}",method = RequestMethod.POST)
public String put(@PathVariable("id") int id) {
System.out.println("put:" + id);
return "success"; //注意,这里返回的是json字符串,而不会跳转到success.jsp
}
/**
* 1.处理delete请求
* 2.注意:delete请求不能使用跳转,需要返回json格式的字符串
*/
@RequestMapping(value = "/restful/{id}",method = RequestMethod.DELETE)
@ResponseBody //表示返回值自动转为json格式数据
public String delete(@PathVariable("id") int id) {
System.out.println("delete:" + id);
return "[{\"id\":\"11\",\"name\":\"JoJo\"},{\"id\":\"12\",\"name\":\"Dio\"}]";
}
}
5. 控制器方法的返回值(重要)
5.1 返回值类型
5.1.1 返回String类型
- 返回值类型是String类型时,默认会以转发方式跳转到页面;
- 需要配置springMVC.xml中的视图解析器;
上面的代码的返回值全部是String类型,使用转发方式跳转
5.1.2 返回void
- 在方法内部通过servletApi自行控制返回结果;
- 注意:文件下载需要使用返回void形式
5.1.3 返回ModelAndView
-
ModelAndView是SpringMVC提供的对象
-
作用:控制器存储数据的同时完成跳转功能
-
提供两种方法:
- addObject:将请求数据封装到对象中存入request域(利用ModelMap)
- setViewName:设置视图名称,视图解析器根据名称跳转到指定视图
5.1.4 示例代码
@Controller
public class ReturnValueController {
/**
* 1. 返回值为String类型
*/
@RequestMapping("/str")
public String strReturn(){
return "success";
}
/**
* 2. 返回void
*/
@RequestMapping("/void")
public void voidReturn(HttpServletResponse response){
}
/**
* 3. 返回值为ModelAndView
* 在存储数据的同时完成跳转操作
*/
@RequestMapping("/mv")
public ModelAndView returnmodelAndView(HttpServletResponse response){
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
//往request域存入数据
mv.addObject("JoJo","StarPlatinum" );
//设置跳转页面
mv.setViewName("success");
return mv;
}
}
5.2 转发和重定向
5.2.1 forward转发
- contrller 方法提供了一个 String 类型返回值之后, 在返回值里使用
forward:
- 它相当于
response.getRequestDispatcher(url).forward(..)
/**
* 使用forward方式转发
*/
@RequestMapping("/forward")
public String forward(){
return "forward:/pages/success.jsp"; //指定跳转路径
}
5.2.2 重定向
-
contrller 方法提供了一个 String 类型返回值之后, 在返回值里使用
redirect:
-
它相当于
response.sendRedirect(url)
-
注意:重定向到jsp页面时,jsp页面不可放在WEB-INF目录下
/**
* 使用重定向转发
*/
@RequestMapping("/redirect")
public String redirect(){
return "redirect:/pages/success.jsp"; //指定跳转路径
}
6. SpringMVC实现文件上传(重要)
- 3种上传方式:传统文件上传、SpringMVC文件上传、SpringMVC跨服务器方式文件上传。
6.1 传统文件上传
6.1.1 使用传统方式实现文件上传的三大条件
- form标签的enctype属性的取值必须是:
multipart/form-data
,表示表单以文件上传形式提交。(一般表单提交数据不写该属性,默认值是application/x-www-form-urlencoded,表示不以文件上传形式提交) - method属性取值必须为:post
- 提供一个文件选择域**
<input type="file" />
** - 此外,需要添加Commons-fileupload支持包
6.1.2 添加依赖
<!--文件上传支持包-->
<dependency>
<groupId>Commons-fileupload</groupId>
<artifactId>Commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
6.1.3 文件上传页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>upload</title>
</head>
<body>
<!--传统文件上传三要素-->
<form action="/upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"/>
证件照:<input type="file" name="imgFile"/><!--文件上传-->
<input type="submit" value="提交">
</form>
</body>
</html>
6.1.4 控制器类
/**
* 使用传统方式:Apache提供的fileUpload组件实现文件上传
*/
@Controller
public class TraditionalUploadController {
@RequestMapping("/upload")
public void upload(HttpServletRequest request) throws Exception {
/*
实现文件上传思路:
1. 获取文件上传目录地址
2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
3. 处理文件上传
3.1 创建文件上传核心工具类ServletFileUpload
3.2 使用核心工具类将表单数据封装到FileItem对象
3.3 遍历FileItem对象,获取每个表单元素,如果是普通元素,打印;如果是文件元素
3.3.1 获取文件名,并使用UUID规则使文件名唯一化(避免重名)
3.3.2 上传文件并删除临时文件
*/
//1. 获取文件上传目录地址
String realPath = request.getSession().getServletContext().getRealPath("/upload");
//文件上传的目标地址:E:/Java_study/JavaprojectsIV/day56project_SpringMVC_day2/target/day56project_SpringMVC_day2-1.0-SNAPSHOT/upload
System.out.println(realPath);
//2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
//创建目录
File file = new File(realPath,date);
if (!file.exists()) {
file.mkdirs();
}
//3. 处理文件上传
//创建FileItem工厂
FileItemFactory factory = new DiskFileItemFactory();
//3.1 创建文件上传核心工具类ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
//3.2 使用核心工具类将表单数据封装到FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
//3.3 遍历FileItem对象,获取每个表单元素,如果是普通元素,打印;
for (FileItem fileItem : fileItems) {
//判断:如果是普通表单元素就获取打印
if (fileItem.isFormField()) {
String nameStr = fileItem.getString("UTF-8");
System.out.println("输入的用户名:" + nameStr);
} else {
//文件元素
//3.3.1 获取文件名,并使用UUID规则使文件名唯一化(避免重名)
String fileName = fileItem.getName();
fileName = UUID.randomUUID().toString().replaceAll("-","")+"_" +fileName;
//3.3.2 上传文件并删除临时文件
fileItem.write(new File(file,fileName));//父路径加文件名
fileItem.delete();
}
}
}
}
6.2 SpringMVC文件上传(重点)
- springmvc框架提供了一个对象MultipartFile,该对象可作为控制器方法的参数。参数的名称必须和表单file元素的name属性取值一致
- MultipartFile提供了transferTo(file)方法可以直接上传文件
6.2.1 测试上传页面
- 同传统方式
6.2.2 控制器
@Controller
public class SpringMVCUploadController {
/**
实现文件上传思路:
1. 获取文件上传目录地址
2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
3. 处理文件上传
3.1 使用MultipartFile对象获取文件名,并使用UUID规则使文件名唯一化(避免重名)
3.2 直接使用MultipartFile对象的方法上传文件
*/
@RequestMapping("/upload2")
public String upload(HttpServletRequest request, MultipartFile imgFile) throws IOException {
//1. 获取文件上传目录地址
String realPath = request.getSession().getServletContext().getRealPath("/upload");
//文件上传的目标地址:E:/Java_study/JavaprojectsIV/day56project_SpringMVC_day2/target/day56project_SpringMVC_day2-1.0-SNAPSHOT/upload
System.out.println(realPath);
//2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
//创建目录
File file = new File(realPath,date);
if (!file.exists()) {
file.mkdirs();
}
//3. 处理文件上传
//3.1 使用MultipartFile对象获取文件名,并使用UUID规则使文件名唯一化(避免重名)
String fileName = imgFile.getOriginalFilename();
fileName = UUID.randomUUID().toString().replaceAll("-","")+"_" +fileName;
//3.2 直接使用MultipartFile对象的方法上传文件
imgFile.transferTo(new File(file,fileName));
//顺便把用户名打印一下吧
System.out.println(request.getParameter("username"));
//4. 如果使用返回void,由于没有指定返回的页面,默认返回到控制类方法的映射,即默认返回upload2,而项目没有/pages/upload2.jsp,会找不到返回页面而报错
//故指定返回的页面
return "upload";
}
}
6.2.3 springMVC.xml配置文件上传解析器
-
使用文件上传解析器:CommonsMultipartResolver
-
注意事项:文件上传解析器的id是固定的(一定要是multipartResolver),不能起别的名称,否则无法实现请求参数的绑定
<!--配置文件上传解析器,id固定为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--指定上传的文件大小限制,比如是10M-->
<property name="maxUploadSize" value="10485760"></property>
</bean>
6.3 springmvc 跨服务器方式的文件上传
6.3.1 实际开发的分服务器处理
- 分服务器处理的目的是让不同的服务器处理不同的功能,从而提高我们项目的运行效率
- 如:
- 数据库服务器:访问数据库
- 缓存和消息服务器:负责处理大并发访问的缓存和消息
- 文件服务器:负责存储用户上传文件的服务器
- 应用服务器:负责部署应用
6.3.2 pom.xml导入jersey坐标
<!--跨服务器上传,jersey坐标支持包-->
<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>
6.3.3 控制类
@Controller
public class SToSUploadController {
@RequestMapping("/upload3")
public String upload(HttpServletRequest request,MultipartFile imgFile) throws IOException {
//创建jersey包中提供的client对象
Client client = new Client();
//使用client和文件服务器建立联系
//6080是文件服务器的端口号
String uploadPath = "http://localhost:6080/fileSystem/upload/" + imgFile.getOriginalFilename();
WebResource webResource = client.resource(uploadPath);
//将web资源对象添加到文件服务器上
webResource.put(String.class,imgFile.getBytes());
return "success";
}
}
6.3.4 springMVC.xml配置文件上传解析器
- 配置方式同6.2.3
6.3.5 测试页面
- 同上