后端刷新前端页面-springboot使用sse向vue前端发送数据

适用场景:
后端更新状态通知前端刷新
优点:
简洁轻量,避免了前端需要主动刷新页面才能获取到更新的数据
缺点:
只能传送字符串,只能有后端向前端发送不可逆向
vue部分:

data() {
  return {
    source: null,
    username:Vue.ls.get(USER_NAME)
  };
},
beforeDestroy() {
  //离开页面前关闭sse连接
  this.source.close()
  closeSSE(this.username) //后端关闭连接方法
},
mounted() {
  this.createEventSource()
},
//创建sse连接
methods: {
    createEventSource() {
      let that = this
      if (window.EventSource) {
        this.source = new EventSource('http://localhost:8110/pda/v1/account/sse/connect/' + Vue.ls.get(USER_NAME))
        this.source.addEventListener('open', function (e) {
          console.log('建立连接。。。')
        }, false)   
        this.source.addEventListener('message', function (e) {
          console.log('收到消息', e.data)
          // 具体业务
        })
        this.source.addEventListener('error', function (e) {
          if (e.readyState === EventSource.CLOSED) {
            console.log('连接关闭')
          } else {
            console.log(e)
          }
        }, false)
      } else {
        alert('你的浏览器不支持SSE')
      }
    },
 }

springboot部分:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * 主动向前端推送信息
 */
public class SseEmitterServer {

    private static final Logger logger = LoggerFactory.getLogger(SseEmitterServer.class);

    /**
     * 当前连接数
     */
    private static AtomicInteger count = new AtomicInteger(0);

    /**
     * 使用map对象,便于根据userId来获取对应的SseEmitter,或者放redis里面
     */
    private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();

    /**
     * 创建用户连接并返回 SseEmitter
     * @param employeeCode 用户ID
     * @return SseEmitter
     */
    public static SseEmitter connect(String employeeCode) {
        // 设置超时时间,0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
        SseEmitter sseEmitter = new SseEmitter(0L);
        // 注册回调
        sseEmitter.onCompletion(completionCallBack(employeeCode));
        sseEmitter.onError(errorCallBack(employeeCode));
        sseEmitter.onTimeout(timeoutCallBack(employeeCode));
        sseEmitterMap.put(employeeCode, sseEmitter);
        // 数量+1
        count.getAndIncrement();
        logger.info("创建新的sse连接,当前用户:{}", employeeCode);
        return sseEmitter;
    }

    /**
     * 给指定用户发送信息
     * @param employeeCode
     * @param jsonMsg
     */
    public static void sendMessage(String employeeCode, String jsonMsg) {
        try {
            SseEmitter emitter = sseEmitterMap.get(employeeCode);
            if (emitter == null) {
                logger.warn("sse用户[{}]不在注册表,消息推送失败", employeeCode);
                return;
            }
            emitter.send(jsonMsg, MediaType.APPLICATION_JSON);
        } catch (IOException e) {
            logger.error("sse用户[{}]推送异常:{}", employeeCode, e.getMessage());
            removeUser(employeeCode);
        }
    }

    /**
     * 群发消息
     * @param jsonMsg
     * @param employeeCodes
     */
    public static void batchSendMessage(String jsonMsg, List<String> employeeCodes) {
        employeeCodes.forEach(employeeCode -> sendMessage(jsonMsg, employeeCode));
    }

    /**
     * 群发所有人
     * @param jsonMsg
     */
    public static void batchSendMessage(String jsonMsg) {
        sseEmitterMap.forEach((k, v) -> {
            try {
                v.send(jsonMsg, MediaType.APPLICATION_JSON);
            } catch (IOException e) {
                logger.error("用户[{}]推送异常:{}", k, e.getMessage());
                removeUser(k);
            }
        });
    }

    /**
     * 移除用户连接
     */
    public static void removeUser(String employeeCode) {
        SseEmitter emitter = sseEmitterMap.get(employeeCode);
        if(emitter != null){
            emitter.complete();
        }
        sseEmitterMap.remove(employeeCode);
        // 数量-1
        count.getAndDecrement();
        logger.info("移除sse用户:{}", employeeCode);
    }

    /**
     * 获取当前连接信息
     */
    public static List<String> getIds() {
        return new ArrayList<>(sseEmitterMap.keySet());
    }

    /**
     * 获取当前连接数量
     */
    public static int getUserCount() {
        return count.intValue();
    }

    private static Runnable completionCallBack(String employeeCode) {
        return () -> {
            logger.info("结束sse用户连接:{}", employeeCode);
            removeUser(employeeCode);
        };
    }

    private static Runnable timeoutCallBack(String employeeCode) {
        return () -> {
            logger.info("连接sse用户超时:{}", employeeCode);
            removeUser(employeeCode);
        };
    }

    private static Consumer<Throwable> errorCallBack(String employeeCode) {
        return throwable -> {
            logger.info("sse用户连接异常:{}", employeeCode);
            removeUser(employeeCode);
        };
    }

}

controller

/**
 * 用于创建连接(将用户注册到server中)
 */
@GetMapping("/sse/connect/{userId}")
public SseEmitter connect(@PathVariable String userId) {
   return SseEmitterServer.connect(userId);
}

/**
 * 用于删除连接(将用户从server中移除)
 */
@GetMapping("/sse/closed/{userId}")
public void closed(@PathVariable String userId) {
   SseEmitterServer.removeUser(userId);
}

//业务中调用方法向vue发送数据

SseEmitterServer.batchSendMessage("111");
### 回答1: 外卖项目的前后端分离是指将项目的前端部分和后端部分进行分离开发,前端使用Vue框架,后端使用Spring Boot框架。 前端使用Vue框架可以提供良好的用户界面和交互体验。Vue具有组件化的特点,使得前端开发更加模块化和可维护。同时,Vue的数据绑定和响应式设计可以帮助实现快速更新页面的功能。通过Vue,用户可以方便地浏览外卖项目的菜单、下单、支付等操作,提升用户的使用体验。 后端使用Spring Boot框架可以提供强大的后台支持。Spring Boot是一种轻量级的Java框架,可以快速搭建和部署项目,减少开发的复杂度。使用Spring Boot,开发人员可以方便地实现外卖项目的后台逻辑,例如订单的处理、菜单的管理、支付的接口等。同时,Spring Boot集成了许多常用且可靠的开源库,为项目提供了高效、稳定的基础设施。 前后端分离的优势在于前端后端可以并行开发,提高开发效率。前端后端之间通过定义接口进行通信,降低了耦合度,灵活性更强。同时,单独部署前端后端也可以提高项目的可维护性和可扩展性。例如,当需要添加新的功能或修改现有功能时,只需要修改相应的前端后端代码,而不会影响到整个项目。 总之,外卖项目的前后端分离以及使用VueSpring Boot框架的设计选择,可以帮助实现一个高效、稳定、可扩展的外卖平台。 ### 回答2: 外卖项目采用前后端分离的架构,前端使用Vue框架,后端采用Spring Boot框架。 前端使用Vue框架可以实现用户界面的可视化设计和交互体验。Vue框架具有简单易用、灵活可扩展、高效性能等特点,适用于构建复杂的单页面应用(SPA)。通过Vue框架,可以实现用户注册、登录、浏览菜单、购物车管理、订单处理等功能的前端设计和开发。前端通过调用后端接口,获取后端处理的数据,并将数据展示在用户界面上。 后端使用Spring Boot框架可以实现业务逻辑的处理和数据存储。Spring Boot框架提供了快速构建、简化配置和集成多种功能的特性,适用于快速开发和维护可靠的应用程序。通过Spring Boot框架,可以处理用户注册、登录验证、菜单管理、订单处理等业务逻辑,并与数据库进行交互,存储与外卖项目相关的数据。后端还需要提供RESTful接口,供前端调用和交互。 前后端分离架构的好处是可以实现前端后端的解耦,提高开发效率和维护性。前端后端可以同时进行开发,并可采用不同的技术栈,使得团队成员能够专注于自己的领域。前后端分离还可以实现多端复用,例如可以用同一组后端接口提供给Web端和移动端调用。 总的来说,外卖项目采用前后端分离的架构,借助VueSpring Boot框架实现了用户界面的展示和交互以及业务逻辑的处理和数据存储,从而使得项目开发更加高效和可维护。 ### 回答3: 外卖项目采用前后端分离的架构,前端使用Vue.js框架进行开发,后端使用Spring Boot框架进行开发。 前端使用Vue.js框架的原因是因为Vue.js具有简洁、高效、灵活的特点,能够轻松构建交互式的用户界面。Vue.js还拥有一套完整的生态系统,能够方便地进行组件化开发,并提供了强大的工具来处理数据和状态的变化。 后端使用Spring Boot框架的原因是因为Spring Boot是一个简化了Spring开发的微框架,能够快速构建可独立运行的、生产级的应用。Spring Boot提供了大量的开箱即用的特性,如自动配置、快速开发等,能够极大地提高开发效率。 在外卖项目中,前端负责用户界面的展示和交互逻辑的实现。前端通过Vue.js进行组件化开发,将页面拆分为多个可复用的组件,提高开发效率和代码维护性。前端还通过Vue.js提供的路由功能,实现不同页面之间的跳转和导航。同时,前端还与后端通过HTTP协议进行通信,获取后端提供的数据和服务,并将其展示给用户。 后端负责处理前端发送的请求,并根据业务逻辑进行相应的处理,最终返回数据给前端后端还负责与数据库交互,对数据进行增删改查操作。后端使用Spring Boot提供的RESTful风格的API,能够轻松构建出符合规范的接口。同时,后端还可以利用Spring Security进行权限管理,确保只有具备相应权限的用户才能访问特定的接口。 综上所述,外卖项目采用前后端分离的架构,前端使用Vue.js框架进行开发,后端使用Spring Boot框架进行开发,能够提高开发效率和代码的可维护性,同时还能够满足用户对于界面交互和数据操作的需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值