在之前springMVC上传功能详解(一)中新增加controller进行处理,配置文件照旧
项目架构如下:
controller处理器:
package controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartFile;
import entity.User;
/**
* 上传用户头像
*/
@Controller
public class UploadImageController {
//上传头像的表单页面
@RequestMapping("/toUploadHead.do")
public String toUploadHead(){
return "userHead/uploadHead";
}
@RequestMapping("/uploadHead.do")
//将上传文件自动绑定到该属性headimage
public String uploadHead(User user, HttpServletRequest request){
MultipartFile headimage = user.getHeadimage();//文件对象
String fileName = headimage.getOriginalFilename();//文件名 例如:wq.png
String path = getImagePath(request);
File targetFile = new File(path ,fileName);
if(!targetFile.exists()){//若文件夹不存在则重新创建
targetFile.mkdirs();
}
//保存
try {
headimage.transferTo(targetFile);
request.setAttribute("fileUrl", getURLEncoderString(path + File.separator + fileName));//编码(传入前端路径可能乱码)
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return "userHead/userInfo";
}
//获取上传头像的路径
public String getImagePath(HttpServletRequest request){
String path = request.getSession().getServletContext().getRealPath("");
path = path.substring(0,path.lastIndexOf(File.separator));
path = path.substring(0,path.lastIndexOf(File.separator) + 1);// D:\liferay\tomcat\tomcat-7.0.81
return path + "uploadImg";
}
@RequestMapping("/getImage.do")
//显示头像图片
public void getImage(HttpServletRequest request, HttpServletResponse response){
String fileUrl = request.getParameter("fileUrl");//文件路径
System.out.println("显示路径:"+fileUrl);
FileInputStream fis = null;
OutputStream os = null;
try {
fis = new FileInputStream(fileUrl);
os = response.getOutputStream();
int count = 0;
byte[] buffer = new byte[1024 * 8];
while ((count = fis.read(buffer)) != -1) {
os.write(buffer, 0, count);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@RequestMapping("/downImage.do")
//下载头像图片
public void downImage(HttpServletRequest request, HttpServletResponse response) throws IOException{
String fileUrl = request.getParameter("fileUrl");//文件路径(不解码,否则+号变成了空格)
System.out.println("下载路径:"+fileUrl);
File file = new File(fileUrl);
//以下载方式打开
FileInputStream fis = null;
OutputStream os = null;
String downName = new String(file.getName().getBytes("UTF-8"),"iso-8859-1");
response.setHeader("Content-Disposition", "attachment;filename=" + downName);
try {
fis = new FileInputStream(file);//创建流对象
os = response.getOutputStream();//写出
int count = 0;
byte[] buffer = new byte[1024 * 8];
while ((count = fis.read(buffer)) != -1) {
os.write(buffer, 0, count);
}
os.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {//释放资源
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os != null){
os.close();
}
}
/*
//* 方式二
String fileUrl = request.getParameter("fileUrl");//文件路径(不解码,否则+号变成了空格)
File file = new File(fileUrl);
System.out.println(file.getName());
HttpHeaders headers = new HttpHeaders();//http头信息
String downloadFileName = new String(file.getName().getBytes("UTF-8"),"iso-8859-1");//设置编码
headers.setContentDispositionFormData("attachment", downloadFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//MediaType:互联网媒介类型 contentType:具体请求中的媒体类型信息
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);
*/
}
//编码和解码
public static String getURLEncoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
public static String URLDecoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLDecoder.decode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
//异常处理
@ExceptionHandler
public String exHandle(Exception ex, HttpServletRequest request){
if(ex instanceof MaxUploadSizeExceededException){
//long maxSize = ((MaxUploadSizeExceededException) ex).getMaxUploadSize();//允许上传文件的最大值
request.setAttribute("errorMsg", "文件总内容超过了3 M");
return "error/error";
}else{
return "error/system_error";
}
}
}
spring配置文件与之前一致,拦截器也不变,两个错误页面不变
User实体类如下:
这个实体类中的headimage属性的主要作用就是用来映射我们上传的文件,可以看到它是MultipartFile类型的,其主要作用是用来映射把上面的form表单的headimage属性自动注入到对象里面(在controller中获取参数时候将参数注入到实体类中)
package entity;
import java.io.Serializable;
import org.springframework.web.multipart.MultipartFile;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String userName;
private MultipartFile headimage;//上传文件会自动绑定到该属性
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public MultipartFile getHeadimage() {
return headimage;
}
public void setHeadimage(MultipartFile headimage) {
this.headimage = headimage;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((headimage == null) ? 0 : headimage.hashCode());
result = prime * result
+ ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (headimage == null) {
if (other.headimage != null)
return false;
} else if (!headimage.equals(other.headimage))
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
@Override
public String toString() {
return "User [userName=" + userName + ", headimage=" + headimage + "]";
}
}
主页面index1.jsp
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>文件上传示例</title>
</head>
<body>
<a href="toUploadHead.do">上传用户头像且显示</a>
</body>
</html>
上传表单页面uploadHead.jsp:
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<!-- 头像上传的页面 -->
<html>
<head>
<title>文件图片</title>
<script type="text/javascript" src="js/jquery-1.11.1.js"></script>
<script type="text/javascript">
//在JS中判断上传文件 单个上传时候必须先选定文件,不能直接在没有文件的情况下上传,否则弹窗提示
function checkSingleFile(){
var file = $("#sub1").val();
if(file == ""){
//没有选择文件
alert("请选择要上传的文件!");
return false;
}
return true;
}
</script>
</head>
<body>
<form action="uploadHead.do" method="post" enctype="multipart/form-data" onsubmit="return checkSingleFile();">
<p>用户头像</p>
<input id="sub1" type="file" name="headimage" />
<input type="submit" value="上传单个"/>
</form>
</body>
</html>
上传成功后跳转到userInfo.jsp页面,显示头像和下载按钮
登录链接页面如下:
单击后:
此处选择单个文件上传,单个上传必须先选中文件,否则有提示,如下图所示:
userInfo.jsp文件获取后台传来的路径是经过UTF-8编码的,上传成功后会显示上传的头像图片,单击链接会下载该图片文件,最好不要采用超链接的方式下载,可以采用按钮+JS事件来处理,如代码:window.location = 'downImage.do?fileUrl='+fileUrl;
总结如下:
1.表单在提交前会校验文件,JS校验,必须有文件才能上传
2.在拦截器处理文件尺寸大小,将抛出的文件尺寸过大异常抛给@ExceptionHandler处理,限制上传文件大小,与案例(一)相同的处理方式,只是文件设置大小需小一点,一般头像就几十KB,
3.上传后将文件路径:例如D:\liferay\apache-tomcat-7.0.81\uploadImg\qq.jpg采用UTF-8的编码方式编码后传到头像显示页面(userInfo.jsp)
4.此时要在jsp页面的img标签中显示图片:
<img alt="用户头像" src="getImage.do?fileUrl=${fileUrl }" />
通过标签上的get请求,利用原始的IO流进行处理,处处参数fileUrl是后台传来且进过UTF-8编码的字符串,例如:
文件经过编码后的的真实路径:D%3A%5Cliferay%5Capache-tomcat-7.0.81%5CuploadImg%5Cqq.jpg
这样可避免特殊字符的编码问题,此处显示头像发送请求,附带该参数传递,后台接收该参数,需处理一些编码方式如下:
String fileUrl = request.getParameter("fileUrl");//文件路径(不解码,否则+号变成了空格)
File file = new File(fileUrl);
//以下载方式打开
FileInputStream fis = null;
OutputStream os = null;
String downName = new String(file.getName().getBytes("UTF-8"),"iso-8859-1");
response.setHeader("Content-Disposition", "attachment;filename=" + downName);
文件名要用ISO-8859-1编码,否则弹出的下载框文件名乱码或部分识别不了
5.文件下载后保存的路径如下:
下载方式可以采用传统的IO流也可以用如上已经注释的代码,均可成功
6.本篇博文介绍了SpringMvc上传和文件的功能,需要注意的地方就是对于文件上传包common-fileupload.jar包的使用,还有在配置文件上配置mulitipartResolver这个bean。下面又介绍了用java 实体类去映射上传文件的属性对应的文件,这点的好处就是它会自动映射,然后把对象放入到我们的请求域中,就可以展示给界面用户层,这也是mvc思想模式的体现。接下来是介绍去下载文件,只需要从我们的写入的目标地址去取出文件,再进行responseEntity对象的封装,就可以实现下载功能