angular与springboot实现文件的上传以及照片回显
近期进入公司,开始接触angular,并要求使用angular+springboot做一个小例子,其中涉及到了照片上传这方面的知识,做出来以后记录一下踩过的坑,希望之后再做这类功能的时候不要再犯。
文件上传
从前端开始说起,我先把代码贴上,这是文件上传组件的html界面,angular的构造我就不写了,自己看一下官方文档应该就都能明白。
可以看到ngmodel双向绑定的属性是from?.name,那么这里为什么要加这个?呢
?.是angular模板中的安全属性操作符语法,属于angular模板特有语法
a?.b表示当a存在时(不为null或undefined),取a.b的值,否则置空;以避免出现a未赋值时直接报错 详见官方文档
The safe navigation operator ( ?. ) and null property paths
add.component.html
<div class="container" style="width: 30%;margin-left: 35%">
<h3 class="text-center">新增页面</h3>
<br/>
<form method="post" (ngSubmit)="onSubmit(regForm.value)" #regForm="ngForm">
<div class="form-group" >
<label for="name">姓名</label>
<input type="text" class="form-control" name="name" (ngModel)="from?.name" placeholder="请输入姓名">
</div>
<div class="form-group" >
<label for="name">性别</label><br/>
<input type="radio" class="" name="sex" (ngModel)="from?.sex" value="男"/>男
<input type="radio" class="" name="sex" (ngModel)="from?.sex" value="女"/>女
</div>
<div class="form-group" >
<label for="name">出生日期</label>
<input class="form-control" type="text" id="date" name="date" autocomplete="off" (ngModel)="from?.date" placeholder="请选择出生日期"/>
</div>
<div class="form-group" >
<label for="name">手机号</label>
<input class="form-control" type="text" name="phonenum" (ngModel)="from?.phonenum" placeholder="请输入手机号"/>
</div>
<div class="form-group" >
<label for="name">地址</label>
<input class="form-control" type="text" name="local" (ngModel)="from?.local" placeholder="请输入地址"/>
</div>
<div class="form-group">
<label for="inputfile">照片</label><br/>
<img height="100px" width="200px" [src]="_d.bypassSecurityTrustUrl(imgsrc)"/><br/>
<br/>
<input type="file" name="photo" id="photo" (change)="fileChange($event)" (ngModel)="from?.photo" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block btn-sm" style="width:100px">提交</button>
</div>
</form>
</div>
这里我是通过angular的form表单提交的文件,以及除了文件之外的一些参数,比如手机号、姓名还有性别啥的,我把代码改的尽量简单,看一下ts文件中是怎么接收的。
add.comentpont.ts
import { Component, OnInit } from '@angular/core';
import { ListService } from '../list.service'
import { DomSanitizer } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
declare let laydate;
@Component({
selector: 'app-add',
templateUrl: './add.component.html',
styleUrls: ['./add.component.css']
})
export class AddComponent implements OnInit {
/**声明表单变量 */
from:{
name:String,
sex:String,
date:String,
phonenum:String,
local:String,
photo:File
}
/**设置的图片框默认显示一张图片*/
imgsrc = 'http://localhost:8888/images/20190807152104882.jpg';
date:string;
file:any;
formdate:FormData
constructor(
private listservice:ListService,
private router:Router,
public _d: DomSanitizer,
private location: Location
) { }
ngOnInit() {
/**使用了layui的日期插件*/
laydate.render({
elem:'#date',
theme:'#4DC6FD',
done:(value,date,endDate)=>{
this.date=value;
}
});
}
onSubmit(value):void{
this.formdate=new FormData();
this.formdate.append("name",value.name)
this.formdate.append("sex",value.sex)
this.formdate.append("date",this.date)
this.formdate.append("phonenum",value.phonenum)
this.formdate.append("local",value.local)
this.formdate.append("file",this.file)
this.listservice.onSubmit(this.formdate).subscribe(
//执行成功以后通过路由进行组件跳转
()=>this.router.navigate(['admin/addresslist'])
);
}
//上传文件的input框的监听事件
fileChange(e) {
this.file = e.srcElement.files[0]; // 获取图片这里只操作一张图片
this.imgsrc = window.URL.createObjectURL(this.file); // 获取上传的图片临时路径
}
}
拿到表单的数据之后,把数据全都给append进了一个FormData对象中,一般通过Ajax上传文件的话应该都是通过formdata来传的
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { List } from './List';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ListService {
file = new FormData();
constructor(public http:HttpClient) { }
//将我们的参数以及上传的文件提交给服务器
onSubmit(formdate:any):Observable<{}>{
let api = 'http://localhost:8888/listController/addtest'
//我们知道post方法有三个参数,切记,最后一个参数不要写,空着,angular会自动判断应该使用什么请求头,因为包含文件,规定特定的请求头的话可能会出错,所以索性不要规定
return this.http.post(api,formdate);
}
}
到这里为止,angular做的工作就完成了
springboot接收数据
ListController.java
@Controller
@CrossOrigin
@RequestMapping("/listController")
public class ListController {
@Autowired
private ListService listService;
/**
* 新建页面添加数据
* 使用MultipartFile接口接收前台传的file(文件),其他的参数用实体类接收就可以了
*/
@PostMapping("/addtest")
@ResponseBody
public int addtest(@RequestParam("file") MultipartFile file, Formlist formlist) throws IOException{
if(file.isEmpty()){
System.out.println("file为空");
}
//使用时间给上传的文件命名,这种方式没有用uuid命名好,因为同一时间有可能会上传多个文件
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS");
String res = sdf.format(new Date());
String originaFilename = file.getOriginalFilename();
//获取文件的后缀名
String newFileName = res+originaFilename.substring(originaFilename.lastIndexOf("."));
String rootPath = "/images/";
File newFile = new File(rootPath+newFileName);
System.out.println(rootPath+newFileName);
//定义向数据库中存取的文件路径
String src=rootPath+newFileName;
if(!newFile.getParentFile().exists()){
newFile.getParentFile().mkdirs();
}else{
System.out.println(newFile.getParentFile());
}
if(!newFile.exists()){
//使用transferTo()方法将文件存到所在服务器上
file.transferTo(newFile);
}
return listService.add(src,formlist);
}
}
这里我们还需要配置两个文件
application.java 我们的启动文件中配置文件存放的路径
@SpringBootApplication
@EnableScheduling
@MapperScan("MpTest.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
MultipartConfigElement multipartConfigElement(){
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("E:/gitprogram/MP/src/main/resources/static");
return factory.createMultipartConfig();
}
}
UploadConfiguration.java
重写addResourceHandlers方法,设置照片回显时的虚拟路径,这样我们在前台查看我们的照片或者文件的时候只需要使用http://IP:port/‘数据库中取到的路径’ 就可以访问了
@Configuration
public class UploadConfiguration extends WebMvcConfigurationSupport {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/images/**")
.addResourceLocations("file:E:/gitprogram/MP/src/main/resources/static/images/");
}
}
后边的代码就是将我们获取的这些数据存在数据库中了,因为我用的mp就不贴出来了,看一下前台获取数据时的代码吧。
<div class="col-xs-2 col-sm-2 text-center center-vertical"><img *ngIf="item.photo" height="50px" width="100px" src="http://127.0.0.1:8888/{{item.photo}}"></div>