用Spring Boot & Angular2快速开发文件上传服务
来源:互联网 发布:mysql desc 命令 编辑:程序博客网 时间:2024/06/10 16:08
序
文件上传可以作为一个独立的微服务。用Spring Boot和Angular2开发这样的服务非常有优势,可以用最少的代码,实现非常强的功能。如果比了解Spring Boot和Angular2的,请先看这几个文章:
用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 实现RESTful CRUD
用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - AngularJS2客户端
用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加代理服务器
用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加权限控制
Angular2文件上传组件
Angular2带来了全新的组件模型。如果你熟悉面向对象这个编程语言范式,就会发现这个新的组件模型和面向对象非常接近。我在学习到Angular2的组件模型的时候非常的激动,因为我觉得这是对前端开发模型的一个革命,就像C++语言之于汇编语言。它的好处显而易见,使用组件对代码基本上没有侵入性,容易写出高内聚松耦合的代码,等等。
言归正传,Angular2的文件上传组件我使用了这个:https://github.com/valor-software/ng2-file-upload/,然后简化了它的官方示例。下面是开发的步骤。
建立Angular2项目
在node环境中,先安装Angular2的CLI:
npm install -g angular-cli
用CLI的好处是,几个简单的命令就可以初始化Angular2项目,并且会自动生成相应的文件,不用自己手写了,另外打包发布也非常方便。用下面的命令建立uploader-client项目:
ng new uploader-client之后进入uploader-client目录,可以看到项目的相关文件都生成好了,我们可以直接开发业务代码了。具体请参考官网:https://github.com/angular/angular-cli
实现上传功能
进入uploader-client/src/app,下面app打头的文件我们需要修改一下:
app.module.ts:
import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { FormsModule } from '@angular/forms';import { HttpModule } from '@angular/http';import { AppComponent } from './app.component';import { FileUploadModule } from 'ng2-file-upload';@NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, FormsModule, HttpModule, FileUploadModule ], providers: [], bootstrap: [AppComponent]})export class AppModule { }
该文件导入了文件上传组件(FileUploadModule),因此修改的代码总共有2行,其它代码都是自动生成的。增加的行用绿底色标出子,但是由于页面编辑器的原因,实际上页面看不到绿色,看到的可能是这样的字符串:
请自行脑转,下面的代码有多处也是这样的。
<span style="background-color: rgb(51, 204, 0);">
请自行脑转,下面的代码有多处也是这样的。
app.component.ts:
import { Component } from '@angular/core';import { FileUploader, FileSelectDirective } from 'ng2-file-upload';@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css']})export class AppComponent { title = 'app works!'; public url:string = 'http://localhost:8080'; public uploader:FileUploader = new FileUploader({url: this.url});}这个文件添加了3行代码,其它也是自动生成的。增加的行也很简单,就是添加了一个名字叫做uploader的属性,是FileUploader的实例。
app.component.html
<h1> {{title}}</h1><div> <h3>Select files</h3> Multiple <input type="file" ng2FileSelect [uploader]="uploader" multiple ><br/> Single <input type="file" ng2FileSelect [uploader]="uploader" /> <h3>Upload queue</h3> <p>Queue length: {{ uploader?.queue?.length }}</p> <table class="table"> <thead> <tr> <th width="30%">Name</th> <th width="5%">Size</th> <th width="20%">Progress</th> <th width="20%">Status</th> <th width="25%">Actions</th> </tr> </thead> <tbody> <tr *ngFor="let item of uploader.queue"> <td><strong>{{ item?.file?.name }}</strong></td> <td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td> <td *ngIf="uploader.isHTML5"> <div [ngStyle]="{ 'width': item.progress + '%' }"></div> </td> <td> <span *ngIf="item.isSuccess">OK</span> <span *ngIf="item.isCancel">Cancel</span> <span *ngIf="item.isError">Error</span> </td> <td> <button type="button" (click)="item.upload()" [disabled]="item.isReady || item.isUploading || item.isSuccess"> Upload </button> <button type="button" (click)="item.cancel()" [disabled]="!item.isUploading"> Cancel </button> <button type="button" (click)="item.remove()"> Remove </button> </td> </tr> </tbody> </table> <div> Queue progress: <div [ngStyle]="{ 'width': uploader.progress + '%' }"></div> <button type="button" (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length"> Upload all </button> <button type="button" (click)="uploader.cancelAll()" [disabled]="!uploader.isUploading"> Cancel all </button> <button type="button" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length"> Remove all </button> </div></div>
这个文件增加了65行,稍微复杂了一点,不过提供了单文件上传,多文件上传,文件队列管理,上传取消等很多功能,甚至还有根据文件的不同状态去设置按钮的状态。我觉得这里面充分体现了Angular2组件模型的威力。其中最关键的代码是Multiple和Single下面的input标签,将选择的文件跟uploader绑定了起来。之后就是利用uploader组件的功能了。编译打包
使用下面的命令就可以产生编译打包好的前端:
ng build这样生成的是开发环境的包。参数--proc可以生成生产环境的包。运行该命令之后,会在uploader-client目录下面生成一个dist目录,里面有index.html,以及inline.js,main.bundle.js和styles.bundle.js。这就是前端需要的所以文件了。将这些生成的文件(还有.map文件帮助调试)一起拷贝到下面要讲到的uploader-server/src/main/resources/static下面。或者可以修改uploader-client/angular-cli.json,将dist改为该目录的相对路径。这样ng build之后就不需要拷贝了。
建立Spring Boot项目
还是去http://start.spring.io/,创建一个项目模板,在Dependencies中增加Web和Configuration Processor。之后拷贝Spring官方的文件上传示例:https://spring.io/guides/gs/uploading-files/,将示例里面所有java文件拷贝过来。修改其中的一个文件:
package com.shdanyan;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.http.HttpHeaders;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.shdanyan.storage.StorageFileNotFoundException;import com.shdanyan.storage.StorageService;@Controllerpublic class FileUploadController { private final StorageService storageService; @Autowired public FileUploadController(StorageService storageService) { this.storageService = storageService; } /* * @GetMapping("/") public String listUploadedFiles(Model model) throws * IOException { * * model.addAttribute("files", storageService .loadAll() .map(path -> * MvcUriComponentsBuilder .fromMethodName(FileUploadController.class, * "serveFile", path.getFileName().toString()) .build().toString()) * .collect(Collectors.toList())); * * return "uploadForm"; } */ @GetMapping("/") public String index() { return "forward:index.html"; } @GetMapping("/files/{filename:.+}") @ResponseBody public ResponseEntity<Resource> serveFile(@PathVariable String filename) { Resource file = storageService.loadAsResource(filename); return ResponseEntity .ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"") .body(file); } @PostMapping("/") public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { storageService.store(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!"); return "redirect:/"; } @ExceptionHandler(StorageFileNotFoundException.class) public ResponseEntity<?> handleStorageFileNotFound( StorageFileNotFoundException exc) { return ResponseEntity.notFound().build(); }}
修改的页面用绿底色显示出来,即将原来的页面替换成了我们的Angular2的页面,总共是3行代码。这样一个完整的上传功能就实现了。上传的关键代码是Controller里面响应POST请求的方法handleFileUpload。用spring-boot:run就可以运行了,然后在浏览器中打开链接http://localhost:8080就可以看到上传的网页了。总结:
我们用100行不到的代码,就实现了功能完善的文件上传功能。完整的代码可以在这里下载:https://github.com/cuiwader/file-uploader。那么您是否认同Spring Boot和Angular2的强大功能呢?欢迎留言。另外里面的一个技术细节,ng2-file-upload使用了HTML5的一些新特性,通过XMLHttpRequest(XHR)API完成了文件上传和进度查询功能。从它源代码里面的这一行也可以看出,它似乎还能工作在不支持HTML5的浏览器中,我没有测试过。
let transport = this.options.isHTML5 ? '_xhrTransport' : '_iframeTransport';在上传文件的时候,可以看到HTTP请求包含了这个头:Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryQ8K9wTfL0BIB6BTG。后面的boundary是分隔。在其后的Request Payload里面,可以看到该分隔被使用:
------WebKitFormBoundaryQ8K9wTfL0BIB6BTGContent-Disposition: form-data; name="file"; filename="a.pptx"Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation------WebKitFormBoundaryQ8K9wTfL0BIB6BTG--第一个分隔Content-Type表明传送的是一个office的PPT文件。第二个分隔后面就是文件的内容,但是没有显示出来。我猜测应该是用二进制传输的,multipart/form-data是支持二进制传输的,如果转换为base64,则会有一个Content-Transfer-Encoding指明用了base64编码,现在没有指明。另外Content-Type实际上指明了这是一个二进制文件,所以是直接二进制传输的。同时我们还可以看到,不同的分隔还有CR+LF。
2 1
- 用Spring Boot & Angular2快速开发文件上传服务
- 使用Spring Boot搭建文件上传服务
- Spring Boot Web应用开发 文件上传
- Spring boot 文件上传
- spring boot 文件上传
- Spring-boot 文件上传
- Spring Boot 文件上传
- spring-boot 文件上传
- Spring boot快速开发
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 实现RESTful CRUD
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加代理服务器
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - AngularJS2客户端
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加权限控制
- Spring Boot基础教程12-web应用开发-文件上传
- Spring boot 文件上传(多文件上传)
- spring boot文件上传【多文件上传】
- spring boot文件上传、下载
- 使用spring boot 上传文件
- SpringMVC的几种返回方式
- Erlang crash_dump文件查看
- 第十一周—C语言 oj上机题目(输出空心三角形)(函数的调用)
- 第十一周 OJ 星座问题
- Java四种线程池的使用
- 用Spring Boot & Angular2快速开发文件上传服务
- androidSwipeLayout简单用法,仿qq会话列表listview左右滑动
- java外部类与内部类的关系
- 【Day47】有关数据库的知识点总结
- Android官方开发文档Training系列课程中文版:Activity测试之创建单元测试
- 默认浏览器打开指定Url
- osg三角带绘制
- Fibonacci数列 知识点梳理
- define和typedef