同步中图片上传至控制器:
JSP页面
<form action="${pageContext.request.contextPath}/file/upLoad" method="post" enctype="multipart/form-data">
学生姓名:<input type="text" name="stuName"><br>
学生图像:<input type="file" name="stuImg"><br>
<input type="submit" value="提交">
</form>
需要注意:包含图片上传的表单,需要请求方式为post,enctype="multipart/form-data"(必须)
控制器:
// 进行文件上传的操作
@RequestMapping("/upLoad")
public String upLoadTest(String stuName, MultipartFile stuImg, HttpServletRequest request) throws IOException {
// 获取文件上传的路径
// request.getServletContext():获取当前项目的路径
// getRealPath("/static/upload"):获取当前项目下static/upload的路径
String dir = request.getServletContext().getRealPath("/static/upload");
// 判断文件的路径是否存在,不存在则创建
File path = new File(dir);
if (!path.exists()) {
path.mkdirs();
}
// 获取文件的原始名称
String oldFileName = stuImg.getOriginalFilename();
// 获取文件的新名称
String newFileName = FileNameByUUID.getFileName() + FileTypeUtil.getFileType(oldFileName);
// 将文件写入到指定的路径中
File file = new File(dir, newFileName);
stuImg.transferTo(file);
//如果要将图片保存至数据库中,newFileName就是要保存的文件名
//数据库图片字段存图片名称,读取图片时,根据图片名称就可以找到图片
return "index";
}
这里使用到的工具类:
FileNameByUUID(给文件起一个不重复的名字)
FileTypeUtil(获取文件的后缀名,例如:.jpg)
为什么要给文件重命名?因为可能出现不同用户上传名字相同内容不同的图片,例两张11.jpg,但两张内容不同,如果不重命名,同名文件会出现后一个文件覆盖上一个文件
用到的工具类
import java.util.UUID;
public class FileNameByUUID {
private FileNameByUUID() {
}
public static String getFileName() {
String fileName = UUID.randomUUID().toString().replace("-", "");
return fileName;
}
}
public class FileTypeUtil {
private FileTypeUtil() {
}
public static String getFileType(String fileName) {
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
return fileType;
}
}
扩展:文件下载功能
JSP页面
<body>
<p>头像一</p>
<a href="${pageContext.request.contextPath}/file/downLoad?fileName=头像1.JPG">头像1.JPG</a>
<a href="${pageContext.request.contextPath}/file/download2?fileName=头像1.JPG">头像1.JPG</a>
</body>
控制器
// 进行文件下载的操作
@RequestMapping("/downLoad")
public void downLoad(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
//设置响应头
//如果文件名有中文,需要设置为utf-8
String saveFileName = URLEncoder.encode(fileName, "utf-8");
//告诉浏览器发送的数据是一个附件,浏览器收到后会自动下载
response.setHeader("Content-Disposition", "attachment; filename=" + saveFileName);
//告诉浏览器发送的数据类型
response.setContentType("application/octet-stream;charset=utf-8"); //二进制流数据(最常见的文件下载)通用数据类型
//获取文件的真实路径
String realPath = request.getServletContext().getRealPath("/static/files/" + fileName);
//将文件内容写入到响应输出流中
//使用IO流来进行读写操作,读取文件,写入到响应输出流中
InputStream in = new FileInputStream(realPath);
//告诉浏览器发送的数据长度
//获取文件的大小
int size = in.available();
//设置响应头的长度:文件的大小
response.setContentLength(size);
//获取响应输出流
ServletOutputStream out = response.getOutputStream();
byte[] bys = new byte[1024];
int len = 0;
while ((len = in.read(bys)) != -1) {
out.write(bys, 0, len);
}
out.flush();
in.close();
out.close();
}
// 实现下载的第二种方式
@RequestMapping("/download2")
public ResponseEntity download2(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
// 得到图片的路径
String paths = request.getServletContext().getRealPath("/static/files/" + fileName);
InputStream in = new FileInputStream(paths);
//定义byte数组,长度就是整个图片的长度
byte[] bys = new byte[in.available()];
//读取图片
in.read(bys);
//设置响应头
HttpHeaders headers = new HttpHeaders();
//封装一个HttpHeader 响应头对象
//告诉浏览器发送的数据类型
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//如果文件名有中文,需要设置为utf-8
String saveFileName = URLEncoder.encode(fileName, "utf-8");
// 告诉浏览器发送的数据是一个附件,浏览器收到后会自动下载
headers.setContentDispositionFormData("attachment", saveFileName);
//告诉浏览器发送的数据长度
headers.setContentLength(bys.length);
//将数据,响应头,响应状态码封装到ResponseEntity对象中
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bys, headers, HttpStatus.OK);
// 返回ResponseEntity对象
return responseEntity;
}
异步请求实现图片上传至控制器
一般情况下需求是添加:一个表单通过异步请求提交给控制器,目的是把数据保存到数据库中,其中包含图片
情景:添加学生信息,包含学生图像
控制器:(整体思路和同步相同)
@RequestMapping("/addStudent")
@ResponseBody
public ResponseEntity addStudent(Student student, MultipartFile student_img, HttpServletRequest request) throws IOException {
//MultipartFile student_img 除了图像其余学生信息正常传值,图像单独处理,
//所以表单上的学生图像字段,不能和实体类字段一致(一致的话就自动映射到studnet对象里面了)
//这里实体类是studentImg 表单的name设置为student_img
// 获取文件夹路径
String dir = request.getServletContext().getRealPath("/static/image");
// 判断文件夹是否存在,不存在则创建
File path = new File(dir);
if (!path.exists()) {
path.mkdirs();
}
// 获取文件名
String oldFileName = student_img.getOriginalFilename();
// 生成新的文件名
String newFileName = FileNameByUUID.getFileName() + FileTypeUtil.getFileType(oldFileName);
// 创建文件
File file = new File(dir, newFileName);
// 保存文件
student_img.transferTo(file);
// 设置图片路径
student.setStudentImg(newFileName);
student.setStudentId(IdUtil.getId());
try {
Boolean aBoolean = studentService.addStudent(student);
if (aBoolean) {
return new ResponseEntity("添加成功", Commons.SUCCESS);
} else {
return new ResponseEntity("添加失败", Commons.FAILES);
}
} catch (SystemException e) {
return new ResponseEntity(Commons.EXCEPTIONMSG, Commons.SYSTEMEXCEPTION);
} catch (BusinessException e) {
return new ResponseEntity(e.getMessage(), Commons.BUSINESSEXCEPTION);
} catch (Exception e) {
return new ResponseEntity("error,请联系管理员", Commons.EXCEPTION);
}
}
JSP页面的表单:(引用的是Bootstrap样式)
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" id="close"><span
aria-hidden="true">☣︎</span></button>
<h4 class="modal-title" id="myModalLabel">添加学生信息</h4>
</div>
<div class="modal-body">
<form id="myForm" method="post">
学生姓名:<input type="text" name="studentName"><br>
学生性别:<input type="radio" name="studentSex" value="男">男
<input type="radio" name="studentSex" value="女">女<br>
出生日期:<input type="date" name="studentBornDate"><br>
<%--不能和实体类的属性名一样,一样的话就自动装到student对象里面了--%>
学生头像:<input type="file" name="student_img" id="showImg">
<div id="studentImg">
<img src="" id="img" style="width: 50px">
</div>
<br>
学生班级:
<select name="studentClass.classId" id="studentClass">
</select>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="btn-save">提交</button>
</div>
</div>
</div>
</div>
JS代码:
function addStudent() {
console.log("拿到的数据:" + $("#myForm").serialize());
$.ajax({
url: "/springmvc0512_studentByAjax/student/addStudent",
//type:请求的方式
type: "post",
//data:请求的参数
data: new FormData($("#myForm")[0]),
//contentType:false
contentType: false,
//processData指不对数据做任何处理
processData: false,
success: function (msg) {
if (msg.code == 200) {
//bootstrap中拟态框写好的关闭样式
$('#myModal').modal('hide');
//再刷新一个页面
loadStudent(1, 4);
/* $("#close").trigger("click");
console.log("确认已经点击")
alert("添加成功!");*/
} else if (msg.code == 500) {
$('#myModal').modal('hide');
alert(msg.message);
} else if (msg.code == 400) {
$('#myModal').modal('hide');
alert(msg.message);
}
}
});
}
到此:同步异步在控制器获取图片都已经解决
另外,因为数据库保存的是图片名称,如果需求是删除这条数据也需要把对应的图片删除的话
controller:(以学生信息为例)
@RequestMapping("/delete")
public ResponseEntity delete(Integer studentId, HttpServletRequest request) {
try {
//根据学生编号查询学生信息
Student byId = studentService.getById(studentId);
//获取学生头像
String studentImg = byId.getStudentImg();
//删除学生信息 一定要在删除学生头像之前获取图片名称,要不然删了就获取不到了
Boolean delete = studentService.delete(studentId);
if (delete) {
//如果删除操作成功了,对应的把图片也删除
//获取图片的路径
String path = request.getServletContext().getRealPath("/static/image/" + studentImg);
//根据路径创建文件对象
File file = new File(path);
//判断文件是否存在,存在则删除
if (file.exists()) {
file.delete();
}
return new ResponseEntity(Commons.SUCCESS, "成功!");
} else {
return new ResponseEntity(Commons.FAILES, "失败!");
}
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity(Commons.EXCEPTIONMSG, Commons.EXCEPTION);
}
}
更新操作,是通过主键更新所有字段,因为其他的标签都可以写默认值,但是图片不能写默认值
那么,如果用户没有对图片进行修改的话,空图片进入控制器后进入数据库,用户原本的图片就没有了
解决思路:
1、使用动态SQL判断图片字段是否为空,为空则不修改
2、在控制器判断用户是否修改了图片,如果没有修改,查出来用户之前的图片并赋值给对象,然后再进行更新
方法2代码示例:
@RequestMapping("/update/{studentId}")
public ResponseEntity update(Student student, @PathVariable("studentId") Integer studentId, MultipartFile stuImg, HttpServletRequest request) {
try {
student.setStudentId(studentId);
Boolean updateMsg = false;
String oldStudentImg = null;
if (stuImg != null) {//如果用户修改了图片
//查询用户之前的图片,修改完成后把之前的图片删除
Student byId = studentService.getById(studentId);
oldStudentImg = byId.getStudentImg();
String dir = request.getServletContext().getRealPath("/static/image");
// 判断文件夹是否存在,不存在则创建
File path = new File(dir);
if (!path.exists()) {
path.mkdirs();
}
String oldFileName = stuImg.getOriginalFilename();
String newFileName = FileNameByUUID.getFileName() + FileTypeUtil.getFileType(oldFileName);
File file = new File(dir, newFileName);
stuImg.transferTo(file);
student.setStudentImg(newFileName);
updateMsg = studentService.update(student);
} else {
Student byId = studentService.getById(student.getStudentId());
student.setStudentImg(byId.getStudentImg());
updateMsg = studentService.update(student);
}
if (updateMsg) {
if (oldStudentImg != null) {
//如果修改成功了,对应的把图片也删除
//获取图片的路径
String path = request.getServletContext().getRealPath("/static/image/" + oldStudentImg);
//根据路径创建文件对象
File file = new File(path);
//判断文件是否存在,存在则删除
if (file.exists()) {
file.delete();
}
}
return new ResponseEntity(Commons.SUCCESS, "成功!");
} else {
return new ResponseEntity(Commons.FAILES, "失败!");
}
} catch (IOException e) {
System.out.println(e.getMessage());
return new ResponseEntity(Commons.EXCEPTIONMSG, Commons.EXCEPTION);
}
}
扩展:如何实现这种效果
JSP
学生头像:<input type="file" name="student_img" id="showImg">
<div id="studentImg">
<img src="" id="img" style="width: 50px">
</div>
JS
<script>
window.onload = function () {
//获取下拉框
let input_file = document.querySelector("#showImg");
//给下拉框添加事件
input_file.onchange = function () {
//判断是否有文件
if (input_file.files.length > 0) {
//获取文件
let file = input_file.files[0];
//创建文件读取对象
let reader = new FileReader();
//读取文件
reader.readAsDataURL(file);
//读取完成后
reader.onload = function () {
//获取img标签
let img = document.querySelector("#img");
//设置img标签的src属性
img.src = reader.result;
}
}
}
}
</script>