当前位置:   article > 正文

vue+spring boot实现文件上传_springboot vue文件上传

springboot vue文件上传

目录

1.前端画面

2.后端

3.总结


1.前端画面

  1. <template>
  2. <div class="app-container">
  3. <el-descriptions title="入区信息" border style="margin-bottom: 20px">
  4. <el-descriptions-item label="申报平台名称">{{ showDescription.companyName }}</el-descriptions-item>
  5. <el-descriptions-item label="主管关区">
  6. <dict-tag :options="dict.type.master_cuscd" :value="showDescription.masterCuscd"/>
  7. </el-descriptions-item>
  8. <el-descriptions-item label="核放单编号">{{ showDescription.passportNo }}</el-descriptions-item>
  9. <el-descriptions-item label="承运车牌号">{{ showDescription.vehicleNo }}</el-descriptions-item>
  10. <el-descriptions-item label="申报入区日期">{{ showDescription.declInputDate }}</el-descriptions-item>
  11. </el-descriptions>
  12. <el-row :gutter="10" class="mb8">
  13. <el-col :span="1.5">
  14. <el-button
  15. type="danger"
  16. plain
  17. icon="el-icon-delete"
  18. size="mini"
  19. :disabled="multiple"
  20. @click="handleDelete"
  21. v-hasPermi="['goodsManage:storageInDetail:remove']"
  22. >删除
  23. </el-button>
  24. </el-col>
  25. <el-col :span="1.5">
  26. <el-button
  27. type="success"
  28. plain
  29. icon="el-icon-upload"
  30. size="mini"
  31. @click="handleImport"
  32. >导入
  33. </el-button>
  34. </el-col>
  35. <el-col :span="1.5">
  36. <el-button
  37. type="warning"
  38. plain
  39. icon="el-icon-download"
  40. size="mini"
  41. @click="handleExport"
  42. v-hasPermi="['goodsManage:storageInDetail:export']"
  43. >导出
  44. </el-button>
  45. </el-col>
  46. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  47. </el-row>
  48. <el-table v-loading="loading" :data="storageInDetailList" @selection-change="handleSelectionChange">
  49. <el-table-column type="selection" width="55" align="center" />
  50. <el-table-column label="序号" align="center" type="index" fixed/>
  51. <el-table-column label="核放单编号" align="center" prop="passportNo" width="240" />
  52. <el-table-column label="申报平台名称" align="center" prop="companyName" width="200" show-overflow-tooltip/>
  53. <el-table-column label="料号" align="center" prop="itemRecordNo" width="150"/>
  54. <el-table-column label="商品编码" align="center" prop="gcode" width="150"/>
  55. <el-table-column label="商品名称" align="center" prop="gname" width="150" show-overflow-tooltip/>
  56. <el-table-column label="申报计量单位" align="center" prop="unit" width="100"/>
  57. <el-table-column label="申报数量" align="center" prop="qty"/>
  58. <el-table-column label="货物毛重" align="center" prop="grossWeight"/>
  59. <el-table-column label="货物净重" align="center" prop="netWeight"/>
  60. <el-table-column label="备注" align="center" prop="note"/>
  61. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
  62. <template slot-scope="scope">
  63. <el-button
  64. size="mini"
  65. type="text"
  66. icon="el-icon-edit"
  67. @click="handleUpdate(scope.row)"
  68. v-hasPermi="['goodsManage:storageInDetail:edit']"
  69. v-if="false"
  70. >修改
  71. </el-button>
  72. <el-button
  73. size="mini"
  74. type="text"
  75. icon="el-icon-delete"
  76. @click="handleDelete(scope.row)"
  77. v-hasPermi="['goodsManage:storageInDetail:remove']"
  78. >删除
  79. </el-button>
  80. </template>
  81. </el-table-column>
  82. </el-table>
  83. <pagination
  84. v-show="total>0"
  85. :total="total"
  86. :page.sync="queryParams.pageNum"
  87. :limit.sync="queryParams.pageSize"
  88. @pagination="getList"
  89. />
  90. <!-- 添加或修改国内低值货物入区子表对话框 -->
  91. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
  92. <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  93. <el-form-item label="入区主表id" prop="pid">
  94. <el-input v-model="form.pid" placeholder="请输入入区主表id"/>
  95. </el-form-item>
  96. <el-form-item label="核放单编号" prop="passportNo">
  97. <el-input v-model="form.passportNo" placeholder="请输入核放单编号"/>
  98. </el-form-item>
  99. <el-form-item label="申报平台id" prop="companyId">
  100. <el-input v-model="form.companyId" placeholder="请输入申报平台id"/>
  101. </el-form-item>
  102. <el-form-item label="申报平台名称" prop="companyName">
  103. <el-input v-model="form.companyName" placeholder="请输入申报平台名称"/>
  104. </el-form-item>
  105. <el-form-item label="料号" prop="itemRecordNo">
  106. <el-input v-model="form.itemRecordNo" placeholder="请输入料号"/>
  107. </el-form-item>
  108. <el-form-item label="商品编码" prop="gcode">
  109. <el-input v-model="form.gcode" placeholder="请输入商品编码"/>
  110. </el-form-item>
  111. <el-form-item label="商品名称" prop="gname">
  112. <el-input v-model="form.gname" placeholder="请输入商品名称"/>
  113. </el-form-item>
  114. <el-form-item label="申报计量单位" prop="unit">
  115. <el-input v-model="form.unit" placeholder="请输入申报计量单位"/>
  116. </el-form-item>
  117. <el-form-item label="申报数量" prop="qty">
  118. <el-input v-model="form.qty" placeholder="请输入申报数量"/>
  119. </el-form-item>
  120. <el-form-item label="货物毛重" prop="grossWeight">
  121. <el-input v-model="form.grossWeight" placeholder="请输入货物毛重"/>
  122. </el-form-item>
  123. <el-form-item label="货物净重" prop="netWeight">
  124. <el-input v-model="form.netWeight" placeholder="请输入货物净重"/>
  125. </el-form-item>
  126. <el-form-item label="备注" prop="note">
  127. <el-input v-model="form.note" type="textarea" placeholder="请输入内容"/>
  128. </el-form-item>
  129. </el-form>
  130. <div slot="footer" class="dialog-footer">
  131. <el-button type="primary" @click="submitForm">确 定</el-button>
  132. <el-button @click="cancel">取 消</el-button>
  133. </div>
  134. </el-dialog>
  135. <!-- 上传文件对话框 -->
  136. <upload-dialog :info="info" ref="uploadDialog"/>
  137. </div>
  138. </template>
  139. <script>
  140. import {
  141. listStorageInDetail,
  142. getStorageInDetail,
  143. delStorageInDetail,
  144. addStorageInDetail,
  145. updateStorageInDetail
  146. } from "@/api/goodsManage/storageInDetail";
  147. import {getStorageInMaster} from "@/api/goodsManage/storageInMaster";
  148. export default {
  149. name: "StorageInDetail",
  150. dicts: ['master_cuscd'],
  151. data() {
  152. return {
  153. // 遮罩层
  154. loading: true,
  155. // 选中数组
  156. ids: [],
  157. // 非单个禁用
  158. single: true,
  159. // 非多个禁用
  160. multiple: true,
  161. // 显示搜索条件
  162. showSearch: true,
  163. // 总条数
  164. total: 0,
  165. // 国内低值货物入区子表表格数据
  166. storageInDetailList: [],
  167. //画面头显示
  168. showDescription: {},
  169. // 弹出层标题
  170. title: "",
  171. // 是否显示弹出层
  172. open: false,
  173. /**导入相关参数*/
  174. info: {
  175. url: "/goodsManage/storageInDetail/import",
  176. title: "入区货物明细导入",
  177. open: false,
  178. params: null
  179. },
  180. // 查询参数
  181. queryParams: {
  182. pageNum: 1,
  183. pageSize: 10,
  184. pid: null,
  185. passportNo: null,
  186. companyId: null,
  187. companyName: null,
  188. itemRecordNo: null,
  189. gcode: null,
  190. gname: null,
  191. unit: null,
  192. qty: null,
  193. grossWeight: null,
  194. netWeight: null,
  195. note: null,
  196. },
  197. // 表单参数
  198. form: {},
  199. // 表单校验
  200. rules: {}
  201. };
  202. },
  203. created() {
  204. this.queryParams.pid = this.$route.params && this.$route.params.id;
  205. this.getMasterInfo();
  206. this.getList();
  207. },
  208. watch: {
  209. //监听上传组件弹框关闭
  210. 'info.open': {
  211. immediate: false,
  212. handler: function (val) {
  213. if (!val) {
  214. //刷新列表
  215. this.loading = true;
  216. setTimeout(this.handleQuery, 2000);
  217. }
  218. }
  219. }
  220. },
  221. methods: {
  222. /** 查询国内低值货物入区主表列表 */
  223. getMasterInfo(){
  224. getStorageInMaster(this.queryParams.pid).then(response =>{
  225. this.showDescription = response.data;
  226. })
  227. },
  228. /** 查询国内低值货物入区子表列表 */
  229. getList() {
  230. this.loading = true;
  231. listStorageInDetail(this.queryParams).then(response => {
  232. this.storageInDetailList = response.rows;
  233. this.total = response.total;
  234. this.loading = false;
  235. });
  236. },
  237. // 取消按钮
  238. cancel() {
  239. this.open = false;
  240. this.reset();
  241. },
  242. // 表单重置
  243. reset() {
  244. this.form = {
  245. id: null,
  246. pid: null,
  247. passportNo: null,
  248. companyId: null,
  249. companyName: null,
  250. itemRecordNo: null,
  251. gcode: null,
  252. gname: null,
  253. unit: null,
  254. qty: null,
  255. grossWeight: null,
  256. netWeight: null,
  257. note: null,
  258. createBy: null,
  259. createTime: null,
  260. updateBy: null,
  261. updateTime: null
  262. };
  263. this.resetForm("form");
  264. },
  265. /** 搜索按钮操作 */
  266. handleQuery() {
  267. this.queryParams.pageNum = 1;
  268. this.getList();
  269. },
  270. /** 重置按钮操作 */
  271. resetQuery() {
  272. this.resetForm("queryForm");
  273. this.handleQuery();
  274. },
  275. /**导入处理*/
  276. handleImport() {
  277. this.info.open = true;
  278. this.info.params = {pid: this.queryParams.pid};
  279. },
  280. // 多选框选中数据
  281. handleSelectionChange(selection) {
  282. this.ids = selection.map(item => item.id)
  283. this.single = selection.length !== 1
  284. this.multiple = !selection.length
  285. },
  286. /** 新增按钮操作 */
  287. handleAdd() {
  288. this.reset();
  289. this.open = true;
  290. this.title = "添加国内低值货物入区子表";
  291. },
  292. /** 修改按钮操作 */
  293. handleUpdate(row) {
  294. this.reset();
  295. const id = row.id || this.ids
  296. getStorageInDetail(id).then(response => {
  297. this.form = response.data;
  298. this.open = true;
  299. this.title = "修改国内低值货物入区子表";
  300. });
  301. },
  302. /** 提交按钮 */
  303. submitForm() {
  304. this.$refs["form"].validate(valid => {
  305. if (valid) {
  306. if (this.form.id != null) {
  307. updateStorageInDetail(this.form).then(response => {
  308. this.$modal.msgSuccess("修改成功");
  309. this.open = false;
  310. this.getList();
  311. });
  312. } else {
  313. addStorageInDetail(this.form).then(response => {
  314. this.$modal.msgSuccess("新增成功");
  315. this.open = false;
  316. this.getList();
  317. });
  318. }
  319. }
  320. });
  321. },
  322. /** 删除按钮操作 */
  323. handleDelete(row) {
  324. const ids = row.id || this.ids;
  325. this.$modal.confirm('是否确认删除国内低值货物入区子表编号为"' + ids + '"的数据项?').then(function () {
  326. return delStorageInDetail(ids);
  327. }).then(() => {
  328. this.getList();
  329. this.$modal.msgSuccess("删除成功");
  330. }).catch(() => {
  331. });
  332. },
  333. /** 导出按钮操作 */
  334. handleExport() {
  335. this.download('goodsManage/storageInDetail/export', {
  336. ...this.queryParams
  337. }, `storageInDetail_${new Date().getTime()}.xlsx`)
  338. },
  339. selectCompany(val) {
  340. this.queryParams.companyId = val;
  341. this.handleQuery();
  342. }
  343. }
  344. };
  345. </script>

上传组件

  1. <template>
  2. <el-dialog v-dialog-drag ref="uploadDialog" :title="info.title" :visible.sync="info.open" width="500px"
  3. append-to-body>
  4. <el-upload
  5. drag
  6. accept=".xls, .xlsx"
  7. action="#"
  8. :show-file-list="false"
  9. :http-request="requestUpload"
  10. :before-upload="beforeUpload">
  11. <i class="el-icon-upload"></i>
  12. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  13. <div slot="tip" class="el-upload__tip">只能上传xls/xlsx文件</div>
  14. </el-upload>
  15. </el-dialog>
  16. </template>
  17. <script>
  18. import {upload} from "@/api/tool/upload";
  19. export default {
  20. props: {
  21. info: {
  22. url: null,
  23. title: null,
  24. open: Boolean,
  25. params: null
  26. }
  27. },
  28. data() {
  29. return {
  30. // 上传参数
  31. upload: {
  32. file: null,
  33. updateSupport: true,
  34. params: null
  35. }
  36. };
  37. },
  38. methods: {
  39. beforeUpload(file) {
  40. this.upload.file = file;
  41. if (this.info.params) {
  42. this.upload.params = JSON.stringify(this.info.params);
  43. }
  44. },
  45. requestUpload() {
  46. let formData = new FormData();
  47. formData.append("file", this.upload.file);
  48. formData.append("updateSupport", this.upload.updateSupport);
  49. formData.append("params", this.upload.params);
  50. upload(this.info.url, formData).then(response => {
  51. this.info.open = false;
  52. this.$modal.msgSuccess("导入成功");
  53. });
  54. },
  55. }
  56. };
  57. </script>

上传组件js

  1. import request from "@/utils/request";
  2. /**
  3. * 上传文件
  4. * @param data
  5. * @returns {AxiosPromise}
  6. */
  7. export function upload(url,data) {
  8. return request({
  9. url: url,
  10. method: 'post',
  11. data: data
  12. })
  13. }

2.后端

  1. /**
  2. * @param file
  3. * @param params
  4. * @return
  5. * @throws Exception
  6. */
  7. @PreAuthorize("@ss.hasPermi('goodsManage:storageInDetail:add')")
  8. @Log(title = "国内低值货物入区子表", businessType = BusinessType.IMPORT)
  9. @PostMapping("/import")
  10. public AjaxResult importExcel(@RequestParam("file") MultipartFile file, String params) throws Exception {
  11. storageInDetailService.importMaster(file, params);
  12. return AjaxResult.success();
  13. }
  1. @Override
  2. @Transactional(rollbackFor = Exception.class)
  3. public int importMaster(MultipartFile file, String params) throws Exception {
  4. //导入校验是否主表已经审核通过,审核通过不允许再次导入
  5. checkMasterApproveType(params);
  6. //读取Excel信息
  7. DynamicHeaderListener parseListener = new DynamicHeaderListener();
  8. EasyExcel.read(file.getInputStream(), parseListener).sheet("表体").headRowNumber(2).doReadSync();
  9. List<Map<Integer, String>> dataList = parseListener.getList();
  10. if (CollUtil.isEmpty(dataList)) {
  11. log.error("读入的入区明细为空");
  12. throw new MultipartException("读入的入区明细为空,请重新导入");
  13. }
  14. JSONObject param = JSON.parseObject(params);
  15. Long pid = param.getLongValue("pid");
  16. //查询主表信息
  17. StorageInMaster storageInMaster = storageInMasterService.getById(pid);
  18. if (ObjectUtil.isEmpty(storageInMaster)) {
  19. log.error("入区信息不存在");
  20. throw new MultipartException("入区信息不存在,请确认");
  21. }
  22. List<StorageInDetail> details = new ArrayList<>();
  23. dataList.forEach(item -> {
  24. StorageInDetail storageInDetail = new StorageInDetail();
  25. //入区主表id
  26. storageInDetail.setPid(pid);
  27. //核放单编号
  28. storageInDetail.setPassportNo(storageInMaster.getPassportNo());
  29. //申报平台id
  30. storageInDetail.setCompanyId(storageInMaster.getCompanyId());
  31. //申报平台名称
  32. storageInDetail.setCompanyName(storageInMaster.getCompanyName());
  33. //料号
  34. storageInDetail.setItemRecordNo(item.get(2));
  35. //商品编码
  36. storageInDetail.setGcode(item.get(3));
  37. //商品名称
  38. storageInDetail.setGname(item.get(4));
  39. //申报计量单位
  40. storageInDetail.setUnit(item.get(5));
  41. //申报数量
  42. storageInDetail.setQty(BigDecimal.valueOf(Long.parseLong(item.get(6))));
  43. //货物毛重
  44. storageInDetail.setGrossWeight(Convert.toBigDecimal(item.get(7), BigDecimal.ZERO));
  45. //货物净重
  46. storageInDetail.setNetWeight(Convert.toBigDecimal(item.get(8), BigDecimal.ZERO));
  47. //备注
  48. storageInDetail.setNote(item.get(9));
  49. //创建人
  50. storageInDetail.setCreateBy(SecurityUtils.getUserId().toString());
  51. details.add(storageInDetail);
  52. });
  53. BigDecimal declQty = new BigDecimal(0);
  54. for (StorageInDetail insertData : details) {
  55. this.save(insertData);
  56. declQty = declQty.add(insertData.getQty());
  57. }
  58. StorageInMaster updateMaster = new StorageInMaster();
  59. updateMaster.setDeclQty(declQty);
  60. updateMaster.setId(pid);
  61. storageInMasterService.updateById(updateMaster);
  62. return 1;
  63. }

3.总结

上传文件时,要使用 FormData() 构造函数,将上传的文件及参数封装在FormData()中,同时浏览器会自动识别并添加请求头 "Content-Type: multipart/form-data",且参数依然像是表单提交时的那种键值对儿,此外 FormData() 构造函数 new 时可以直接传入 form 表单的 dom 节点。注意使用post请求,后端接收的时候可以使用requestParam,也可以不使用。

Content-Type: multipart/form-data,这种类型是后来追加的。为什么要新增一个类型,而不使用旧有的application/x-www-form-urlencoded:因为旧有类型不适合用于传输大型二进制数据或者包含非ASCII字符的数据。平常我们使用这个类型都是把表单数据使用url编码后传送给后端,二进制文件当然没办法一起编码进去了。所以multipart/form-data就诞生了,专门用于有效的传输文件。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/283687
推荐阅读
相关标签
  

闽ICP备14008679号