SpringMVC 基础(二)
2022-04-12 本文已影响0人
yjtuuige
- SpringMVC 基础 查看链接
一、AJAX
1.1 简介
-
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML);
-
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术;
-
AJAX 不是一种新的编程语言,而是一种用于创建更好更快,以及交互性更强的 Web 应用程序的技术;
-
在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来,Google Suggest 能够自动完成搜索单词;
-
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当我们在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表,如百度的搜索框:
-
传统的网页(即不用 AJAX 技术的网页)想要更新内容或者提交一个表单,都需要重新加载整个网页;
-
使用 AJAX 技术的网页,通过在后台服务器,进行少量的数据交换,就可以实现异步、局部更新;
-
使用 AJAX,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的 Web 用户界面;
1.2 伪造 AJAX
-
可以使用前端的一个标签,来伪造一个 ajax 的样子:
iframe 标签
- 新建模块,并导入 web 支持;
- 配置
web.xml
及 springMVC 配置文件,运行 Tomcat 测试环境; - 编写 html 页面,使用 iframe 测试,感受下效果:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>iframe伪造ajax</title> <script> window.onload = function () { let myDate = new Date(); document.getElementById("currentTime").innerText = myDate.getTime(); }; function LoadPage() { let url = document.getElementById("url").value; document.getElementById("iframe1").src = url; }; </script> </head> <body> <div> <p>请输入要加载的地址:<span id="currentTime"></span></p> <p> <input id="url" type="text" value="https://juejin.cn/"/> <input type="submit" value="提交" onclick="LoadPage()"/> </p> </div> <div> <h3>加载页面位置:</h3> <iframe id="iframe1" style="width: 100%;height: 500px;"></iframe> </div> </body> </html>
- 使用 IDEA 打开浏览器进行测试;
小结:
- 利用 AJAX 可以实现:
- 注册时,输入用户名,自动检测用户是否已经存在;
- 登陆时,提示用户名,密码错误;
- 删除数据行时,将行 ID 发送到后台,后台在数据库中删除,数据库删除成功后,在页面 DOM 中,将数据行也删除;
- ...等等;
1.3 jQuery.ajax
- jQuery 3.6.0 开发版 下载链接
- Ajax 的核心是 XMLHttpRequest 对象(XHR):
- XHR 为向服务器发送请求和解析服务器响应,提供了接口,能够以异步方式,从服务器获取新数据;
- jQuery 提供多个与 AJAX 有关的方法;
- 通过 jQuery AJAX 方法,能够使用 HTTP Get 和 HTTP Post,从远程服务器上请求文本、HTML、XML 或 JSON,同时能够把这些外部数据,直接载入网页的被选元素中;
- jQuery(是一个库) 不是生产者,而是大自然搬运工;
- jQuery Ajax 本质就是 XMLHttpRequest,对它进行了封装,方便调用:
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 将自动替换 ? 为正确的函数名,以执行回调函数
*/
测试一:HttpServletResponse 实现
- 使用最原始的 HttpServletResponse 处理,最简单,最通用:
- 配置
web.xml
和 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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--配置SpringMVC-->
<!-- 1. 开启SpringMVC注解驱动,注意导入mvc的头文件-->
<mvc:annotation-driven/>
<!--2. 静态资源过滤-->
<mvc:default-servlet-handler/>
<!--3. 扫描包:Controller-->
<context:component-scan base-package="com.study.controller"/>
<!--4. 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 创建 Controll:AjaxController
// 不走视图页面,直接返回字符串
@RestController
public class AjaxController {
@RequestMapping("/a1")
public void ajax1(String name, HttpServletResponse response) throws IOException {
System.out.println("前端传递参数:" + name);
if ("admin".equals(name)) {
response.getWriter().println("true");
} else {
response.getWriter().println("false");
}
}
}
- 导入 jQuery,可以使用在线的 CDN,也可以下载导入:
<%--<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>--%>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
- 编写 index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<%--<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>--%>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>
function a1() {
// post、get都是调用的ajax方法,可以直接用 $.ajax
$.post({
url: "${pageContext.request.contextPath}/a1",
// data:传递给后端的数据,键值对的形式 name对应后端的name
data: {"name": $("#userName").val()},
// data:后端返回的数据 status:状态
success: function (data, status) {
console.log(data);
console.log(status);
}
});
}
</script>
</head>
<body>
<%--onblur:失去焦点触发事件--%>
用户名:<input type="text" id="userName" onblur="a1()"/>
</body>
</html>
-
启动 Tomcat 测试:
- 打开浏览器的控制台,当鼠标离开输入框时,可以看到发出了一个 ajax 的请求;
-
流程分析:
测试二:SpringMVC、JSON 方式实现
- 需要导入 Jackson 依赖:否则请求路径时,报错 406
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>
- 创建实体类:user
- 使用 lombok,需要事先导入依赖;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
- 在 Controller 类中添加方法:
- 获取一个集合对象,展示到前端页面;
@RequestMapping("/a2")
public List<User> ajax2() {
List<User> list = new ArrayList<>();
list.add(new User("test01", 20, "男"));
list.add(new User("test02", 21, "女"));
list.add(new User("test03", 20, "男"));
// 类中使用@RestController注解,将list转成json格式返回
return list;
}
- 前端页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%--jQuery--%>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>
$(function () {
$("#btn").click(function () {
/*
简写方式:
$.post(url,param[可以省略(传递给后端的参数)],success[回调函数])
*/
$.post("${pageContext.request.contextPath}/a2", function (data) {
console.log(data);
let html = "";
for (let i = 0; i < data.length; i++) {
<%-- jsp中需要转义es6模板字符串${}:\${} --%>
html += `<tr>
<td>\${data[i].name}</td>
<td>\${data[i].age}</td>
<td>\${data[i].sex}</td>
</tr>`
}
$("#content").html(html);
});
/*
$.post({
url: "${pageContext.request.contextPath}/a2",
success:function (data){
let html = "";
for (let i = 0; i < data.length; i++) {
html += `<tr>
<td>\${data[i].name}</td>
<td>\${data[i].age}</td>
<td>\${data[i].sex}</td>
</tr>`
}
$("#content").html(html);
}
});
*/
})
})
</script>
</head>
<body>
<input type="button" id="btn" value="获取数据"/>
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content"></tbody>
</table>
</body>
</html>
-
运行测试:
1.4 AJAX 注册提示
- 在 Controller 类中,添加方法:
@RequestMapping("/a3")
public String ajax3(String name, String pwd) {
String msg = "";
if (name != null) {
// admin:模拟数据库查询的数据
if ("admin".equals(name)) {
msg = "OK";
} else {
msg = "用户名有误";
}
}
if (pwd != null) {
// 123456:模拟数据库查询的数据
if ("123456".equals(pwd)) {
msg = "OK";
} else {
msg = "密码有误";
}
}
// 类中使用@RestController注解,将msg转成json格式返回
return msg;
}
- 创建前端页面:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>
function a1() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"name": $("#name").val()},
success: function (data) {
if (data.toString() === "OK") {
$("#userInfo").css("color", "green");
}else {
$("#userInfo").css("color", "red");
}
$("#userInfo").html(data);
}
});
}
function a2() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"pwd": $("#pwd").val()},
success: function (data) {
if (data.toString() === "OK") {
$("#pwdInfo").css("color", "green");
}else {
$("#pwdInfo").css("color", "red");
}
$("#pwdInfo").text(data);
}
});
}
</script>
</head>
<body>
<p>
<%--onblur:失去焦点触发事件--%>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userInfo"></span>
</p>
<p>
密码:<input type="text" id="pwd" onblur="a2()"/>
<span id="pwdInfo"></span>
</p>
</body>
</html>
- 处理 JSON 乱码:SpringMVC 配置文件中进行配置
<!--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>
-
运行测试:
1.5 获取 baidu 接口 Demo
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JSONP百度搜索</title>
<style>
#q {
width: 500px;
height: 30px;
border: 1px solid #ddd;
line-height: 30px;
display: block;
margin: 0 auto;
padding: 0 10px;
font-size: 14px;
}
#ul {
width: 520px;
list-style: none;
padding: 0;
border: 1px solid #ddd;
margin: -1px auto 0;
display: none;
}
#ul li {
line-height: 30px;
padding: 0 10px;
}
#ul li:hover {
background-color: #f60;
color: #fff;
}
</style>
<script>
// 2.步骤二
// 定义demo函数 (分析接口、数据)
function demo(data) {
let Ul = document.getElementById('ul');
let html = '';
// 如果搜索数据存在 把内容添加进去
if (data.s.length) {
// 隐藏掉的ul显示出来
Ul.style.display = 'block';
// 搜索到的数据循环追加到li里
for (let i = 0; i < data.s.length; i++) {
// es6 模板字符串
html += `<li>${data.s[i]}</li>`
// html += '<li>' + data.s[i] + '</li>';
}
// 循环的li写入ul
Ul.innerHTML = html;
}
}
// 1.步骤一
window.onload = function () {
// 获取输入框和ul
let Q = document.getElementById('q');
let Ul = document.getElementById('ul');
// 事件鼠标抬起时候
Q.onkeyup = function () {
// 如果输入框不等于空
if (this.value != '') {
// ☆☆☆☆☆☆JSONPz重点☆☆☆☆☆☆
// 创建标签
let script = document.createElement('script');
// 给定要跨域的地址 赋值给src
// 这里是要请求的跨域的地址 百度搜索的跨域地址
script.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=' + this.value + '&cb=demo';
// 将组合好的带src的script标签追加到body里
document.body.appendChild(script);
}
}
}
</script>
</head>
<body>
<input type="text" id="q"/>
<ul id="ul">
</ul>
</body>
</html>
二、拦截器
2.1 概述
- SpringMVC 的处理器,拦截器,类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理,可以自定义拦截器,实现特定的功能;
- 过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用;
-
过滤器:
- servlet 规范中的一部分,任何 Java web 工程都可以使用;
- 在
url-pattern
中配置了/*
之后,可以对所有要访问的资源,进行拦截;
-
拦截器:
- 拦截器是 SpringMVC 框架自有的,只有使用了 SpringMVC 框架的工程才能使用;
- 拦截器只会拦截访问控制器方法,如果访问的是 jsp、html、css、image、js,是不会进行拦截的;
2.2 自定义拦截器
- 要自定义拦截器,必须实现 HandlerInterceptor 接口;
- 创建新模块,并添加 web 支持;
- 配置
web.xml
和 springmvc 配置文件; - 创建拦截器:config 目录下,创建 MyInterceptor
public class MyInterceptor implements HandlerInterceptor {
/*
如果返回true执行下一个拦截器
如果返回false就不执行下一个拦截器
*/
// 在请求处理的方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("------------处理前------------");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
// 在请求处理方法执行之后执行(一般用于处理日志)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
// 在dispatcherServlet处理后执行,做清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("------------清理------------");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
- 在 SpringMVC 的配置文件中,配置拦截器:
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--
/**:包括路径及其子路径
/admin/*:拦截的是/admin/add等等这种,/admin/add/user不会被拦截
/admin/**:拦截的是/admin/下的所有
-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.study.config.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
- 创建 Controller,接收请求:
@RestController
public class TestController {
@RequestMapping("/interceptor")
public String test2() {
System.out.println("控制器中的方法执行了");
return "hello";
}
- 编写前端:index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
</body>
</html>
-
配置 Tomcat,启动测试:
2.3 验证用户是否登录 (认证用户)
实现思路:
- 有一个登陆页面,需要写一个 controller 访问页面;
- 登陆页面有一个提交表单的动作,需要在 controller 中处理,判断用户名、密码是否正确,如果正确,向 session 中写入用户信息,返回登陆成功信息;
- 拦截用户请求,判断用户是否登陆,如果用户已经登陆,放行,如果用户未登陆,跳转到登陆页面;
测试:
- 创建登陆页面:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/user/toLogin">登录</a>
<a href="${pageContext.request.contextPath}/user/toSuccess">成功页面</a>
</body>
</html>
- 创建 Controller 类,处理请求:
@Controller
@RequestMapping("/user")
public class LoginController {
// 跳转到登录页面
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
// 跳转到成功页面
@RequestMapping("/toSuccess")
public String toSuccess() {
return "success";
}
// 登陆提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) {
// 把用户的信息存在Session中
session.setAttribute("user", username);
return "success";
}
// 退出登陆
@RequestMapping("/logout")
public String logout(HttpSession session) {
// 移除Session
session.removeAttribute("user");
// 手动注销Session
// session.invalidate();
return "login";
}
}
- 创建登陆成功的页面:
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h3>登录成功页面</h3>
<hr>
${user}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>
- 在 index 页面上测试跳转,启动 Tomcat 测试,未登录也可以进入主页:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/user/toLogin">登录</a>
<a href="${pageContext.request.contextPath}/user/toSuccess">成功页面</a>
</body>
</html>
- 创建登录拦截器:
public class LoginInterceptor implements HandlerInterceptor {
// 在请求处理的方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是登陆页面则放行
if (request.getRequestURI().contains("toLogin")) {
return true;
}
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已登陆也放行
if (session.getAttribute("user") != null) {
return true;
}
// 用户没有登陆跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
- 在 SpringMVC 的配置文件中,注册拦截器:
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.study.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- 再次重启 Tomcat 测试,可以实现登录拦截功能;
三、文件上传和下载
3.1 概述
- 文件上传是项目开发中最常见的功能之一,springMVC 可以很好的支持文件上传,但是 SpringMVC 上下文中,默认没有装配 MultipartResolver,因此,默认情况下,不能处理文件上传工作;
- 如果想使用 Spring 的文件上传功能,则需要在上下文中配置MultipartResolver;
- 前端表单要求:为了能上传文件,必须将表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data,只有在这样的情况下,浏览器才会把用户选择的文件,以二进制数据发送给服务器;
- 表单中的 enctype 属性说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单,会将表单域中的值处理成 URL 编码方式;
- multipart/form-data:以二进制流的方式,来处理表单数据,这种编码方式,会把文件域指定文件的内容,也封装到请求参数中,不会对字符编码;
- text/plain:除了把空格转换为
+
号外,其他字符都不做编码处理,这种方式适用 直接通过表单发送邮件;
<!--编码方式:文件上传-->
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
- 一旦设置了enctype 为 multipart/form-data,浏览器即会采用二进制流的方式,来处理表单数据,而对于文件上传的处理,则涉及在服务器端解析原始的 HTTP 响应;
- 在 2003 年,Apache Software Foundation 发布了开源的 Commons FileUpload 组件,很快成为 Servlet/JSP 程序员上传文件的最佳选择;
- Servlet3.0 规范已经提供方法来处理文件上传,但这种上传需要在 Servlet 中完成;
- Spring MVC 提供了更简单的封装;
- Spring MVC 为文件上传,提供了直接的支持,这种支持是用 即插即用 的 MultipartResolver 实现的;
- Spring MVC 使用 Apache Commons FileUpload 技术实现了一个 MultipartResolver 实现类
CommonsMultipartResolver
因此,SpringMVC 的文件上传,还需要依赖 Apache Commons FileUpload 的组件;
3.2 文件上传
- 创建新模块,并添加 web 框架支持;
- 配置
web.xml
及 SpringMVC 配置文件; - 配置 Tomcat,启动测试环境;
- 导入文件上传的 jar 包,commons-fileupload 或 Maven 依赖:
<!--文件上传:自动导入commons-io-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
- 在 SpringMVC 配置文件中配置 bean:
multipartResolver
- id 必须为:multipartResolver,否则报400错误;
<!--文件上传配置:id必须为:multipartResolver,否则报400错误-->
<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):将上传文件,保存到一个目录文件中;
- 编写前端页面:
index.jsp
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
- 创建 Controller 类:FileController
上传方式一:
@Controller
public class FileController {
// 上传方式 1:
// @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.transferTo
来保存上传的文件; - 在 FileController 类中添加方法:
/*
上传方式 2:
采用file.transferTo来保存上传的文件
*/
@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";
}
- 修改前端表单提交地址;
- 运行测试;
3.3 文件下载
-
文件下载步骤:
- 设置 response 响应头;
- 读取文件:InputStream;
- 写出文件:OutputStream;
- 执行操作;
- 关闭流(先开后关);
-
代码实现:
// 文件下载
@RequestMapping("/download")
public String downloads(HttpServletResponse response, HttpServletRequest request) throws Exception {
// 要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.png";
// 1. 设置response 响应头
// 设置页面不缓存,清空buffer
response.reset();
// 字符编码
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="${pageContext.request.contextPath}/download">点击下载</a>
- 运行测试;
四、SSM 回顾
