メッセージ システムの設計と実装

文/JC_Huang (概要本の著者)
原文リンク: http://www.jianshu.com/p/f4d7827821f1
著作権は著者に属し、転載する場合は著者に連絡して許可を得て、「概要書の著者」とマークを付けてください。

製品分析

まず、メッセージが市場でどのように実装されるかを見てみましょう。

Jianshu

Jianshuのメッセージシステムは主に2つのタイプに分かれています

  • ショートメッセージ
  • リマインダー

ショートメッセージ
ショートメッセージの性質は、実際にはプライベートメッセージと同じであり、特定の情報内容を含むユーザーからユーザーに送信されるメッセージです。


ショートレター

リマインダー
リマインダーは、システムによって送信されるメッセージの形式です。コピーは固定されており、通常は特定のオブジェクトへのハイパーリンクがあります。


Jianshu リマインダー

Zhihu

Zhihu は Jianshu と同じで、主に 2 つのタイプがあります:

  • プライベートメッセージ
  • メッセージ

プライベートメッセージ
Jianshu と同様に、ユーザーがユーザーにメッセージを送信できます。管理者からユーザーに送信されるメッセージにすることができます。


Zhihu プライベートメッセージ

メッセージ
Zhihu メッセージは Jianshu のリマインダーよりも優れています。 Zhihu は、ユーザーの読書プレッシャーを軽減するために、複数の同様のメッセージを収集します。


Zhihu News

3 つのカテゴリーのニュース

2 つの製品の簡単な分析を通じて、これに基づいて、もう 1 つのメッセージ、つまりアナウンスを追加します。
アナウンスの主な性質は、システムがサイト上のすべてのユーザーが読むことができる特定のコンテンツを含むメッセージを送信することです。
メッセージには 3 つのカテゴリがあります:

  1. アナウンス
  2. リマインド
  3. プライベート メッセージ

リマインダーの言語分析

Jianshu から一連のリマインダー サンプルを取得します。

  • 3dbe1bd90774 さんがあなたをフォローしました
  • magicdawn があなたの記事「シングル サインオンを実装する 3 つの方法」を気に入ってくれました
  • 悪徳プログラムはあなたの記事「RESTful API に基づいてユーザー権限制御を設計する方法?」を気に入りました。 》
  • alexcc4 さんがあなたの記事「Nodejs での単体テストの実装」を気に入ってくれました。
  • あなたは「RESTful API に基づいてユーザー権限制御を設計する方法?」で書きました。 "cnlinjie からコメントを受け取りました
  • あなたの記事「セッション原則」がトピック「ios 開発」に追加されました

文の構造を分析してください、リマインダーの内容は単なるものです

「誰が誰のものに何をするのか」
「誰かが誰かの何かで何かをする」

誰か = リマインダーのトリガー、または送信者、送信者としてマーク
何かをする = リマインダーのアクション、コメント、いいね、注目はすべて 1 つのアクションに属し、アクションとしてマーク
何か = リマインダーのアクションのオブジェクト、どの特定の記事それは、ターゲットとしてマークされています
誰かの = リマインダー アクションのオブジェクトの所有者、targetOwner

としてマークされています これは明らかです、送信者と targetOwner は Web サイトのユーザーであり、ターゲットは特定の記事がリマインダーの対象である場合、記事に限定されず、他にもある場合は、ターゲットが記事であるかそれ以外であるかをマークする targetType を追加する必要があります。アクションは固定されています。Web サイト全体でリマインダーをトリガーするアクションはいくつかしかありません: コメント、いいね、フォロー... (または企業がリマインダーを必要とするその他のアクション)

の両側メッセージを取得するには 2 つの方法があります

  • プッシュ
  • プル

Zhihu を例に挙げます
プッシュの方が多いです特定の質問のフォロワーのリストを維持する必要があります。この質問をプッシュする条件がトリガーされると (たとえば、誰かが質問に回答するなど)、この通知が各フォロワーに送信されます。

プルはプッシュの逆で、少し面倒です。たとえば、ユーザーがオンラインになるたびに、各問題のイベント リストがポーリングされます。元のタイムスタンプよりも大きい場合は、それを取得します。

メッセージの分類に応じて異なる取得方法を使用します。:
メッセージが生成されると、メッセージは特定のメッセージ テーブルに保存されます。送信者がメッセージを作成した後、関心のある問題の表に従ってメッセージをプルし、それを独自のメッセージ キューに追加します。また、受信者を指定するか、受信者のメッセージ キューにメッセージを追加します。

購読

リマインダーに従ってプル方式を使用するには、注目すべき事項のリストを維持する必要があります。

この動作を次のように呼びます。

"サブスクライブ" サブスクライブ

サブスクリプションには次の 3 つのコア属性があります

:

サブスクリプション ターゲットtarget
  • サブスクリプション ターゲット タイプ targetType
  • サブスクリプション アクション action
  • たとえば、記事を公開する場合、記事「XXX」コメント アクションをサブスクライブします。 , そのため、記事「XXX」にコメントが付けられるたびに、リマインダーを送信して通知する必要があります。

購読ルールも拡張できます

記事が気に入った場合、購読アクションは記事を公開するときとは異なる場合があります。 記事が気に入ったら、更新情報やコメントを得るためにこの記事を購読していただければ幸いです。
記事を投稿するときに、この記事のコメント アクションを購読できればいいのにと思います。

この時点で、もう 1 つのパラメータが必要です。subscribReason

アクション配列に対応する異なる subscribReason、

subscribeReason = like、actions = [update, comment]
subscribeReason = に対応します。 public 、アクションに対応 = [コメント]

サブスクリプション ルールは拡張することもできます

ユーザーは独自のサブスクリプション設定を持つことができます。たとえば、すべてのお気に入りのアクションに対して、「I Don'」受け取りたくないのです。 たとえば、知っているリマインダーの設定

知っているリマインダーの設定
なので、別のテーブルを維持する必要があります: SubscriptionConfig

、ユーザーのリマインダー設定を保存します。 また、ユーザーがリマインダー設定を持っていない場合は、システムによって提供される一連のデフォルト設定を使用できます: defaultSubscriptionConfig
Aggregation

If I public私がオンラインではなかったとき、「XXX」という記事に 10 回コメントが付けられました。オンラインになったときは、次のようなメッセージを 10 回受け取ったはずです。「誰々があなたの記事「XXX」にコメントしました。

まだですか? 「A、B、C、D... あなたの記事 "XXX" にコメントしました。」というメッセージが表示されます。


Zhihu は集計において優れた仕事をしました。彼らが達成したいかどうかを知る必要があります。これはかなり技術的です:

Zhihu のメッセージング メカニズムは技術的にどのように設計され、計画されていますか?

Web サイトのメッセージ (通知) システムは一般的にどのように実装されていますか?

関数のこの部分に関しては、まだ具体的な実装方法が決まっていないため、これ以上詳しく説明することはできません。 ⊙﹏⊙

5 つのエンティティ

上記の分析を通じて、このメッセージング システムを構築するためにどのようなエンティティ クラスが必要であるかがおおよそわかります:

ユーザー メッセージ キュー UserNotify
  1. ユーザー
  2. サブスクリプション
  3. サブスクリプション設定 SubscriptionConfig
  4. メッセージ通知
  5. アナウンス
    • リマインド
    • メッセージ
  6. 動作の内訳

ここまで述べたので、メッセージ プロセス全体の動作をいくつか整理してみましょう。 >システムまたは管理者、メッセージを作成

createNotify (アナウンス | リマインド | メッセージ)

    • ユーザー、メッセージの購読、購読解除
    • 購読、購読のキャンセル
    • ユーザー管理サブスクリプション設定
    • getSubscriptionConfig, updateSubscriptionConfig
    • ユーザー、メッセージをプル
    • pullNotify (アナウンス | リマインド | メッセージ | すべて)
    • ユーザー、メッセージ キューをクエリします
    • getUserNotify(get cancel | remember | message | all)
    • ユーザーがメッセージを読み取ります
    • 読む
  • >>>>>>>>>> ;>>>>>>>>>>>>>>>>>>>> ;>>>>>>>>>>>>>>>>>>>> ;>>>>>>>>>>>>>>>>>>>>>>

モデル設計

通知

<code class="javascript">id            : {type: <span class="hljs-string">'integer', primaryKey: <span class="hljs-literal">true},        <span class="hljs-comment">// 主键content     : {type: <span class="hljs-string">'text'},    <span class="hljs-comment">// 消息的内容type        : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true, enum: [<span class="hljs-number">1, <span class="hljs-number">2, <span class="hljs-number">3]},  <span class="hljs-comment">// 消息的类型,1: 公告 Announce,2: 提醒 Remind,3:信息 Messagetarget      : {type: <span class="hljs-string">'integer'},    <span class="hljs-comment">// 目标的IDtargetType  : {type: <span class="hljs-string">'string'},    <span class="hljs-comment">// 目标的类型action      : {type: <span class="hljs-string">'string'},    <span class="hljs-comment">// 提醒信息的动作类型sender      : {type: <span class="hljs-string">'integer'},    <span class="hljs-comment">// 发送者的IDcreatedAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>

保存リマインド
メッセージ テーブルには、targettargetType フィールドが必要です。このリマインダーに関連付けられたオブジェクトを記録します。 action フィールドには、リマインダーに関連付けられたアクションが記録されます。
たとえば、メッセージ: 「Xiao Ming が記事を気に入った」
その後:

<code class="javascript">target = <span class="hljs-number">123,  <span class="hljs-comment">// 文章IDtargetType = <span class="hljs-string">'post',  <span class="hljs-comment">// 指明target所属类型是文章sender = <span class="hljs-number">123456  <span class="hljs-comment">// 小明ID</span></span></span></span></span></span></code>

アナウンスとメッセージを保存
もちろん、Notify は保存もサポートしていますお知らせと情報。 content フィールドは使用されますが、targettargetType、および action フィールドは使用されません。

UserNotify

<code class="javascript">id            : {type: <span class="hljs-string">'integer', primaryKey: <span class="hljs-literal">true},        <span class="hljs-comment">// 主键isRead      : {type: <span class="hljs-string">'boolean', required: <span class="hljs-literal">true},   user        : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true},  <span class="hljs-comment">// 用户消息所属者notify      : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true}   <span class="hljs-comment">// 关联的NotifycreatedAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></span></span></code>

UserNotify を使用して、リマインダー (通知) の特定のコンテンツに関連付けられたユーザーのメッセージ キューを保存します。
UserNotify は主に 2 つの方法で作成されます:

  1. アナウンスとリマインドをプルするためにサブスクリプション テーブルを走査するときに作成されます
  2. 新しい情報 (メッセージ) はすぐに作成されます。

サブスクリプション

<code class="javascript">target      : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true},    <span class="hljs-comment">// 目标的IDtargetType  : {type: <span class="hljs-string">'string', required: <span class="hljs-literal">true},    <span class="hljs-comment">// 目标的类型action      : {type: <span class="hljs-string">'string'},   <span class="hljs-comment">// 订阅动作,如: comment/like/post/update etc.user        : {type: <span class="hljs-string">'integer'},createdAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></code>

サブスクリプションは、Notify テーブルから UserNotify にメッセージをプルするための前提条件です。ユーザーはまず特定のターゲットのアクションをサブスクライブし、次にこの Only を生成します。ユーザーはターゲットのアクションを通知されます。
例: 「Xiao Ming は製品 A のコメントに注目しました」、データは次のように表現されます:

<code class="javascript">target: <span class="hljs-number">123,  <span class="hljs-comment">// 产品A的IDtargetType: <span class="hljs-string">'product',action: <span class="hljs-string">'comment',user: <span class="hljs-number">123  <span class="hljs-comment">// 小明的ID</span></span></span></span></span></span></code>

このように、製品 A で生成されたすべてのコメントにより Xiao への通知が生成されます。明。

SubscriptionConfig

<code class="javascript">action: {type: <span class="hljs-string">'json', required: <span class="hljs-literal">true},   <span class="hljs-comment">// 用户的设置user: {type: <span class="hljs-string">'integer'}</span></span></span></span></code>

ユーザーごとにサブスクリプションの習慣が異なる場合があります。このテーブルでは、ユーザーは特定のアクションをサブスクライブするかどうかを一律に設定できます。デフォルトでは、システムによって提供されるデフォルト構成が使用されます。

<code class="javascript">defaultSubscriptionConfig: {  <span class="hljs-string">'comment'   : <span class="hljs-literal">true,    <span class="hljs-comment">// 评论  <span class="hljs-string">'like'      : <span class="hljs-literal">true,    <span class="hljs-comment">// 喜欢}</span></span></span></span></span></span></code>

このモデルのセットでは、targetTypeaction は必要に応じて拡張できます。各アクションのリマインダーをさらに追加します: hate が嫌われた、update が更新されたなど。

設定ファイル NotifyConfig

<code class="javascript"><span class="hljs-comment">// 提醒关联的目标类型targetType: {  PRODUCT : <span class="hljs-string">'product',    <span class="hljs-comment">// 产品  POST    : <span class="hljs-string">'post'    <span class="hljs-comment">// 文章},<span class="hljs-comment">// 提醒关联的动作action: {  COMMENT   : <span class="hljs-string">'comment',  <span class="hljs-comment">// 评论  LIKE      : <span class="hljs-string">'like',     <span class="hljs-comment">// 喜欢},<span class="hljs-comment">// 订阅原因对应订阅事件reasonAction: {  <span class="hljs-string">'create_product'  : [<span class="hljs-string">'comment', <span class="hljs-string">'like']  <span class="hljs-string">'like_product'    : [<span class="hljs-string">'comment'],  <span class="hljs-string">'like_post'       : [<span class="hljs-string">'comment'],},<span class="hljs-comment">// 默认订阅配置defaultSubscriptionConfig: {  <span class="hljs-string">'comment'   : <span class="hljs-literal">true,    <span class="hljs-comment">// 评论  <span class="hljs-string">'like'      : <span class="hljs-literal">true,    <span class="hljs-comment">// 喜欢}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>

サービス層 NotifyService

NotifyService には次のメソッドがあります:

  • createAnnounce(content, sender )
  • createRemind(ターゲット、targetType、アクション、送信者、コンテンツ)
  • createMessage(コンテンツ、送信者、受信者)
  • pullAnnounce(user)
  • pullRemind ( user)
  • subscribe(user, target, targetType,reason)
  • cancelSubscription(user, target, targetType)
  • getSubscriptionConfig(userID)
  • updateSubscriptionConfig ( userID)
  • getUserNotify(userID)
  • read(user, NoticeIDs)

各メソッドの処理ロジックは以下のとおりです:

createAnnounce (content, sender)

  1. Notify テーブルにアナウンス レコードを挿入します

createRemind(target, targetType, action, sender 、content)

  1. Notify テーブルにリマインダー レコードを挿入します

createMessage(content, sender,Receiver)

  1. Notify テーブルに情報レコードを挿入します
  2. UserNotify テーブルにレコードを挿入し、新しく作成された Notify を関連付けます

pullAnnounce(user)

  1. UserNotify から最新のアナウンス情報の作成時刻を取得します: lastTime
  2. lastTime をフィルター条件として使用して、Notify のアナウンス情報をクエリします
  3. 新しい UserNotify を作成し、クエリされたお知らせ情報を関連付けます

pullRemind(user)

  1. ユーザーのサブスクリプション テーブルをクエリし、一連のユーザーのサブスクリプションを取得しますrecords
  2. 各サブスクリプション レコードの targettargetTypeactioncreatedAt を介して Notify テーブルをクエリし、サブスクライブされた Notify レコードを取得します。 (サブスクリプション時刻はリマインダーの作成時刻よりも前である必要があることに注意してください)
  3. ユーザーの構成ファイル SubscriptionConfig をクエリします。そうでない場合は、デフォルトの構成 DefaultSubscriptionConfig を使用します。
  4. サブスクリプション構成を使用して、クエリされたものをフィルタリングします。 Notify
  5. フィルターされた通知を関連付けとして使用して、新しい UserNotify

subscribe(user, target, targetType,reason)

    を作成します
  1. 理由 NotifyConfig によってクエリを実行し、対応するアクション グループを取得します: actions
  2. アクション グループを走査し、アクションごとに新しいサブスクリプション レコードを作成します

cancelSubscription (user, target, targetType)

  1. usertargettargetType

getSubscriptionConfig に対応する 1 つ以上のレコードを削除します(userID)

  1. SubscriptionConfig テーブルをクエリしてユーザーのサブスクリプション構成を取得します

updateSubscriptionConfig(userID)

  1. ユーザーの SubscriptionConfig レコードを更新します

getUserNotify(userID)

  1. ユーザーのメッセージ リストを取得します

読み取り(ユーザー、通知ID)

  1. 指定された通知を更新し、isRead 属性を true に設定します

シーケンス図

リマインダーのサブスクリプション、作成、取得


リマインダーのサブスクリプション、作成、プル


製品の作成後に NotifyService.subscribe メソッドを呼び出し、
メソッドを呼び出して、製品のレビュー後に呼び出すことができます。 NotifyService.createRemind メソッド、
はその後、ユーザーがシステムにログインするときに NotifyService.pullRemind メソッドを呼び出します。または、ユーザーがメッセージ キューをクエリするときに、
は最後に NotifyService.getUserNotify メソッドを呼び出します。

アナウンスの作成と取得


アナウンスの作成と取得


管理者から送信 アナウンス時が作成され、NotifyService.createAnnounce メソッドが呼び出され、
次に、ユーザーがシステムにログインするとき、または別の時点で NotifyService.pullAnnounce メソッドが呼び出され、最後にユーザーがシステムにログインしたときに
メソッドが呼び出されます。メッセージキューをクエリします。 NotifyService.getUserNotify

情報の作成


情報の作成

情報を作成するには、
を直接呼び出すだけです これNotifyService.createMessage次回ユーザーがメッセージ キューをクエリするときに、この情報がクエリされます。


声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
华为GT3 Pro和GT4的差异是什么?华为GT3 Pro和GT4的差异是什么?Dec 29, 2023 pm 02:27 PM

许多用户在选择智能手表的时候都会选择的华为的品牌,其中华为GT3pro和GT4都是非常热门的选择,不少用户都很好奇华为GT3pro和GT4有什么区别,下面就就给大家介绍一下二者。华为GT3pro和GT4有什么区别一、外观GT4:46mm和41mm,材质是玻璃表镜+不锈钢机身+高分纤维后壳。GT3pro:46.6mm和42.9mm,材质是蓝宝石玻璃表镜+钛金属机身/陶瓷机身+陶瓷后壳二、健康GT4:采用最新的华为Truseen5.5+算法,结果会更加的精准。GT3pro:多了ECG心电图和血管及安

修复:截图工具在 Windows 11 中不起作用修复:截图工具在 Windows 11 中不起作用Aug 24, 2023 am 09:48 AM

为什么截图工具在Windows11上不起作用了解问题的根本原因有助于找到正确的解决方案。以下是截图工具可能无法正常工作的主要原因:对焦助手已打开:这可以防止截图工具打开。应用程序损坏:如果截图工具在启动时崩溃,则可能已损坏。过时的图形驱动程序:不兼容的驱动程序可能会干扰截图工具。来自其他应用程序的干扰:其他正在运行的应用程序可能与截图工具冲突。证书已过期:升级过程中的错误可能会导致此issu简单的解决方案这些适合大多数用户,不需要任何特殊的技术知识。1.更新窗口和Microsoft应用商店应用程

Go中Type关键字有哪些用法Go中Type关键字有哪些用法Sep 06, 2023 am 09:58 AM

Go中Type关键字的用法有定义新的类型别名或者创建新的结构体类型。详细介绍:1、类型别名,使用“type”关键字可以为已有的类型创建别名,这种别名不会创建新的类型,只是为已有的类型提供一个新的名称,类型别名可以提高代码的可读性,使代码更加清晰;2、结构体类型,使用“type”关键字可以创建新的结构体类型,结构体是一种复合类型,可以用于定义包含多个字段的自定义类型等等。

解决Ubuntu挂载移动硬盘错误:未知的文件系统类型exfat解决Ubuntu挂载移动硬盘错误:未知的文件系统类型exfatJan 05, 2024 pm 01:18 PM

ubuntu挂载移动硬盘出现错误:mount:unknownfilesystemtype'exfat'处理方法如下:Ubuntu13.10或安装exfat-fuse:sudoapt-getinstallexfat-fuseUbuntu13.04或以下sudoapt-add-repositoryppa:relan/exfatsudoapt-getupdatesudoapt-getinstallfuse-exfatCentOSLinux挂载exfat格式u盘错误的解决方法CentOS中加载extfa

如何修复无法连接到iPhone上的App Store错误如何修复无法连接到iPhone上的App Store错误Jul 29, 2023 am 08:22 AM

第1部分:初始故障排除步骤检查苹果的系统状态:在深入研究复杂的解决方案之前,让我们从基础知识开始。问题可能不在于您的设备;苹果的服务器可能会关闭。访问Apple的系统状态页面,查看AppStore是否正常工作。如果有问题,您所能做的就是等待Apple修复它。检查您的互联网连接:确保您拥有稳定的互联网连接,因为“无法连接到AppStore”问题有时可归因于连接不良。尝试在Wi-Fi和移动数据之间切换或重置网络设置(“常规”>“重置”>“重置网络设置”>设置)。更新您的iOS版本:

php提交表单通过后,弹出的对话框怎样在当前页弹出,该如何解决php提交表单通过后,弹出的对话框怎样在当前页弹出,该如何解决Jun 13, 2016 am 10:23 AM

php提交表单通过后,弹出的对话框怎样在当前页弹出php提交表单通过后,弹出的对话框怎样在当前页弹出而不是在空白页弹出?想实现这样的效果:而不是空白页弹出:------解决方案--------------------如果你的验证用PHP在后端,那么就用Ajax;仅供参考:HTML code<form name="myform"

watch4pro好还是gt好watch4pro好还是gt好Sep 26, 2023 pm 02:45 PM

watch4pro和gt各自具有不用的特点和适用场景,如果注重功能的全面性、高性能和时尚外观,同时愿意承担较高的价格,那么Watch 4 Pro可能更适合。如果对功能要求不高,更注重电池续航和价格的合理性,那么GT系列可能更适合。最终的选择应根据个人需求、预算和喜好来决定,建议在购买前仔细考虑自己的需求,并参考各种产品的评测和比较,以做出更明智的选择。

Linux类型命令Linux类型命令Mar 20, 2024 pm 05:06 PM

在本指南中,我们将学习更多关于Linux中的”type”命令。前提条件:要执行本指南中演示的步骤,您需要以下组件:正确配置的Linux系统。查看如何创建LinuxVM用于测试和学习目的。对命令行界面的基本理解Linux中的Type命令与其他Linux专用命令(例如:ls、chmod、shut、vi、grep、pwd等)不同,”type”命令是一个内置的Bash函数,它显示作为参数提供的命令类型的信息。$type除了Bash,其他炮弹(Zsh、Ksh等)还附带

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター