1.使用vue-cli创建前端项目
运用vue-cli工具可以很轻松地构建前端项目,当然,使用webstorm来构建会更加简洁(如图)。本文推荐使用webstorm,因为在后续开发中,ide会使我们的开发更加简洁。部分配置如图:
2.navbar编写
作为一个webapp,navbar作为应用的导航栏是必不可少的。在本项目中,笔者引入了bootstrap对navbar进行了轻松地构建。在vue中我们需要在components文件夹中将我们的组件加进去,对于本工程来说,navbar是我们要加入的第一个组件,他独立于router之外,一直固定在网页上方。
2.1 首先,我们使用npm来安装vue,vue-cli,bootstrap
1
2
3
|
npm install vue
npm install -g vue-cli
npm install --save bootstrap jquery popper.js
|
2.2 接下来我们在components目录下new一个vue组件,并且在main.js中引入bootstrap依赖:
1
2
|
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min'
|
2.3 下面就可以开始写代码了,由于本文只关注table相关的功能,所以导航栏中除了script意外的元素都已经disable,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<template>
<nav class = "navbar navbar-expand-lg navbar-dark bg-dark" >
<span class = "navbar-brand mb-0 h1" >vue-springboot</span>
<button class = "navbar-toggler" type= "button" data-toggle= "collapse" data-target= "#navbarnav" aria-controls= "navbarnav" aria-expanded= "false" aria-label= "toggle navigation" >
<span class = "navbar-toggler-icon" ></span>
</button>
<div class = "collapse navbar-collapse" id= "navbarnav" >
<ul class = "navbar-nav" >
<li class = "nav-item" >
<router-link class = "nav-link" to= "/home" >home</router-link>
</li>
<li class = "nav-item active" >
<router-link to= "/" class = "nav-link" >script</router-link>
</li>
<li class = "nav-item" >
<router-link to= "/history" class = "nav-link" >history</router-link>
</li>
</ul>
</div>
</nav>
</template>
<script>
export default {
name: "mynavbar"
}
</script>
<style scoped>
</style>
|
2.3 在app.vue中引入mynavbar
3.script table编写
作为自动化工具,必不可少的一部分就是引入script,我们希望用户能够*地使用h5界面进行script的编写,因此在这里使用了vue的数据双向绑定进行table crud。
3.1 新建一个vue组件scripttable,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
<template>
<div class = "container-fluid" id= "scripttable" >
<h3>my script</h3>
<form style= "margin-top: 1rem" >
<input type= "file" @change = "getfile($event)" class = "" multiple/>
<input type= "button" value= "upload" @click = "submit($event)" class = "btn btn-dark" >
</form>
<table class = "table table-hover text-center table-bordered"
style= "word-break: break-all; word-wrap: break-word;margin-top: 1rem;" >
<thead>
<th>#</th>
<th>platform</th>
<th>action</th>
<th>path</th>
<th>value</th>
<th>wait</th>
<th>screenshot</th>
<th>change</th>
</thead>
<tbody>
<tr v-cloak v- for = "(item, index) in steps" >
<th>{{index+ 1 }}</th>
<td>{{item.platform}}</td>
<td>{{item.action}}</td>
<td>{{item.path}}</td>
<td>{{item.value}}</td>
<td>{{item.wait}}</td>
<td>{{item.screenshot}}</td>
<td><a href= "#" v-on:click= "edit(item)" >edit</a> | <a href= "#" v-on:click= 'aaa(index)' >delete</a>
</td>
</tr>
<tr>
<th></th>
<td><select class = "form-control" v-model= "stepstemp.platform" >
<option>web</option>
<option>android</option>
</select></td>
<td><select class = "form-control" v-model= "stepstemp.action" >
<option>click</option>
<option>get</option>
<option>input</option>
<option>swipe</option>
</select></td>
<td><input class = "form-control" v-model= "stepstemp.path" placeholder= "enter the xpath" ></td>
<td><input class = "form-control" v-model= "stepstemp.value" placeholder= "enter the input value" ></td>
<td><input class = "form-control" v-model= "stepstemp.wait" placeholder= "waiting seconds" ></td>
<td><select class = "form-control" v-model= "stepstemp.screenshot" >
<option>yes</option>
<option>no</option>
</select></td>
<td>
<button class = "btn btn-sm btn-dark" v-on:click= 'save' v- if = "isnotedit" >save</button>
<button class = "btn btn-sm btn-primary" v-on:click= 'saveedit' v- else >saveedit</button>
</td>
</tr>
</tbody>
</table>
<hr/>
</div>
</template>
<script>
import vue from 'vue'
import axios from 'axios'
export default {
name: "scripttable" ,
data() {
return ({
steps: [],
stepstemp: {
platform: '' ,
action: '' ,
path: '' ,
value: '' ,
wait: '' ,
screenshot: ''
},
isnotedit: true
});
},
methods: {
save: function () {
this .steps.push( this .stepstemp);
this .stepstemp = {
platform: '' ,
action: '' ,
path: '' ,
value: '' ,
wait: '' ,
screenshot: ''
};
},
aaa: function (index) {
this .steps.splice(index, 1 )
},
edit: function (item) {
this .isnotedit = false ;
this .stepstemp = item;
},
saveedit: function () {
this .isnotedit = true ;
this .stepstemp = {
platform: '' ,
action: '' ,
path: '' ,
value: '' ,
wait: '' ,
screenshot: ''
};
}
}
}
</script>
<style scoped>
</style>
|
3.3 运行dev,打开localhost:8080
npm run dev
前端页面效果如下:
至此,本文相关的纯前端部分完成地差不多了,加上mock的数据后,我们可以开始进行后端的开发了。
4.使用spring initializr创建后端项目
为了更轻松地构建工程,构建restful api以及更轻松地配置请求处理,笔者选择了spring boot作为后端框架。
4.1 首先我们使用idea集成的spring initializr来构建项目,部分配置如图:
4.2 接下来在pom.xml中引入poi依赖,点击import change。如下所示:
1
2
3
4
5
|
<dependency>
<groupid>org.apache.poi</groupid>
<artifactid>poi-ooxml</artifactid>
<version> 4.0 . 0 </version>
</dependency>
|
4.3 接下来我们在application.properties中配置server.port=8088,与前端项目分开
5.pojo类step的编写
下面是对pojo类的编写,本文所需的pojo只有step一种,与前端的table相对应,代码如下:
1
2
3
4
5
6
7
8
9
10
|
import lombok.data;
@data
public class step {
private string platform;
private string action;
private string path;
private string value;
private int wait;
private string screenshot;
}
|
6.uploadcontroller的编写
接下来是对前端post请求的handler(controller)进行编写,我们将上传这个post请求与"/uploadfile"相对应,注意加入@crossorigin注解实现跨域,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package com.daniel.vuespringbootuploadbe;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.crossorigin;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.responsebody;
import org.springframework.web.multipart.multipartfile;
import java.io.file;
import java.io.ioexception;
import java.nio.file.files;
import java.nio.file.path;
import java.nio.file.paths;
import java.util.list;
@controller
@crossorigin
@responsebody
public class uploadcontroller {
private static string uploaded_folder = "src/main/resources/static/temp/" ;
@autowired
private loadservice loadservice;
@postmapping ( "/upload" )
public list<step> singlefileupload(multipartfile file) {
try {
// get the file and save it somewhere
byte [] bytes = file.getbytes();
path path = paths.get(uploaded_folder + file.getoriginalfilename());
files.write(path, bytes);
} catch (ioexception e) {
e.printstacktrace();
}
// print file data to html
list<step> result = loadservice.casttostep( new file(uploaded_folder + file.getoriginalfilename()));
return result;
}
}
|
7.loadservice的编写
下面该编写service来读取请求中传送的文件了,简单地来说只有一个步骤,将excel中的script转换为pojo的链表并在controller中作为responsebody返回.
7.1 首先创建service接口,代码如下:
1
2
3
4
5
6
7
8
|
package com.daniel.vuespringbootuploadbe;
import org.springframework.stereotype.service;
import java.io.file;
import java.util.list;
@service
public interface loadservice {
list<step> casttostep(file file);
}
|
7.2 接下来创建service实现类,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package com.daniel.vuespringbootuploadbe;
import org.apache.poi.openxml4j.exceptions.invalidformatexception;
import org.apache.poi.ss.usermodel.row;
import org.apache.poi.ss.usermodel.sheet;
import org.apache.poi.ss.usermodel.workbook;
import org.apache.poi.xssf.usermodel.xssfworkbook;
import org.springframework.stereotype.service;
import java.io.file;
import java.io.ioexception;
import java.util.arraylist;
import java.util.list;
@service
public class loadserviceimpl implements loadservice {
@override
public list<step> casttostep(file file) {
list<step> steps = new arraylist<>();
workbook workbook = null ;
try {
workbook = new xssfworkbook(file);
} catch (ioexception e) {
e.printstacktrace();
} catch (invalidformatexception e) {
e.printstacktrace();
}
sheet sheet = workbook.getsheetat( 0 );
int num = sheet.getlastrownum() - sheet.getfirstrownum();
//read steps
for ( int i = 0 ; i < num; i++) {
row row = sheet.getrow(i+ 1 );
step step = new step();
step.setplatform(row.getcell( 0 ).getstringcellvalue());
step.setaction(row.getcell( 1 ).getstringcellvalue());
step.setpath(row.getcell( 2 ).getstringcellvalue());
step.setvalue(row.getcell( 3 ).getstringcellvalue());
step.setwait(( int ) row.getcell( 4 ).getnumericcellvalue());
step.setscreenshot(row.getcell( 5 ).getstringcellvalue());
steps.add(step);
}
try {
workbook.close();
} catch (ioexception e) {
e.printstacktrace();
}
return steps;
}
}
|
8.搭建简单的restful api
文章临近尾声,现在前后端的独立代码基本开发完毕,是时候搭建restful了,本文中的api非常简单,就是对上传做出响应,并将返回的json写入界面上的table中,完成script导入,npm安装axios后,在scripttable组件中加入如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
getfile: function (event) {
this .file = event.target.files[ 0 ];
console.log( this .file);
},
submit: function (event) {
event.preventdefault();
let formdata = new formdata();
formdata.append( "file" , this .file);
axios.post( 'http://localhost:8088/upload' , formdata)
.then(function (response) {
for (let i = 0 ; i < response.data.length; i++) {
var tempdata = {
platform: response.data[i].platform,
action: response.data[i].action,
path: response.data[i].path,
value: response.data[i].value,
wait: response.data[i].wait,
screenshot: response.data[i].screenshot
};
this .steps.push(tempdata);
}
}.bind( this ))
. catch (function (error) {
alert( "fail" );
console.log(error);
});
}
|
9.运行服务,编写script并上传
接下来我们创建一个excel,按如图格式编写简单script,运行前后端服务,实现上传:
运行后,excel文件会上传到后端工程的static的temp目录中
总结
以上所述是小编给大家介绍的使用vue+spring boot实现excel上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:https://juejin.im/post/5bff4a1851882516eb5625a1