SpringBoot+vue 文件传输+跨域
1:前端传输文件保存到后端:
1:导包
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version> <!-- 使用时请检查最新版本 -->
</dependency>
2:contoller
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile
import org.whh.base.util.AjaxResult;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequestMapping("/files")
public class FileController {
// 文件上传存储路径
private static final String filePath = System.getProperty("user.dir") + "/file/";
/**
* 文件上传
*/
@PostMapping("/upload")
public AjaxResult upload(MultipartFile file) {
synchronized (FileController.class) {
String flag = System.currentTimeMillis() + "";
String fileName = file.getOriginalFilename();
try {
if (!FileUtil.isDirectory(filePath)) {
FileUtil.mkdir(filePath);
}
// 文件存储形式:时间戳-文件名
FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName);
System.out.println(fileName + "--上传成功");
Thread.sleep(1L);
} catch (Exception e) {
System.err.println(fileName + "--文件上传失败");
}
return AjaxResult.success(flag);
}
}
/**
* 获取文件
*/
@GetMapping("/{flag}")
public void avatarPath(@PathVariable String flag, HttpServletResponse response) {
if (!FileUtil.isDirectory(filePath)) {
FileUtil.mkdir(filePath);
}
OutputStream os;
List<String> fileNames = FileUtil.listFileNames(filePath);
String avatar = fileNames.stream().filter(name -> name.contains(flag)).findAny().orElse("");
try {
if (StrUtil.isNotEmpty(avatar)) {
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(avatar, "UTF-8"));
response.setContentType("application/octet-stream");
byte[] bytes = FileUtil.readBytes(filePath + avatar);
os = response.getOutputStream();
os.write(bytes);
os.flush();
os.close();
}
} catch (Exception e) {
System.out.println("文件下载失败");
}
}
}
3: 前端
<el-form-item label="文件上传" label-width="20%">
<el-upload action="http://localhost:8080/api/files/upload" :on-success="successUpload">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-table-column label="文件下载">
<template v-slot="scope">
<el-image
style="width: 70px; height: 70px; border-radius: 50%"
:src="'http://localhost:8080/api/files/' + scope.row.img"
:preview-src-list="['http://localhost:8080/api/files/' + scope.row.img]">
</el-image>
</template>
</el-table-column>
<el-button type="primary" @click="down(scope.row.img)">下载</el-button>
方法
successUpload(res) {
上传成功后做一些操作
},
2:前端传输excel文件:
1:导包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.3</version>
</dependency>
2:controller
@PostMapping("/easyexcel")
public void easyexcel(@RequestBody Query query,HttpServletResponse response) throws IOException {
this.setExcelResponseProp(response, "员工表");
// 获取需要导出的列表
List<EmployeeVo> easyexcelist = employeeService.get(query);
// 设置格式
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle());
EasyExcel.write(response.getOutputStream())
.head(EmployeeVo.class)
.excelType(ExcelTypeEnum.XLSX)
.sheet("员工表")
.registerWriteHandler(horizontalCellStyleStrategy) //引入格式
.doWrite(easyexcelist);
}
private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
}
@RequestMapping("/importScore")
public void importScore(@RequestParam MultipartFile file,HttpServletResponse response) throws IOException {
//读取列表
List<EmployeeVo> importList = EasyExcel.read(file.getInputStream())
.head(EmployeeVo.class)
.sheet()
.doReadSync();
System.out.println("====================================");
importList.forEach(System.out::println);
// 正则表达式,用于匹配电子邮件地址
String emailRegex = "[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+";
Pattern pattern = Pattern.compile(emailRegex);
List<EmployeeVo> validEmails = new ArrayList<>();
List<EmployeeVo> invalidEmails = new ArrayList<>();
for (EmployeeVo employee : importList) {
String email = employee.getEmail();
if (Objects.nonNull(email) && pattern.matcher(email).matches()) {
validEmails.add(employee); // 如果是有效的电子邮件,添加到validEmails列表中
} else {
invalidEmails.add(employee); // 如果不是有效的电子邮件,添加到invalidEmails列表中
}
}
// 设置格式
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle());
EasyExcel.write(response.getOutputStream())
.head(EmployeeVo.class)
.excelType(ExcelTypeEnum.XLSX)
.sheet("错误数据表")
.registerWriteHandler(horizontalCellStyleStrategy) //引入格式
.doWrite(invalidEmails);
employeeService.upInsert(validEmails);
// if (!invalidEmails.isEmpty()){
// return AjaxResult.success(invalidEmails);
// }
// return AjaxResult.success("全部成功");
}
3:前端
<el-upload :http-request="upLoadError" action="ip/employee/importScore" >
<el-button type="primary">点击上传</el-button>
</el-upload>
upLoadError(data){
let param = new FormData;
param.append("file",data.file);
this.$http({
url: '/employee/importScore',
method: 'post',
responseType: 'blob',
// 可根据下拉框 选择要导出信息
data: param
}).then(({data}) => {
if (!data || data.size === 0) {
this.$message({message: '列表为空', type: 'error', duration: 1500});
return
}
let blob = new Blob([data], {type: 'application/vnd.ms-excel'})
let url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = '错误数据表.xls' // 重命名文件
link.click()
URL.revokeObjectURL(url) // 释放内存
this.queryData();
})
},
outExcel(){
this.$http({
url: '/employee/easyexcel',
method: 'post',
responseType: 'blob',
// 可根据下拉框 选择要导出的年级或者学校名字的同学信息
data: this.search
}).then(({data}) => {
if (!data || data.size === 0) {
this.$message({
message: '列表为空',
type: 'error',
duration: 1500
})
return
}
let blob = new Blob([data], {type: 'application/vnd.ms-excel'})
let url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = '员工表.xls' // 重命名文件
link.click()
URL.revokeObjectURL(url) // 释放内存
})
},
跨域
vue代理
修改 index.js ,增加如下内容:
proxyTable: {
'/api': { //所有以api开头的url都代理给下面的地址
target: 'http://localhost:80', //所有以api开头的请求,都代理给 http://localhost:80
changeOrigin: true,
pathRewrite: { //路径重新
'^/api': '' // 当请求的地址中有api开头,会去掉api吧请求定向到 http://localhost:80 后台地址
}
},
}
在main.js添加统一的 api前缀
axios.defaults.baseURL='/api'
页面请求效果
this.$http.post("/dept/page",para)...省略...
后端CrosFilter解决
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://127.0.0.1:8081");
config.addAllowedOrigin("http://localhost:8081");
config.addAllowedOrigin("http://127.0.0.1:80");
config.addAllowedOrigin("http://localhost:80");
config.addAllowedOrigin("http://127.0.0.1");
config.addAllowedOrigin("http://localhost");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new
UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
Njinx代理
解决跨域(将前端的8088端口请求转接到后端8080端口)
server {
listen 8088;
server_name localhost;
location / {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'PATCH,GET,POST,DELETE,PUT,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,token,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'PATCH,GET,POST,DELETE,PUT,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,token,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5;
}
}