第一种,前后端分离,前端采用vue+element
逻辑:通过前端上传图片到后端,后端将其保存到服务器,并将其保存路径及其他信息返回给前端,前端再将该图片路径及其学生信息一起提交
StuAdd.vue
<template>
<el-card class="box-card">
<el-form ref="form" :model="stu" label-width="80px">
<el-form-item label="选择头像">
<el-upload
class="upload-demo"
action="http://localhost:9999/stu/stu/addPic"
:on-success="handleSuccess"
:file-list="fileList"
list-type="picture">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="stu.name"></el-input>
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="stu.age"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="stu.email"></el-input>
</el-form-item>
<el-form-item label="生日">
<el-col :span="12">
<el-date-picker type="date" placeholder="选择日期" v-model="stu.birth" style="width: 100%;"></el-date-picker>
</el-col>
</el-form-item>
<el-form-item label="所在学校">
<el-select v-model="stu.schid" placeholder="活动区域">
<el-option v-for="(item,index) in schs" :label="item.name"
:value="item.id" :key="index"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addStu">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
export default {
name:'app',
data(){
return{
stu:{
name:'',
age:'',
birth:'',
email:'',
schid:'',
pics:[],
savepath:[],
realname:[],
uploadtime:[],
},
schs:[],
fileList:[],
}
},
methods:{
//文件上传成功时的钩子
handleSuccess(response,file,fileList){
this.stu.pics.push(response.data)
this.stu.savepath.push(response.data.savepath)
this.stu.realname.push(response.data.realname)
this.stu.uploadtime.push(response.data.uploadtime)
},
addStu(){
this.$http.post('/stu/addStu',
//本来是 stu{name:xx,age:xx,pics:[{},{}]}
//加上 arrayFormat:'repeat' 变成 stu{name:xx,age:xx,pics[name]=xx&pics[savepath]=xx&...}
//加上 allowDots:true 变成 stu{name:xx,age:xx,pics.name=xx&pics.savepath=xx&...}
this.$qs.stringify(this.stu,{allowDots:true,arrayFormat:'repeat'}))
.then(response=>{
}).catch(error=>console.log('出错了:'+error))
},
queryAllSchs(){
this.$http.get('/stu/queryAllSch')
.then(response=>{
this.schs = response.data.data
}).catch(error=>console.log('出错了:'+error))
},
},
created(){
this.queryAllSchs()
}
}
</script>
<style lang="less" scoped>
</style>
其中 :on-success="handleSuccess" 表示上传成功后执行的方法,主要是将图片存储路径返回给该vue容器
- 第一种后台处理代码:采用servlet处理请求,fileupload处理上传,fastjson处理json格式返回
- 导入文件上传依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
- 代码
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.alibaba.fastjson.JSONArray;
@WebServlet("/addpic")
public class PicServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用第三方组件接收文件 commons-fileupload
FileItemFactory f = new DiskFileItemFactory();
//文件解析器:从req中获得文件对象
ServletFileUpload su = new ServletFileUpload(f);
//解析请求 FileItem:代表 表单空间 如:text password checkbox radio file
try {
List<FileItem> items = su.parseRequest(req);
for (FileItem item : items) {
//如果不是普通表单项,file就不是普通表单项
if (!item.isFormField()) {
//获取文件名字
String fileName = item.getName();
//设置新的唯一的名字防止被覆盖
//获得后缀
String fExt = fileName.substring(fileName.lastIndexOf("."));
//重新命名
String newName = UUID.randomUUID().toString().replaceAll("-","")+fExt;
//path:存放图片的父目录
ServletContext application = this.getServletContext();
//获取 /files 在服务器上的绝对路径
//也就是 该项目所在本地路径 + /files
String path = application.getRealPath("/files");
//该路径不存在,我们先创建
File parent = new File(path);
if (!parent.exists()) {
parent.mkdir();
}
File file = new File(parent,newName);
//保存到服务器
item.write(file);
//以上步骤是把文件保存到服务器,
// 以下把文件信息传递给前端,等待着和学生信息一起传递到数据库中
Pic pic = new Pic();
pic.setRealname(fileName);
pic.setSavepath("/files/"+newName);
pic.setUploadtime(new Timestamp(System.currentTimeMillis()));
pic.setFlag(0);
//返回信息对象
JsonResponse jr = new JsonResponse();
jr.setCode(200);
jr.setMsg("success");
jr.setData(pic);
resp.setContentType("text/plain;charset=UTF-8");
//打印流:原样输出,参数是什么,就输出什么。
PrintWriter out = resp.getWriter();
String str = JSONArray.toJSONString(jr);
out.print(str);
out.flush();
out.close();
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
- 第二种后台处理代码:springmvc全权处理
- 导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
- springmvc.xml文件中配置
<!--配置多元素解析器 即文件解析器对象
id固定为 multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件大小上限,单位为字节,当前为 10m。默认为 -1 表示没有限制。 -->
<property name="maxUploadSize" value="10485760"/>
</bean>
- 代码
import org.springframework.web.multipart.MultipartFile;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@RestController
@RequestMapping("/stu")
public class StudentController {
// public static final String JPEG = "image/jpeg";
// public static final String PNG = "image/png";
@PostMapping("/addPic")
public JsonResponse addPic(MultipartFile file,HttpServletRequest req){
// 1.文件不能为空
/* if (ObjectUtils.isEmpty(file)||file.isEmpty()){
return "文件不能为空";
}*/
// 2.文件类型:jpg、png
/* String contentType = file.getContentType();
if (!StringUtils.equalsAnyIgnoreCase(JPEG,contentType)&&
!StringUtils.equalsAnyIgnoreCase(PNG,contentType)){
return "仅支持jpg和png格式的图片";
}*/
//获取文件名字
String fileName = file.getOriginalFilename();
//获取文件后缀 .png\.jpg\.jpeg
String fExt = fileName.substring(fileName.lastIndexOf("."));
//获取文件扩展名 png\jpg\jpeg
//String extension = FilenameUtils.getExtension(originalFilename);
//重新命名
String newName = UUID.randomUUID().toString().replaceAll("-","")+fExt;
//path代表存放图片的父目录
ServletContext application = req.getServletContext();
//获取 /files 在服务器上的绝对路径
//也就是 该项目所在本地路径 + /files
String path = application.getRealPath("/files");
//该路径不存在,我们先创建
File parent = new File(path);
if(!parent.exists()){
parent.mkdir();
}
File f = new File(parent,newName);
//保存到服务器
try {
file.transferTo(f);
} catch (IOException e) {
e.printStackTrace();
}
//以上步骤是把文件保存到服务器 ,把文件传递给前端 等待着和学生信息一块传递到数据库
Pic pic = new Pic();
pic.setRealname(fileName);
pic.setSavepath("/files/"+newName);
//图片上传时间为 Timestamp 数据类型,即为时间戳
pic.setUploadtime(new Timestamp(System.currentTimeMillis()));
pic.setFlag(0);
//返回信息的对象
JsonResponse jr = new JsonResponse();
jr.setCode(200);
jr.setMsg("添加成功");
jr.setData(pic);
return jr;
}
//添加学生(学生信息+图片信息)
@PostMapping("/addStu")
public JsonResponse addStu(StudentVo vo){
Student stu = new Student();
//进行对象之间属性的赋值,避免通过get、set方法一个一个属性的赋值
//BeanUtils.copyProperties(source,target);
//source 源对象 target 目标对象 他们都是Object类型
BeanUtils.copyProperties(vo,stu);
service.addStuAndPic(stu,vo);
return null;
}
}
file.transferTo(f); //其底层就是使用io流
(1)调用的是 MultipartFile 的实现类 CommonsMultipartFile 的 transferTo(File dest) 方法
(2)其中有一行代码 this.fileItem.write(dest); 其中fileItem是commons.fileupload.FileItem类型。意思就是调用了org.apache.commons.fileupload 包中的 write(dest)方法
(3)其底层就是 fout = new FileOutputStream(dest); fout.write(this.get());
图片实体类
import java.sql.Timestamp;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pic {
private Integer id;
private String savepath;
private String realname;
private Timestamp uploadtime;
private Integer stuid;
private Integer flag;
}
学生实体类
public class Student {
private Integer id;
private String name;
private Integer age;
//注解@JsonFormat主要是后台到前台的时间格式的转换
//注解@DateTimeFormat主要是前台到后台的时间格式的转换
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birth;
private String email;
private Integer schid;
private School sch;
}
学生传输类
public class StudentVo {
private Integer pageNumber;
private Integer pageSize;
private String name;
private Integer age;
private String email;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
private Integer schid;
private String[] birth1;
private String startbirth;
private String endbirth;
private String[] savepath;
private String[] realname;
private String[] uploadtime;
}
第二种:自己编写的文件上传工具,仅供参考
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(path = "/register",method = {RequestMethod.POST})
public String register(User user,MultipartFile upload,String check) throws IOException {
//先通过表单提交过来的用户名,去查询是否存在该用户名
User user2 = iUserService.findUserByUsername(user.getUsername());
//不存在,则可以添加该用户
if (user2 == null){
//调用文件上传工具,上传图片至发布服务器和本地
String fileName = FileUploadUtils.fileUploadUtil(upload,"user",request);
//给传入的图片设置路径
user.setUserIcon(fileName);
return "redirect:/register-ok.jsp";
}else {
request.setAttribute("registerInfo","该用户名已被注册");
return "forward:/register.jsp";
}
}
}
package cn.cyl.utils.fileupload;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Properties;
import java.util.UUID;
//存储图片的文件上传工具
public class FileUploadUtils {
private static Properties properties;
private static String nativePath;
static {
//基于ClassLoder读取配置文件,只能读取类路径下的配置文件
properties = new Properties();
// 使用ClassLoader加载properties配置文件生成对应的输入流
InputStream in = FileUploadUtils.class.getClassLoader().getResourceAsStream("fileupload.properties");
// 使用properties对象加载输入流
try {
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
// 获取本地存储路径的值
nativePath = properties.getProperty("fileurl");
}
/**
* 通过springmvc配置上传文件
* @param upload MultipartFile类型参数,与controller控制方法和表单内的name对应
* @param smallPath 指明要存入的子目录名:主要有用户目录 user,寻物图片目录,招领图片目录
* @param request 请求,用来指定发布的服务的位置
* @return 返回文件名,方便数据库存储文件路径
* @throws IOException
*/
public static String fileUploadUtil(MultipartFile upload,String smallPath,HttpServletRequest request) throws IOException {
//获取上传文件的名称
String filename = upload.getOriginalFilename();
//如果没上传文件
//那么就设置为本地已存在的默认文件
if (filename==""){
if (smallPath=="user"){
filename = properties.getProperty("defaultUser");
}
if (smallPath=="found"){
filename = properties.getProperty("defaultFound");
}
if(smallPath=="lost"){
filename = properties.getProperty("defaultLost");
}
}else {
//上传的位置,即项目发布的服务器内,但本地没有,所有本地还会存储一份
String path = request.getSession().getServletContext().getRealPath("/images/"+smallPath);
//判断该路径是否存在
File file = new File(path);
if (!file.exists()){
//不存在则创建该文件夹
file.mkdirs();
}
//通过 uuid 把文件名称设置唯一值
String uuid = UUID.randomUUID().toString().replace("-","");
filename = uuid+"_"+filename;
//该行代码一定要在下一行代码之前,否则会出现重复转换导致异常
//将 MultipartFile 对象文件转换成输入流,并保存一份至本地路径(该处路径写死了,需要改进)
inputStreamToFile(upload.getInputStream(), new File(nativePath+smallPath+"\\"+filename));
//完成文件上传,并自动帮我们删除了临时文件
upload.transferTo(new File(path,filename));
}
return "images/"+smallPath+"/"+filename;
}
/**
* 将 该输入流 写出 到目标路径
* @param ins 输入流,主要是通过 MultipartFile类型数据文件转换得来
* @param file 输出目的地,即本地存储路径
*/
public static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}