배경
OA 관리 시스템에서는 직원들이 신청서를 제출하고 해당 메시지가 적시에 승인되도록 관련 담당자에게 실시간으로 통보되며 승인 후 결과가 사용자에게 푸시됩니다.
기술 선택
처음 발견한 것이 Firebase여서 매우 신나게 만지기 시작했습니다. Firebase는 사용하기 쉽습니다. js를 인용하고 공식 웹사이트의 튜토리얼을 따르면 프로젝트에 빠르게 적용할 수 있습니다. 다음날 프로젝트를 열었을 때 푸시 기능이 작동하지 않는 것을 발견했습니다. 이유는 무엇입니까? 마침내 Firebase 공식 웹사이트를 열 수 없다는 사실을 발견했습니다. . . Firebase가 Google에 인수되면 중국에서도 차단될 수 있나요? Firebase 자체가 끊어졌을 수도 있지만 더 이상 사용할 수 없습니다. 푸시 기능을 구현하려면 푸시 데이터를 완전히 Firebase 서버에 저장해야 하기 때문에 다음과 같은 문제가 있습니다.
1. 데이터가 안전하지 않습니다
2. Firebase에 대한 의존도가 높음
3. Firebase는 유료입니다(무료 버전은 너무 약함)
그래서 친구가 SignalR이라는 것을 시도해 볼 것을 추천했습니다. ASP.NET 개발자를 위한 것입니다. 다른 서버에 의존하지 않고 무료로 제공되는 메시지 푸시 라이브러리입니다.
사용법
1. nuget에서 최신 버전의 SignalR을 검색하여 추가합니다
2. 페이지에서 jquery.signalR을 참조합니다. 2.2.0.min.js 파일(jquery에 따라 다름)을 만든 다음 신호 자동 생성을 위한 스크립트
를 추가합니다.3. 해당 사용자 정보 처리 및 메시지 푸시 구현에 사용되는 cs 클래스
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace ZmeiOA.Services { [Authorize] [HubName("ZmHub")] public class MsgHub : Hub {/// <summary> /// 连接 /// </summary> /// <returns></returns> public override System.Threading.Tasks.Task OnConnected() { Groups.Add(Context.ConnectionId, Context.User.Identity.Name); return base.OnConnected(); } /// <summary> /// 重新连接 /// </summary> /// <returns></returns> public override System.Threading.Tasks.Task OnReconnected() { Groups.Add(Context.ConnectionId, Context.User.Identity.Name); return base.OnReconnected(); } /// <summary> /// 断开连接 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { Groups.Remove(Context.ConnectionId, Context.User.Identity.Name); return base.OnDisconnected(stopCalled); } } }
설명: SignalR의 푸시 메시지는 사용자 연결(ConnectionId)을 기반으로 하며 SignalR은 각 세션에 대해 자동으로 ConnectionId를 생성합니다. 하지만 우리의 푸시는 사용자(권한 시스템)를 기반으로 합니다. 즉, 로그인 후에만 이 허브에 등록할 수 있습니다. 여기서 사용하는 것은 로그인한 사용자의 ConnectionId와 해당 UserId를 그룹에 추가하는 것입니다. 푸시할 때 그룹의 이름만 지정하면 SignalR이 자동으로 해당 ConnectionId를 찾아서 보냅니다. 메시지(이 방법은 각 사용자의 UserId가 그룹의 키로 추가되기 때문에 최선이 아닐 수 있습니다. 사용자 수가 많으면 그룹도 매우 커지지만 아직 더 나은 대안을 찾지 못했습니다.) .
4. 메시지 푸시에는 두 가지 형태가 있습니다. a. 클라이언트에서 직접 푸시합니다.
차이점은 서버측 푸시는 데이터를 유지한 후 관련자에게 직접 메시지를 푸시할 수 있다는 점입니다. 반면 클라이언트측 푸시는 데이터를 유지한 후 클라이언트가 반환 값을 기반으로 SignalR의 JS를 사용합니다. 이 메소드는 서버의 푸시 기능을 호출합니다. 데이터를 지속시킨 후 업무에 따라 관련자에게 알릴 수 있기 때문에 서버를 이용해 직접 데이터를 푸시하는데, 프런트로 돌아와서 서버의 푸시 방식을 호출하면 그냥 불필요합니다.
예: 신청서 저장 성공 후 즉시 승인자에게 알림
서비스에서 허브 컨텍스트 가져오기
/// <summary> /// 消息推送上下文 /// </summary> protected static IHubContext ZmHubContext = GlobalHost.ConnectionManager.GetHubContext<MsgHub>();
신청서 저장 후 form 관련 담당자에게 푸시 메시지 (참고: 동적 메소드인 BroadcastTodo는 클라이언트에서 메시지를 수신해야 하는 메소드입니다.)
public static ApplyForm Save(FormView view) { //省略业务操作... //... //通知待办事项 ZmHubContext.Clients.Groups(app.AuditorIds.Split(',')).broadcastTodo(app.AuditorIds, new { type = "new", data = app }); return app; }
5. Angular 모듈을 등록할 때 허브를 연결하고 모듈에 전달합니다. 각 컨트롤러가 다음 연결을 사용할 수 있도록 값으로 지정합니다.
var zmHub = $.connection.ZmHub; var zmApp = angular.module('zmApp', ['ngRoute', 'ngResource', 'ngSanitize', 'ngMessages', 'ngSVGAttributes']).value('zmHub', zmHub);
6. 홈페이지의 컨트롤러에서 푸시 메시지를 수신하고 두 가지 푸시 경험을 제공합니다. a. 페이지 메시지. 데스크탑 알림은 브라우저가 최소화된 상태에서도 데스크탑 오른쪽 하단에서 알림을 받을 수 있습니다. (IE가 아닌 Chrome과 Firefox에서 지원)
zmHub.client.broadcastTodo = function (userIds, obj) { //通知下级控制器有待办事项 $scope.$broadcast('todoschanged', obj); //显示桌面通知 if (obj.type == 'new') { //桌面通知标题 var title = '来自[' + obj.data.ApplicantName + ']的申请单'; //申请单类型名称 var formTypeName = DefaultService.getEnumText(17, obj.data.Type); var msg = '[' + formTypeName + ']' + obj.data.Name; //桌面通知方法 NotifyService.Notify('todos', title, msg); } }
하위 컨트롤러의 수신 방법 (Angularjs 방송에 대해서는 설명이 별로 없고, 이해가 안 되시면 공식 홈페이지에서 확인하실 수 있습니다.) :
//接收推送的待办事项 $scope.$on('todoschanged', function (d, obj) { $scope.$apply(function () { //如果是新增数据,在当前列表中添加一条 if (obj.type == 'new') { $scope.todoApps.unshift(obj.data); } else if (obj.type == 'delete') {//如果是撤销申请,则把当前列表中那条数据删除 for (var j = 0; j < $scope.todoApps.length; j++) { if ($scope.todoApps[j].Id == obj.data.Id) { $scope.todoApps.splice(j, 1); break; } } } }); });
Desktop 알림 서비스:
//桌面通知服务 zmApp.factory('NotifyService', function () { return { Notify: function (icon, title, msg) { // At first, let's check if we have permission for notification // If not, let's ask for it if (window.Notification && Notification.permission !== "granted") { Notification.requestPermission(function (status) { if (Notification.permission !== status) { Notification.permission = status; } }); } var iconPath = '/Content/images/icons/' + (icon || 'info') + '.png'; var options = { lang: 'zh-CN', body: msg, icon: iconPath }; var notify; // If the user agreed to get notified if (window.Notification && Notification.permission === "granted") { notify = new Notification(title, options); } else if (window.Notification && Notification.permission !== "denied") { Notification.requestPermission(function (status) { if (Notification.permission !== status) { Notification.permission = status; } if (status === "granted") { notify = new Notification(title, options); } else { console.log('您禁止了桌面通知,无法推送到您的桌面!'); } }); } else { console.log('您禁止了桌面通知,无法推送到您的桌面!'); } if (notify) { notify.onclose = function (evt) { }; //点击切换到浏览器 notify.onclick = function () { window.focus(); }; } } }; });
Desktop 알림 효과:
요약:
SignalR을 사용하여 메시지를 푸시하는 것은 일반적으로 비교적 간단합니다. 달성하고 셀프호스트이므로 다른 서버 의존성 및 데이터 보안 문제에 대해 걱정할 필요가 없습니다. 관심 있는 친구는