From 521ba31fa88aaa629fa1b60250921070d18aaf29 Mon Sep 17 00:00:00 2001 From: dyh <2825183872@qq.com> Date: Thu, 18 Aug 2022 00:31:11 +0800 Subject: [PATCH] =?UTF-8?q?version-2.1[=E5=89=8D=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=AE=80=E5=8D=95=E5=8C=B9=E9=85=8D+Jwt?= =?UTF-8?q?=E9=AA=8C=E8=AF=81+websocket=E4=BE=9D=E8=B5=96,=E4=BD=BF?= =?UTF-8?q?=E7=94=A8]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 18 +++ .../kob/backend/config/SecurityConfig.java | 7 + .../kob/backend/config/WebSocketConfig.java | 15 ++ .../kob/backend/consumer/WebSocketServer.java | 134 ++++++++++++++++++ .../com/kob/backend/consumer/utils/Game.java | 98 +++++++++++++ .../consumer/utils/JwtAuthentication.java | 20 +++ web/src/assets/scripts/GameMap.js | 74 ++-------- web/src/components/GameMap.vue | 5 +- web/src/components/MatchGround.vue | 92 ++++++++++++ web/src/components/PlayGround.vue | 4 +- web/src/components/Wechat.vue | 29 ++++ web/src/store/index.js | 3 +- web/src/store/pk.js | 32 +++++ web/src/views/pk/PkIndexView.vue | 58 +++++++- web/src/views/user/account/copy.vue | 54 ++++++- 15 files changed, 570 insertions(+), 73 deletions(-) create mode 100644 backend/src/main/java/com/kob/backend/config/WebSocketConfig.java create mode 100644 backend/src/main/java/com/kob/backend/consumer/WebSocketServer.java create mode 100644 backend/src/main/java/com/kob/backend/consumer/utils/Game.java create mode 100644 backend/src/main/java/com/kob/backend/consumer/utils/JwtAuthentication.java create mode 100644 web/src/components/MatchGround.vue create mode 100644 web/src/components/Wechat.vue create mode 100644 web/src/store/pk.js diff --git a/backend/pom.xml b/backend/pom.xml index 41c755d..7e762de 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -16,6 +16,24 @@ + + + + com.alibaba + fastjson + 2.0.11 + + + + + + org.springframework.boot + spring-boot-starter-websocket + 2.7.2 + + + + io.jsonwebtoken diff --git a/backend/src/main/java/com/kob/backend/config/SecurityConfig.java b/backend/src/main/java/com/kob/backend/config/SecurityConfig.java index acc5287..5ce4c61 100644 --- a/backend/src/main/java/com/kob/backend/config/SecurityConfig.java +++ b/backend/src/main/java/com/kob/backend/config/SecurityConfig.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; @@ -45,4 +46,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } + + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/websocket/**");//放行这一类链接 + } } diff --git a/backend/src/main/java/com/kob/backend/config/WebSocketConfig.java b/backend/src/main/java/com/kob/backend/config/WebSocketConfig.java new file mode 100644 index 0000000..941aeb8 --- /dev/null +++ b/backend/src/main/java/com/kob/backend/config/WebSocketConfig.java @@ -0,0 +1,15 @@ +package com.kob.backend.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + + return new ServerEndpointExporter(); + } +} diff --git a/backend/src/main/java/com/kob/backend/consumer/WebSocketServer.java b/backend/src/main/java/com/kob/backend/consumer/WebSocketServer.java new file mode 100644 index 0000000..cf72ef8 --- /dev/null +++ b/backend/src/main/java/com/kob/backend/consumer/WebSocketServer.java @@ -0,0 +1,134 @@ +package com.kob.backend.consumer; + + +import com.alibaba.fastjson.JSONObject; +import com.kob.backend.consumer.utils.Game; +import com.kob.backend.consumer.utils.JwtAuthentication; +import com.kob.backend.mapper.UserMapper; +import com.kob.backend.pojo.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +@Component +@ServerEndpoint("/websocket/{token}") // 注意不要以'/'结尾 +public class WebSocketServer { + //ConcurrentHashMap 的优势在于兼顾性能和线程安全,一个线程进行写操作时, + //它会锁住一小部分,其他部分的读写不受影响,其他线程访问没上锁的地方不会被阻塞。 + //(userId,WebSocketServer实例:连接) + final private static ConcurrentHashMap users = new ConcurrentHashMap<>(); + //匹配池 + final private static CopyOnWriteArraySet matchpool = new CopyOnWriteArraySet<>(); + //当前用户 + private User user ; + //session维护(存)链接 + private Session session = null ; + //地图 + private Game game ; + //加入数据库 + private static UserMapper userMapper; + @Autowired + public void setUserMapper(UserMapper userMapper){ + WebSocketServer.userMapper = userMapper; + } + + + + @OnOpen + public void onOpen(Session session, @PathParam("token") String token) throws IOException//token是前端url里的参数 + { + // 建立连接 + this.session = session ;//将session存起来--》一个用户一个session + System.out.println("connected!"); + Integer userId = JwtAuthentication.getUserId(token);//获取id + this.user = userMapper.selectById(userId);//获取用户 + + if(this.user != null){//存在用户 加入连接 + users.put(userId,this);//用户链接--》加入到集合中 + } else {//不存在用户 断开连接 + this.session.close(); + } + System.out.println(user); + } + + @OnClose + public void onClose() { + // 关闭链接 + System.out.println("disconnexted!"); + if(this.user != null){ + users.remove(this.user.getId()); + matchpool.remove(this.user); + } + } + //前端点击 开始匹配 触发 + private void startMatching(){ + System.out.println("start matching!"); + matchpool.add(this.user); + + while(matchpool.size() >= 2) { + Iterator it = matchpool.iterator();//迭代器 + User a = it.next(), b = it.next(); + matchpool.remove(a); + matchpool.remove(b); + + Game game =new Game(13,14,20); + game.createMap(); + + JSONObject respA = new JSONObject();//返回给a + respA.put("event", "start-matching"); + respA.put("opponent_username", b.getUsername()); + respA.put("opponent_photo", b.getPhoto()); + respA.put("gamemap", game.getG()); + users.get(a.getId()).sendMessage(respA.toJSONString());//获取a对应的连接,向前端传递信息(String) + + JSONObject respB = new JSONObject();//返回给b + respB.put("event", "start-matching"); + respB.put("opponent_username", a.getUsername()); + respB.put("opponent_photo", a.getPhoto()); + respB.put("gamemap", game.getG()); + users.get(b.getId()).sendMessage(respB.toJSONString());//获取b对应的连接,向前端传递信息(String) + } + } + //前端点击 取消 触发 + private void stopMatching(){ + System.out.println("stop matching!"); + matchpool.remove(this.user); + } + + @OnMessage + public void onMessage(String message, Session session) { + // 接收前端信息 + System.out.println("receive message!"); + JSONObject data = JSONObject.parseObject(message);//解析message + String event = data.getString("event");//类似map + if("start-matching".equals(event)){ + startMatching(); + } else if("stop-matching".equals(event)){ + stopMatching(); + } + } + + @OnError + public void onError(Session session, Throwable error) { + error.printStackTrace(); + } + + //给前端发送信息 + public void sendMessage(String message){ + //由于是异步的,加上同步锁(只有一个线程能执行该块) + synchronized (this.session){ + try{ + //后端向当前链接发送信息 + this.session.getBasicRemote().sendText(message); + }catch(IOException e){ + e.printStackTrace(); + } + } + } +} diff --git a/backend/src/main/java/com/kob/backend/consumer/utils/Game.java b/backend/src/main/java/com/kob/backend/consumer/utils/Game.java new file mode 100644 index 0000000..eff0bd9 --- /dev/null +++ b/backend/src/main/java/com/kob/backend/consumer/utils/Game.java @@ -0,0 +1,98 @@ +package com.kob.backend.consumer.utils; + +import java.util.Random; + +public class Game { + + final private Integer rows; + final private Integer cols; + final private Integer inner_walls_count; + final private int[][] g; + final private static int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1}; + + //构造map规模 + public Game(Integer rows, Integer cols, Integer inner_walls_count) { + this.rows = rows; + this.cols = cols; + this.inner_walls_count = inner_walls_count; + this.g = new int[rows][cols]; + } + + //货物gamemap + public int[][] getG() + { + return g; + } + + //地图是否连通 + private boolean check_connectivity(int sx, int sy, int tx, int ty) + { + if (sx == tx && sy == ty) return true; + g[sx][sy] = 1; + + for (int i = 0; i < 4; i ++ ) { + int x = sx + dx[i], y = sy + dy[i]; + if (x >= 0 && x < this.rows && y >= 0 && y < this.cols && g[x][y] == 0) + { + if (check_connectivity(x, y, tx, ty)) + { + g[sx][sy] = 0; + return true; + } + } + } + + g[sx][sy] = 0; + return false; + } + + + private boolean draw() // 画地图 + { + for (int i = 0; i < this.rows; i ++ ) + { + for (int j = 0; j < this.cols; j ++ ) + { + g[i][j] = 0; + } + } + + //边 + for (int r = 0; r < this.rows; r ++ ) { + g[r][0] = g[r][this.cols - 1] = 1; + } + //边 + for (int c = 0; c < this.cols; c ++ ) { + g[0][c] = g[this.rows - 1][c] = 1; + } + //随机画 + Random random = new Random(); + for (int i = 0; i < this.inner_walls_count / 2; i ++ ) + { + for (int j = 0; j < 1000; j ++ ) + { + int r = random.nextInt(this.rows); + int c = random.nextInt(this.cols); + + if (g[r][c] == 1 || g[this.rows - 1 - r][this.cols - 1 - c] == 1) + continue; + if (r == this.rows - 2 && c == 1 || r == 1 && c == this.cols - 2) + continue; + + g[r][c] = g[this.rows - 1 - r][this.cols - 1 - c] = 1; + break; + } + } + + return check_connectivity(this.rows - 2, 1, 1, this.cols - 2); + } + + + public void createMap() + { + for (int i = 0; i < 1000; i ++ ) + { + if (draw()) break; + } + } +} diff --git a/backend/src/main/java/com/kob/backend/consumer/utils/JwtAuthentication.java b/backend/src/main/java/com/kob/backend/consumer/utils/JwtAuthentication.java new file mode 100644 index 0000000..04ea317 --- /dev/null +++ b/backend/src/main/java/com/kob/backend/consumer/utils/JwtAuthentication.java @@ -0,0 +1,20 @@ +package com.kob.backend.consumer.utils; + +import com.kob.backend.utils.JwtUtil; +import io.jsonwebtoken.Claims; + +public class JwtAuthentication { + //根据token返回userId + public static Integer getUserId(String token)//不用实例访问 + { + int userid = -1; + try { + Claims claims = JwtUtil.parseJWT(token); + userid = Integer.parseInt(claims.getSubject()); + } catch (Exception e) { + throw new RuntimeException(e); + } + return userid; + } + +} diff --git a/web/src/assets/scripts/GameMap.js b/web/src/assets/scripts/GameMap.js index 8354224..ed604fb 100644 --- a/web/src/assets/scripts/GameMap.js +++ b/web/src/assets/scripts/GameMap.js @@ -6,11 +6,13 @@ import { Wall } from "./Wall"; export class GameMap extends AcGameObject { //画布+父元素 - constructor(ctx,parent) + constructor(ctx,parent,store) { super(); this.ctx = ctx;//画布 this.parent = parent;//父元素 + this.store = store;//全局变量(有地图) + this.L = 0;//小正方形的边长 this.rows = 13; @@ -18,7 +20,7 @@ export class GameMap extends AcGameObject this.walls=[]; - this.inner_walls_count = 5; + this.inner_walls_count = 20; this.snakes = [ new Snake({id:0,color:"#4876ED",r:this.rows-2,c:1},this), @@ -28,62 +30,10 @@ export class GameMap extends AcGameObject } - check_connectivity(g,sx,sy,tx,ty) - { - if(sx==tx&&sy==ty)return true; - g[sx][sy]=true; - let dx=[-1,0,1,0],dy=[0,1,0,-1]; - for(let i=0;i<4;i++) - { - let x = sx + dx[i],y = sy + dy[i]; - if(g[x][y]==false && this.check_connectivity(g,x,y,tx,ty))return true; - } - return false; - } - + //创建墙 create_wall(){ - - //初始化【没有墙 false】 - const g=[] - for(let r=0;r{ - new GameMap(canvas.value.getContext('2d'),parent.value); + new GameMap(canvas.value.getContext('2d'),parent.value,store); // console.log(parent.value);//DOM // console.log(canvas.value);//DOM }) diff --git a/web/src/components/MatchGround.vue b/web/src/components/MatchGround.vue new file mode 100644 index 0000000..95454bb --- /dev/null +++ b/web/src/components/MatchGround.vue @@ -0,0 +1,92 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/PlayGround.vue b/web/src/components/PlayGround.vue index 50068a6..3a5d619 100644 --- a/web/src/components/PlayGround.vue +++ b/web/src/components/PlayGround.vue @@ -2,7 +2,6 @@
- @@ -23,5 +22,4 @@ div.playground { /* background-color: lightblue; */ margin: 40px auto; } - \ No newline at end of file diff --git a/web/src/components/Wechat.vue b/web/src/components/Wechat.vue new file mode 100644 index 0000000..3dfe19e --- /dev/null +++ b/web/src/components/Wechat.vue @@ -0,0 +1,29 @@ + + + + + + \ No newline at end of file diff --git a/web/src/store/index.js b/web/src/store/index.js index 736d257..4805897 100644 --- a/web/src/store/index.js +++ b/web/src/store/index.js @@ -1,7 +1,7 @@ //主页面 import { createStore } from 'vuex' import ModuleUser from './user'; - +import ModulePk from './pk'; export default createStore({ state: { }, @@ -13,5 +13,6 @@ export default createStore({ }, modules: { user:ModuleUser, + pk:ModulePk, } }) diff --git a/web/src/store/pk.js b/web/src/store/pk.js new file mode 100644 index 0000000..9f8c524 --- /dev/null +++ b/web/src/store/pk.js @@ -0,0 +1,32 @@ +// import $ from "jquery" + +export default { + state: { + status:"matching",//matching匹配页面 playing对战页面 + socket:null, + opponent_username:"", + opponent_photo:"", + gamemap:null, + }, + getters: { + }, + mutations: { + updateSocket(state,socket){ + state.socket = socket; + }, + updateOpponent(state,opponent){ + state.opponent_username = opponent.username; + state.opponent_photo = opponent.photo; + }, + updateStatus(state,status){ + state.status = status; + }, + updateGamemap(state,gamemap){ + state.gamemap = gamemap ; + } + }, + actions: { + }, + modules: { + } +} diff --git a/web/src/views/pk/PkIndexView.vue b/web/src/views/pk/PkIndexView.vue index 8f4e974..5afc88d 100644 --- a/web/src/views/pk/PkIndexView.vue +++ b/web/src/views/pk/PkIndexView.vue @@ -1,13 +1,69 @@ diff --git a/web/src/views/user/account/copy.vue b/web/src/views/user/account/copy.vue index 8d8142c..aa4179d 100644 --- a/web/src/views/user/account/copy.vue +++ b/web/src/views/user/account/copy.vue @@ -877,4 +877,56 @@ body { background-image: url("@/assets/images/background.png"); background-size: cover; } - \ No newline at end of file + + + + + + + + + + + + + //初始化【没有墙 false】 + const g=[] + for(let r=0;r