SpringBoot扫码上传文件
# 手机扫码上传文件并实时刷新列表(SpringBoot+WebSocket)
# 流程
- 前端将编写好的上传文件的页面地址生成二维码
- 用户手机扫码,访问那个页面,进行文件上传。(测试时手机和电脑连一个Wifi哈)
- 上传文件成功后,上传文件接口肯定有返回数据,我们携带返回数据调用后台websocket接口
- 后台websocket接口会去推送内容至前端
- 至此功能完成
如果你的需求仅仅是后端推送到前端,前端请求的频率远没有后端推送的频率高, 那么你可以选用 SSE ( Server-sent Events )使用 HTTP 协议,进行替换WebSocket。
简单说两句SSE:
SSE 是单向通道,只能服务器向客户端发送消息,如果客户端需要向服务器发送消息,则需要一个新的 HTTP 请求。
详细说明见这里 (opens new window)
# 代码实现
一共两个html页面,注意替换其中的 IP
先看一下目录结构:
# 前端页面
# showCodePage.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>生产二维码,等待后台websockect推送</title>
</head>
<body>
<h1>二维码在这里展示</h1>
<div id="tag1"></div>
<h1 id="tag2">手机扫码上传文件成功后(文件名+id)会实时由后端推送到这里显示!</h1>
</body>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js" type="text/javascript"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/utf8/3.0.0/utf8.js"></script>
<script type="text/javascript">
function init() {
//Article-content 为显示二维码的div id
$("#tag1").qrcode({
render : "canvas", //设置渲染方式,有table和canvas,使用canvas方式渲染性能相对来说比较好
text: "http://192.168.0.109:8081/index", //扫描二维码后显示的内容,可以直接填一个网址,扫描二维码后自动跳向该链接
width : "200", //二维码的宽度
height : "200", //二维码的高度
background : "#ffffff", //二维码的后景色
foreground : "#000000", //二维码的前景色
});
}
init();
</script>
<script type="text/javascript">
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket('ws://192.168.0.109:8081/webSocket');
} else {
alert('该浏览器不支持websocket!');
}
websocket.onopen = function (event) {
console.log('建立连接');
}
websocket.onclose = function (event) {
console.log('连接关闭');
}
websocket.onmessage = function (event) {
console.log('收到消息:' + event.data)
document.getElementById("tag2").innerHTML = event.data;
}
websocket.onerror = function () {
alert('websocket通信发生错误!');
}
window.onbeforeunload = function () {
websocket.close();
}
</script>
</html>
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
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
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文件上传的页面</title>
<!-- cdn引入ElementUI样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-upload
class="upload-demo"
drag
action="http://192.168.0.109:8998/file/uploadFile"
multiple
:on-success="uploadSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">文件上传接口,用的是file项目接口,启动一下即可</div>
</el-upload>
</div>
</body>
<!--cdn引入ElementUI组件必须先引入Vue-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- cdn引入ElementUI组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
const vm = new Vue({ // 配置对象 options
// 配置选项(option)
el: '#app', // element: 指定用vue来管理页面中的哪个标签区域
data: {
msg: ''
},
methods: {
uploadSuccess(response, file, fileList) {
var url = 'http://192.168.0.109:8081/WebSocketMsg/' + response[0].name +'----'+ response[0].id;
// 成功后调用websocket接口 通知前端刷新数据
axios
.get(url, {
params: {}
})
.then(function (response) {
console.log("调用通知前端接口成功!!!");
})
.catch(function (error) {
console.log("调用通知前端接口失败!!!");
});
}
}
})
</script>
</html>
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
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
# 后端接口
后端只要是一个上传文件的接口就行,重点不在这里,随便一个上传的例子:
/**
* 读取excel
*/
@PostMapping("/readExcel")
public String readExcel(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), ReadTargetColumnEntity.class, new TargetColumnListener(fileService))
.sheet()
.doRead();
return "success";
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
下面给出上图中的代码
# pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kusch</groupId>
<artifactId>ares-springboot-websocket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ares-springboot-websocket</name>
<description>ares-springboot-websocket</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
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
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
# application.properties
server.port=8081
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
1
2
3
4
2
3
4
# controller
@Controller
public class WebSocketController {
@Autowired
private WebSocketInfo WebSocket;
@RequestMapping("/")
public String showCodePage() {
//WebSocket
return "showCodePage";
}
@RequestMapping("/index")
public String index() {
//WebSocket
return "index";
}
//WebSocket通知页面测试
@RequestMapping("/WebSocketMsg/{info}")
@ResponseBody
public void product(@PathVariable(name = "info") String info) {
//WebSocket
WebSocket.sendMessage("本次websocket推送前端的内容为:" + info);
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# WebSocketInfo
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
@ServerEndpoint("/webSocket")
@Slf4j
public class WebSocketInfo {
private Session session;
private static CopyOnWriteArraySet<WebSocketInfo> webSocketSet = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this);
log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());
}
@OnClose
public void onClose() {
webSocketSet.remove(this);
log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
}
@OnMessage
public void onMessage(String message) {
log.info("【websocket消息】收到客户端发来的消息:{}", message);
}
public void sendMessage(String message) {
for (WebSocketInfo webSocket : webSocketSet) {
log.info("【websocket消息】广播消息, message={}", message);
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
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
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
# WebSocketStompConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@EnableWebSocket
@Configuration
public class WebSocketStompConfig {
//这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
编辑 (opens new window)
上次更新: 2023/05/28, 08:23:00