2021-10-30

websocket整合springboot

1、开启WebSocket支持

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket支持
 * @author zhengkai.blog.csdn.net
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.concurrent.atomic.AtomicInteger;

/**
 * @Author:JCccc
 * @Description:
 * @Date: created in 15:56 2019/5/13
 */
@Component
@ServerEndpoint(value = "/websocket/{userId}")
public class WebSocket {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 在线人数
     */
    private AtomicInteger onlineNumber = new AtomicInteger(0);
    /**
     * 会话
     */
    private Session session;
    /**
     * 用户
     */
    private String userID;
    /**
     * 建立连接
     *
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
      //把会话存到连接池中
      this.session=session;
      this.userID=userId;
      onlineNumber.incrementAndGet();
      System.out.println("有新连接加入!当前在线人数为" + onlineNumber.get() +" 当前session是" + session.hashCode()+" 用户id为: "+userId);
      SessionPool.sessions.put(userId,session);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("服务端发生了错误"+error.getMessage());
        error.printStackTrace();
    }
    /**
     * 连接关闭
     */
    @OnClose
    public void onClose(Session session) throws IOException {
        SessionPool.close(session.getId());
        session.close();
        System.out.println("websocket关闭成功!");
    }

    /*
    * 收到客户端消息后调用的方法
    * */
    @OnMessage
    public void onMessage(String message, Session session){
       try {
           if(StringUtils.isNotBlank(message)){
               //解析为JSON文件防止有个篡改
               System.out.println(message);
               /*JSONObject jsonObject = JSON.parseObject(message);
               //追加发送人(防止串改)
               jsonObject.put("senderId",this.userID);
               //抽离接收人
               String recipient=jsonObject.getString("receptionPerson");
               SessionPool.sendMessage(this.userID,jsonObject.toJSONString());
               if(StringUtils.isNotBlank(recipient)&&SessionPool.sessions.containsKey(recipient)){
                   if(jsonObject.get("code").equals(1)){

                   }else {

                   };
                   */
                 SessionPool.sendMessage("小和尚",message);
               }else {
                   logger.info("--用户不在线");
               }
       }catch (Exception e){
           e.printStackTrace();
       }
    }
}
import org.springframework.stereotype.Component;

import javax.websocket.Session;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SessionPool {

    /*以用户的姓名为key,WebSocket为对象保存起来*/
    public static Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

    /*关闭连接 判断session是否为空,如果不是空的那就把他给关闭了*/
    public static void close(String sessionId) throws IOException{
        for (String userID: sessions.keySet()) {
            Session session= sessions.get(userID);
            if(session.getId().equals(sessionId)){
                sessions.remove(userID);
                System.out.println(userID+"用户: "+LocalDate.now()+"  退出");
                break;
            }
        }
    }

    /*发送消息 查询找到用户然后同步发送消息*/
    public static void sendMessage(String userId,String message){
        sessions.get(userId).getAsyncRemote().sendText(message);
    }

    /*循环在线的每一个用户给他们发送消息*/
    public static void sendMessage(String message){
        for (String sessionId:SessionPool.sessions.keySet()){
            /*循环key发送消息*/
            SessionPool.sessions.get(sessionId).getAsyncRemote().sendText(message);
        }
    }
}

uve前台监听

    var websock = null;
	var timer = null;
	var callableMsg = null;
	
	/**
	 * 初始化websocket连接
	 */ 
	function initWebSocket(e){ //初始化weosocket
	   const wsuri = "ws://127.0.0.1:8022/websocket/"+e;       
	   websock = new WebSocket(wsuri);        
	   websock.onmessage = websocketonmessage;    
	   websock.onopen = websocketonopen;     
	   websock.onerror = websocketonerror;     
	   websock.onclose = websocketclose;
	 }
	
	/**
	 * websocket连接成功以后
	 */  
    let websocketonopen = ()=>{
		let that = this;
        websock.send("websocket连接成功!");
         //连接后,定时发送,否则不段时间不通信会自动断连(时间长短一般是服务端指定的)
        timer = setInterval(function () {
			console.log("定时任务")
			websock.send("websocket连接成功!")
        }, 4000);
    }
	
	
	/**
	 * wobsocket连接错误
	 */  
    let websocketonerror = ()=>{//连接建立失败重连
        this.initWebSocket();
    }
	
	/**
	 * websocket监听数据
	 */  
    let websocketonmessage = (e)=>{ //数据接收
        window.dispatchEvent(new CustomEvent('onmessageWS', {
            detail: {
                data: e.data
            }
        }));
    }
	
	/**
	 * websocket发送数据
	 */  
    function socketsend(e){//数据发送
        websock.send(e);
    }
	
	/**
	 * 关闭websocket连接
	 */
    let websocketclose = (e)=>{  //关闭
	    clearInterval(timer);
		websock.close();
        console.log('websocket连接断开'+e);
    }

// 导出
export { initWebSocket, socketsend, websocketclose, websocketonmessage}
<template>
   <div class="loginTop">
     <div class="log">
        <div class="logStyle">

        </div>
        <div class="shopName">
          上海身腾电商管理系统
        </div>
     </div>
     <div class="login">
        <div class="login_info" v-if="status">
          <div class="scan-code">
            <div class="scan" @click="sanCode">
              <div class="code">
                <div class="svgStyle">
                  <i class="el-icon-thumb"></i>
                </div>
                <div class="codeStyle">
                  扫码登录
                </div>
              </div>
            </div>
          </div>
          <div class="loginPass">
            <el-form :model="ruleForm" :rules="rules" ref="ruleForms" size="small" label-width="120px" class="demo-ruleForm">
              <el-form-item>
                <div class="passStyle">
                  密码登录
                </div>
              </el-form-item>
              <el-form-item label="用户名: " prop="name">
                <el-input v-model="ruleForm.name" prefix-icon="el-icon-user-solid"></el-input>
              </el-form-item>
              <el-form-item label="密码: " prop="region">
                <el-input type="password" v-model="ruleForm.region" prefix-icon="el-icon-key"></el-input>
              </el-form-item>
              <el-form-item>
                <div class="login-btn" @click="loginBtn">
                  登录
                </div>
                <div class="opera" style="text-align: right">
                  <spa class="operation" @click="resetForm">
                    忘记密码
                  </spa>
                  <span class="operation" @click="forgotPass">
                        忘记登录名
                  </span>
                </div>
              </el-form-item>
            </el-form>
          </div>
        </div>
       <div class="scan_codes" v-else>
         <div class="scan-code">
           <div class="scan" @click="sanCode">
             <div class="code">
               <div class="svgStyle">
                 <i class="el-icon-thumb"></i>
               </div>
               <div class="codeStyle">
                 密码登录
               </div>
             </div>
           </div>
         </div>
         <div class="loginPass">
           <el-form label-width="105px" class="demo-ruleForm">
             <el-form-item>
               <div class="passStyle">
                 请登录升腾小程序 扫描二维码登录
               </div>
             </el-form-item>
             <el-form-item>
               <div class="login-btn">
                 <div class="codes" @click="flushCodeImg">
                   <img class="imageStyle" :src="imageRul">
                 </div>
               </div>
             </el-form-item>
           </el-form>
         </div>
       </div>
     </div>
   </div>
</template>

<script>
import { useRouter } from 'vue-router'
import { reactive, ref, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import network from "../network/index.js"
import { initWebSocket, websocketsend, websocketclose, websocketonmessage } from "../utils/websocket.js";
//注:别忘了引入axios
  export default{
    setup(){
      /*存储用户名密码等数据*/
      const ruleForm = reactive({
          name: '',
          region: ''
      })
	  let imageRul = ref()
      const ruleForms = ref()
      const router = useRouter()
      //校验用户名和密码事件 from表单校验事件
      const rules = {
        name:[
          {required: true, message: '请输入用户名', trigger: 'blur'},
        ],
        region: [
          { required: true, message: '请输入密码', trigger: 'blur' }
        ]
      }
	  
	  //刷新二维码
	  const flushCodeImg = () =>{
		let xhr = new XMLHttpRequest()
		     xhr.open('GET', "http://localhost:8022/user/createCodeImg", true)
		     xhr.responseType = 'blob' // 关键的一步
		     xhr.onreadystatechange = function() {
							 let uuid = xhr.getResponseHeader('uuid');
		       if (xhr.readyState == 4) {
		         if (xhr.status == 200) {
						let blob = this.response
						// 将blob转化为base64形式
						let reader = new FileReader()
						reader.readAsDataURL(blob)
						reader.onloadend = function() {
						let base64data = reader.result // 这里base64data就是请求到的图片的base64码
						imageRul.value = base64data
						initWebSocket(uuid);
		           }
		         }
		       }
		     }
		xhr.send()  
	  }
	  
      //校验用户点击登录状态 切换二维码登录和密码登录
      let status = ref('true')
	
      //用户点击切换按钮事件
      const sanCode = () =>{
		  if(status.value){
			  let xhr = new XMLHttpRequest()
			       xhr.open('GET', "http://localhost:8022/user/createCodeImg", true)
			       xhr.responseType = 'blob' // 关键的一步
			       xhr.onreadystatechange = function() {
					 let uuid = xhr.getResponseHeader('uuid');
			         if (xhr.readyState == 4) {
			           if (xhr.status == 200) {
							 let blob = this.response
							 // 将blob转化为base64形式
							 let reader = new FileReader()
							 reader.readAsDataURL(blob)
							 reader.onloadend = function() {
							 let base64data = reader.result // 这里base64data就是请求到的图片的base64码
							 imageRul.value = base64data
							 initWebSocket(uuid);
			             }
			           }
			         }
			       }
			  xhr.send()
		  }
		  if(status.value == false){
			  console.log("关闭")
			  websocketclose();
		  }
         status.value = !status.value
      }

      //表单清空事件 忘记密码
      const resetForm = () => {
         // ruleForms.value.resetFields()
        router.push({
          path: '/discover'
        })
      }
	  
	  const forgotPass = () =>{
		router.push({
		  path: '/forgotPass'
		})  
	  }
	  
      //登录按钮事件
      const loginBtn = async() =>{
         /*
         * 校验
         * */
        ruleForms.value.validate((valid) => {
           if(valid){
             const { name,region} = ruleForm
             // eslint-disable-next-line no-unused-vars
             let params={
               username: name,
               password: region
             }
		    network.login(params).then((res) =>{
				if(res.data.resultCode == 40001){
					console.log(res.data.desc)
					ElMessage({
					   showClose: true,
					   type: 'error',
					   message: res.data.desc
					 })
					 return
				}
				if(res.data.resultCode == 10000){
					localStorage.setItem("token",res.data.data) //客户端存储token
					router.push({
					  name: 'menuIndex'  //跳转至主页面
					}) 
					ElMessage({
					   showClose: true,
					   type: 'success',
					   message: '登录成功'
					 })
					return
				}
			})
           }else{
             ElMessage({
               showClose: true,
               type: 'error',
               message: '请输入用户名或密码'
             })
             return;
           }
         })
      }
	  
	  // 创建接收消息函数
	  const getSocketData = e => {
	    const data = e && e.detail.data
	    //这边编写处理服务端消息代码
		console.log("接收消息: "+data)
	  } 
	  //注册监听事件
	  window.addEventListener('onmessageWS', getSocketData)
	  
      return{
        ruleForm,
        sanCode,
        status,
        loginBtn,
        ruleForms,
        rules,
        resetForm,
		forgotPass,
		imageRul,
		flushCodeImg
      }
    }
  }


</script>

<style lang="less" scoped>
::v-deep(.login .login_info .loginPass .el-form .el-form-item .el-form-item__content .el-input .el-input__prefix){
	line-height: 47px !important;
}
.loginTop {
  width: 100%;
  height: 100%;
  background-size: 100% 100%;
  background-image: url(../assets/static/jhk-1634365898144.jpg);
  position: relative;
  .log{
    width: 100%;
    height: 90px;
    display: flex;
    background-color: #53c68c;
    text-indent:25px;
    .logStyle{
      width: 80px;
      height: 80px;
      padding-top: 5px;
      border-radius: 50%;
      img{
        width: 80px;
        height: 80px;
        border-radius: 50%;
      }
    }
    .shopName{
      height: 400px;
      line-height: 90px;
      padding-left: 15px;
      letter-spacing: 5px;
      color: black;
      font-size: 26px;
    }
  }
  .login{
      width: 670px;
      height: 480px;
      position: absolute;
      left: 54%;
      top: 38%;
      background-color: #ffffff;
      box-shadow: 0 0 50px rgb(228, 231, 231);
    .scan_codes{
      width: 100%;
      height: 100%;
      .scan-code {
        width: 100%;
        height: 66px;
        position: relative;
        .scan {
          width: 148px;
          height: 18px;
          position: absolute;
          right: 2px;
          top: 32px;
          .code {
            width: 100%;
            height: 100%;
            cursor: pointer;
            .svgStyle {
              width: 21px;
              height: 18px;
              float: left;
            }
            .codeStyle {
              width: 120px;
              height: 18px;
              height: 18px;
              float: left;
            }
          }
        }
      }
      .loginPass{
        ::v-deep(.el-input__inner){
          height: 48px;
        }
        ::v-deep(.el-form-item){
          margin-top: 35px;
          width: 580px;
        }
        ::v-deep(.el-form-item .passStyle){
          cursor: default;
          border-bottom: 1px solid #e7e4e6;
          font-size: 15px;
        }
        ::v-deep(.el-form-item .login-btn){
          height: 100%;
          width: 100%;
        }
        ::v-deep(.el-form-item .login-btn .codes){
          height: 220px;
          width: 230px;
          margin: 0px auto;
          cursor: pointer;
        }
        ::v-deep(.el-form-item .login-btn .codes .imageStyle){
           height: 100%;
           width: 100%;
        }
	
      }
    }
    .login_info{
        width: 100%;
        height: 100%;
        .scan-code{
          width: 100%;
          height: 66px;
          position: relative;
          .scan{
            width: 148px;
            height: 18px;
            position: absolute;
            right: 2px;
            top: 32px;
            .code{
              width: 100%;
              height: 100%;
              cursor: pointer;
              .svgStyle{
                width: 21px;
                height: 18px;
                float: left;
              }
              .codeStyle{
                width: 120px;
                height: 18px;
                height: 18px;
                float: left;
              }
            }
          }
        }
        .loginPass{
          ::v-deep(.el-form){
            margin-top: 0px;
          }

          ::v-deep(.el-input__inner){
            height: 48px;
          }
          ::v-deep(.el-form-item){
            margin-top: 35px;
            width: 580px;
          }
          ::v-deep(.el-form-item .passStyle){
            cursor: default;
            border-bottom: 1px solid #e7e4e6;
            font-size: 15px;
          }
          ::v-deep(.el-form-item .login-btn){
            height: 48px;
            background-color: #42b983;
            line-height: 48px;
            font-size: 15px;
            text-align:center;
            cursor: pointer;
            letter-spacing: 3px;
          }
          ::v-deep(.el-form-item .opera .operation){
            margin-left: 23px;
            color: #b3b3b3;
            font-size: 0.6em;
            cursor: default;
          }
          ::v-deep(.el-form-item__label){
            line-height: 48px;
          }
        }
      }
  }
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pursue?????

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值