Files
redkale/net.html
Redkale 25684126aa
2017-06-19 13:47:15 +08:00

850 lines
105 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="net_intro" class="anchor" href="#" aria-hidden="true"></a>Net 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Net 组件是基于AIO(NIO.2)的一套TCP/UDP的网络框架且只提供异步接口。org.redkale.net 是所有网络协议服务的基础包。Redkale内置HTTP和远程模式Service依赖的SNCP(Service Node Communicate Protocol)协议的实现包。Redkale启动的<b>&lt;server&gt;</b>节点服务都是基于Net组件实现的协议。下面详细介绍 <a href="#net_http">HTTP服务</a><a href="#net_sncp">SNCP协议</a></p>
<h3><a id="net_http" class="anchor" href="#" aria-hidden="true"></a>HTTP 服务</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale自实现的HTTP服务接口并不遵循Java EE规范JSR 340(Servlet 3.1)Redkale提倡的是HTTP+JSON的服务接口方式因此没有实现JSP规范HTTP+JSON服务接口几乎适合所有类型的客户端(PC应用程序、PC Web、微信H5、移动APP、移动Web)开发。其与JSR 340(Servlet 3.1)的主要区别如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、内置参数的JSON反序列化和响应结果的序列化接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、对数值型的参数和header值提供简易接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、不支持JSP提倡的是HTTP+JSON接口方式。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、无HttpSession对象session可通过配置CacheSource实现。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、内置文件上传接口且可自实现断点续传。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、对响应结果内容可以进行短期缓存从而减少数据源操作的压力。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7、内置WebSocket的集群与组功能且提供伪WebSocket连接功能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8、HttpResponse只能异步输出。<br/>
</p>
<p id="baseservlet">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类这样方便以后加入类似javax.servlet.Filter的功能。 <br/> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个典型的BaseSerlvet实现:
</p>
<div class="highlight"><pre><span></span><span class="nd">@HttpUserType</span><span class="o">(</span><span class="n">UserInfo</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">BaseSerlvet</span> <span class="kd">extends</span> <span class="n">HttpServlet</span> <span class="o">{</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="n">Logger</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="n">fine</span> <span class="o">=</span> <span class="n">logger</span><span class="o">.</span><span class="na">isLoggable</span><span class="o">(</span><span class="n">Level</span><span class="o">.</span><span class="na">FINE</span><span class="o">);</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"APP_TIME"</span><span class="o">)</span> <span class="c1">//[Redkale内置资源] 进程的启动时间</span>
<span class="kd">protected</span> <span class="kt">long</span> <span class="n">serverCreateTime</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonFactory</span> <span class="n">jsonFactory</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前进程的根目录,字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"APP_HOME"</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">home</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前Http Server的web页面的根目录字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"SERVER_ROOT"</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">webroot</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//在调用authenticate之前调用, 必须在此处设置currentUser用户信息</span>
<span class="c1">//该方法可以用于判断请求源是否合法或加入一些全局的拦截操作</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">preExecute</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="kd">final</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">request</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">"User-Agent"</span><span class="o">,</span> <span class="s">""</span><span class="o">).</span><span class="na">contains</span><span class="o">(</span><span class="s">"Redkale-Agent"</span><span class="o">))</span> <span class="o">{</span> <span class="c1">//只用移动APP的接口可以判断User-Agent是否正确</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"retcode"</span><span class="o">,</span> <span class="s">"10001"</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"retmessage"</span><span class="o">,</span> <span class="s">"User-Agent error"</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">finish</span><span class="o">(</span><span class="mi">201</span><span class="o">,</span> <span class="s">"{'success':false, 'message':'User-Agent error, must be Redkale-Agent'}"</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//可以加上一些统计操作</span>
<span class="k">if</span> <span class="o">(</span><span class="n">fine</span><span class="o">)</span> <span class="n">response</span><span class="o">.</span><span class="na">recycleListener</span><span class="o">((</span><span class="n">req</span><span class="o">,</span> <span class="n">resp</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="c1">//记录处理时间太长的请求操作</span>
<span class="kt">long</span> <span class="n">e</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">()</span> <span class="o">-</span> <span class="n">request</span><span class="o">.</span><span class="na">getCreatetime</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span> <span class="o">&gt;</span> <span class="mi">500</span><span class="o">)</span> <span class="n">logger</span><span class="o">.</span><span class="na">fine</span><span class="o">(</span><span class="s">"耗时居然用了 "</span> <span class="o">+</span> <span class="n">e</span> <span class="o">+</span> <span class="s">" 毫秒. 请求为: "</span> <span class="o">+</span> <span class="n">req</span><span class="o">);</span>
<span class="o">});</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">sessionid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sessionid</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">request</span><span class="o">.</span><span class="na">setCurrentUser</span><span class="o">(</span><span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">sessionid</span><span class="o">));</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">//一般用于判断用户的登录态, 返回false表示鉴权失败</span>
<span class="c1">//moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@HttpMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">authenticate</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">info</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">currentUser</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">info</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_UNLOGIN</span><span class="o">));</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(!</span><span class="n">info</span><span class="o">.</span><span class="na">checkAuth</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">getModuleid</span><span class="o">(),</span> <span class="n">request</span><span class="o">.</span><span class="na">getActionid</span><span class="o">()))</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_AUTH_ILLEGAL</span><span class="o">));</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;继承HttpServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能 一个典型的操作<span id="userservlet">用户HttpServlet</span>: </p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span><span class="s">"/user/*"</span><span class="o">},</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户模块服务"</span><span class="o">)</span> <span class="c1">//拦截所有 /user/ 开头的请求</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserServlet</span> <span class="kd">extends</span> <span class="n">BaseSerlvet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//登录操作 </span>
<span class="c1">//因为HttpMapping的判断规则用的是String.startsWith所以HttpMapping.url不能用正则表达式只能是getRequestURI的前缀</span>
<span class="c1">//且同一个HttpServlet类内的所有HttpMapping不能存在包含关系, 如 /user/myinfo 和 /user/myinforecord 不能存在同一HttpServlet中。</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/login"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户登录"</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"bean"</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">LoginBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录参数对象"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">login</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">LoginBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">LoginBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">"bean"</span><span class="o">);</span> <span class="c1">//获取参数</span>
<span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">login</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span> <span class="c1">//登录操作, service内部判断bean的合法性</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">result</span><span class="o">);</span> <span class="c1">//输出结果</span>
<span class="o">}</span>
<span class="c1">//获取当前用户信息</span>
<span class="c1">//未登录的请求会被BaseSerlvet.authenticate方法拦截因此能进入该方法说明用户态存在</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/myinfo"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"获取当前用户信息"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">myinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="c1">//或者使用 user = req.getAttribute("_current_userinfo"); 因为BaseSerlvet.authenticate方法已经将UserInfo注入到_current_userinfo属性中</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//获取指定用户ID的用户信息, 请求如: /user/username/43565443</span>
<span class="c1">// 翻页查询想缓存就需要将翻页信息带进url: /user/query/page:2/size:50 。</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/userinfo/"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"获取指定用户ID的用户信息"</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"#"</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户ID"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">userinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">()));</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//更新个人头像</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/updateface"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"更新用户头像"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">updateface</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="k">for</span> <span class="o">(</span><span class="n">MultiPart</span> <span class="n">part</span> <span class="o">:</span> <span class="n">req</span><span class="o">.</span><span class="na">multiParts</span><span class="o">())</span> <span class="o">{</span> <span class="c1">//遍历上传文件列表 </span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">byts</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="na">getContentBytes</span><span class="o">(</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024L</span><span class="o">);</span> <span class="c1">//图片大小不能超过5M超过5M返回null</span>
<span class="k">if</span> <span class="o">(</span><span class="n">byts</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">102</span><span class="o">,</span> <span class="s">"上传的文件过大"</span><span class="o">));</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">BufferedImage</span> <span class="n">img</span> <span class="o">=</span> <span class="n">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="k">new</span> <span class="n">ByteArrayInputStream</span><span class="o">(</span><span class="n">byts</span><span class="o">));</span>
<span class="c1">//... 此处处理并存储头像图片</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetResult</span><span class="o">.</span><span class="na">SUCCESS</span><span class="o">);</span> <span class="c1">//输出成功信息</span>
<span class="o">}</span>
<span class="k">return</span><span class="o">;</span> <span class="c1">//头像图片仅会传一个, 只需要读取一个即可返回</span>
<span class="o">}</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">103</span><span class="o">,</span> <span class="s">"没有上传图片"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上,所有/user/前缀的请求都会进入UserServlet若没匹配的则返回505错误为了方便以后编写前方静动分离服务器转发规则比较好的习惯是将项目中所有动态Servlet加一个固定前缀<a href="redkale.html#redkale_confxml" target="_blank">application.xml</a> 里设置path即可。</p>
<div class="highlight"><pre><span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;servlets</span> <b><span class="na">path=</span><span class="s">&quot;/pipes&quot;</span></b> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上, 配置了/pipes 前缀后客户端发送Servlet请求需带上前缀请求当前用户信息的url就变成/pipes/user/myinfo 。</p>
<br/>
<p id="net_apidoc">&nbsp;&nbsp;<b> API Doc</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在小型互联网公司里基本是追求敏捷开发很少先花时间设计接口文档再进行开发通常都是直接进行数据库设计和开发开发完后需要开发人员需要编写接口文档提供给前端人员开发。为了减少文档的编写工作量和强制开发人员对接口进行注释Redkale提供了apidoc命令apidoc遍历当前进程中所有标记@WebServlet的可用HttpServlet根据Servlet中@HttpMapping、@HttpParam生成json对象并输出文件。在<b>系统运行</b>时执行apidoc命令会在进程根目录下生成apidoc.json、apidoc.html文件。apidoc.html的模板可以定制 只需在conf/目录下存放一个 <b>apidoc-template.html</b> 文件,且文件中必须包含关键字 <b>${content}</b> 即可实现接口文档的自定义。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了能正确显示接口文档开发人员需要在编写HttpServlet时在每个@HttpMapping方法上加上comment属性和@HttpParam注解, 一个方法上可以注解多个@HttpParam, 如上面的 <a href="#userservlet">UserServlet</a> 。RestServlet是由RestService自动生成@HttpMapping、@HttpParam在REST组件中存在对应的注解@RestMapping、@RestParam因此在编写RestService时需要加上@RestMapping、@RestParam且加上comment属性。如范例: <a href="service.html#helloservice" target="_blank">HelloService</a><br/>
</p>
<p id="net_ws">&nbsp;&nbsp;<b> WebSokcet 服务</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebSokcet协议遵循<a href="http://tools.ietf.org/html/rfc645" target="_blank">IETF RFC 6455</a>其接口并不符合Java EE中的WebSocket的接口规范。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个WebSocket连接对应一个WebSocket实体即一个WebSocket会绑定一个TCP连接。且有两种模式:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议上符合HTML5规范, 其流程顺序如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1 onOpen &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.2 createUserid &nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.3 onConnected &nbsp;&nbsp;&nbsp;&nbsp; WebSocket成功连接后在准备接收数据前回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.4 onMessage/onFragment+ &nbsp;&nbsp; WebSocket接收到消息后回调此消息类方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.5 onClose &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebSocket被关闭后回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此模式下 以上方法都应该被重载。<br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现一个WebSocket服务需要继承 org.redkale.net.http.WebSocketServlet以下是一个简单的聊天范例</p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="s">"/ws/chat"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ChatWebSocketServlet</span> <span class="kd">extends</span> <span class="n">WebSocketServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"本实例的WebSocketNode: "</span> <span class="o">+</span> <span class="kd">super</span><span class="o">.</span><span class="na">node</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">destroy</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"关闭了ChatWebSocketServlet"</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">WebSocket</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">ChatMessage</span><span class="o">&gt;</span> <span class="nf">createWebSocket</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">WebSocket</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">ChatMessage</span><span class="o">&gt;()</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">UserInfo</span> <span class="n">user</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">ChatMessage</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// text 接收的格式: {"receiveid":200000001, "content":"Hi Redkale!"}</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendid</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">();</span> <span class="c1">//将当前用户设为消息的发送方</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendtime</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span> <span class="c1">//设置消息发送时间</span>
<span class="c1">//给接收方发送消息, 即使接收方在其他WebSocket进程节点上有链接Redkale也会自动发送到其他链接进程节点上。</span>
<span class="kd">super</span><span class="o">.</span><span class="na">sendMessage</span><span class="o">(</span><span class="n">message</span><span class="o">,</span> <span class="n">message</span><span class="o">.</span><span class="na">receiveid</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">createUserid</span><span class="o">()</span> <span class="o">{</span> <span class="c1">//创建用户ID</span>
<span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">=</span> <span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="kd">super</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">()));</span>
<span class="k">return</span> <span class="n">CompletableFuture</span><span class="o">.</span><span class="na">completedFuture</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="nf">onOpen</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">CompletableFuture</span><span class="o">.</span><span class="na">completedFuture</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span> <span class="c1">//以request中的sessionid字符串作为WebSocket的sessionid</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">ChatMessage</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">sendid</span><span class="o">;</span> <span class="c1">//发送方用户ID</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">receiveid</span><span class="o">;</span> <span class="c1">//接收方用户ID </span>
<span class="kd">public</span> <span class="n">String</span> <span class="n">content</span><span class="o">;</span> <span class="c1">//文本消息内容</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="n">sendtime</span><span class="o">;</span> <span class="c1">//消息发送时间</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p id="net_httprequest">&nbsp;&nbsp;<b>. HttpRequest 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpRequest</span> <span class="o">{</span>
<span class="c1">//获取客户端地址IP</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端地址IP, 与getRemoteAddres() 的区别在于本方法优先取header中指定为RemoteAddress名的值没有则返回getRemoteAddres()的getHostAddress()。</span>
<span class="c1">//本方法适用于服务前端有如nginx的代理服务器进行中转通过getRemoteAddres()是获取不到客户端的真实IP。</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取请求内容指定的编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBody</span><span class="o">(</span><span class="n">Charset</span> <span class="n">charset</span><span class="o">);</span>
<span class="c1">//获取请求内容的UTF-8编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBodyUTF8</span><span class="o">();</span>
<span class="c1">//获取请求内容的byte[]</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">getBody</span><span class="o">();</span>
<span class="c1">//获取请求内容的JavaBean对象</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getBodyJson</span><span class="o">(</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Type</span> <span class="n">type</span><span class="o">);</span>
<span class="c1">//获取请求内容的JavaBean对象</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getBodyJson</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Type</span> <span class="n">type</span><span class="o">);</span>
<span class="c1">//获取文件上传对象</span>
<span class="kd">public</span> <span class="n">MultiContext</span> <span class="nf">getMultiContext</span><span class="o">();</span>
<span class="c1">//获取文件上传信息列表 等价于 getMultiContext().parts();</span>
<span class="kd">public</span> <span class="n">Iterable</span><span class="o">&lt;</span><span class="n">MultiPart</span><span class="o">&gt;</span> <span class="nf">multiParts</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//获取当前用户信息 数据类型由@HttpUserType指定</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">currentUser</span><span class="o">();</span>
<span class="c1">//获取模块ID来自@HttpServlet.moduleid()</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getModuleid</span><span class="o">();</span>
<span class="c1">//获取操作ID来自@HttpMapping.actionid()</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getActionid</span><span class="o">();</span>
<span class="c1">//获取sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getSessionid</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">autoCreate</span><span class="o">);</span>
<span class="c1">//更新sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">changeSessionid</span><span class="o">();</span>
<span class="c1">//指定值更新sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">changeSessionid</span><span class="o">(</span><span class="n">String</span> <span class="n">newsessionid</span><span class="o">);</span>
<span class="c1">//使sessionid失效</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">invalidateSession</span><span class="o">();</span>
<span class="c1">//获取所有Cookie对象</span>
<span class="kd">public</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">HttpCookie</span><span class="o">[]</span> <span class="nf">getCookies</span><span class="o">();</span>
<span class="c1">//获取Cookie值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取Cookie值 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取协议名 http、https、ws、wss等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getProtocol</span><span class="o">();</span>
<span class="c1">//获取请求方法 GET、POST等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getMethod</span><span class="o">();</span>
<span class="c1">//获取Content-Type的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//获取请求内容的长度, 为-1表示内容长度不确定</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//获取Connection的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getConnection</span><span class="o">();</span>
<span class="c1">//获取Host的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHost</span><span class="o">();</span>
<span class="c1">//获取请求的URL</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequestURI</span><span class="o">();</span>
<span class="c1">//截取getRequestURI最后的一个/后面的部分</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURILastPath</span><span class="o">();</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的short值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的short值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的int值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的int值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的float值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: float type = request.getRequstURILastPath(0.f); //type = 2.f</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">float</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的long值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的long值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的double值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">double</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">//从prefix之后截取getRequestURI再对"/"进行分隔</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getRequstURIPaths</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的值</span>
<span class="c1">// 例如请求URL /pipes/record/query/name:hello</span>
<span class="c1">// 获取name参数: String name = request.getRequstURIPath("name:", "none");</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的short值</span>
<span class="c1">// 例如请求URL /pipes/record/query/type:10</span>
<span class="c1">// 获取type参数: short type = request.getRequstURIPath("type:", (short)0);</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的short值</span>
<span class="c1">// 例如请求URL /pipes/record/query/type:a</span>
<span class="c1">// 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); type = 10</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的int值</span>
<span class="c1">// 例如请求URL /pipes/record/query/offset:2/limit:50</span>
<span class="c1">// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);</span>
<span class="c1">// 获取limit参数: int limit = request.getRequstURIPath("limit:", 20);</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的int值</span>
<span class="c1">// 例如请求URL /pipes/record/query/offset:2/limit:10</span>
<span class="c1">// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);</span>
<span class="c1">// 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的float值 </span>
<span class="c1">// 例如请求URL /pipes/record/query/point:40.0 </span>
<span class="c1">// 获取time参数: float point = request.getRequstURIPath("point:", 0.0f);</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的long值</span>
<span class="c1">// 例如请求URL /pipes/record/query/time:1453104341363/id:40</span>
<span class="c1">// 获取time参数: long time = request.getRequstURIPath("time:", 0L);</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的long值</span>
<span class="c1">// 例如请求URL /pipes/record/query/time:1453104341363/id:40</span>
<span class="c1">// 获取time参数: long time = request.getRequstURIPath("time:", 0L);</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的double值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/point:40.0 &lt;br&gt;</span>
<span class="c1">// 获取time参数: double point = request.getRequstURIPath("point:", 0.0);</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">//获取所有的header名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getHeaderNames</span><span class="o">();</span>
<span class="c1">// 获取指定的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取所有参数名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getParameterNames</span><span class="o">();</span>
<span class="c1">//获取指定的参数值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", false, 0);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">();</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", needcreate, 0);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", false, maxLimit);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit)</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取翻页对象 http://redkale.org/pipes/records/list/offset:0/limit:20/sort:createtime%20ASC</span>
<span class="c1">//http://redkale.org/pipes/records/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}</span>
<span class="c1">//以上两种接口都可以获取到翻页对象</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取HTTP上下文对象</span>
<span class="kd">public</span> <span class="n">HttpContext</span> <span class="nf">getContext</span><span class="o">();</span>
<span class="c1">//获取所有属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="nf">getAttributes</span><span class="o">();</span>
<span class="c1">//获取指定属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//删除指定属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//设置属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取request创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="o">}</span>
</pre></div>
<p id="net_httpresponse">&nbsp;&nbsp;<b>. HttpResponse 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpResponse</span> <span class="o">{</span>
<span class="c1">//增加Cookie值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addCookie</span><span class="o">(</span><span class="n">HttpCookie</span><span class="o">...</span> <span class="n">cookies</span><span class="o">);</span>
<span class="c1">//增加Cookie值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addCookie</span><span class="o">(</span><span class="n">Collection</span><span class="o">&lt;</span><span class="n">HttpCookie</span><span class="o">&gt;</span> <span class="n">cookies</span><span class="o">);</span>
<span class="c1">//创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出</span>
<span class="kd">public</span> <span class="n">AsyncHandler</span> <span class="nf">createAsyncHandler</span><span class="o">();</span>
<span class="c1">//传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">H</span> <span class="kd">extends</span> <span class="n">AsyncHandler</span><span class="o">&gt;</span> <span class="n">H</span> <span class="nf">createAsyncHandler</span><span class="o">(</span><span class="n">Class</span><span class="o">&lt;</span><span class="n">H</span><span class="o">&gt;</span> <span class="n">handlerClass</span><span class="o">);</span>
<span class="c1">//设置状态码</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setStatus</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">);</span>
<span class="c1">//获取状态码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getStatus</span><span class="o">();</span>
<span class="c1">//获取 ContentType</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//设置 ContentType</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setContentType</span><span class="o">(</span><span class="n">String</span> <span class="n">contentType</span><span class="o">);</span>
<span class="c1">//获取内容长度</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//设置内容长度</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setContentLength</span><span class="o">(</span><span class="kt">long</span> <span class="n">contentLength</span><span class="o">);</span>
<span class="c1">//设置Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//添加Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//添加Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addHeader</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="o">?&gt;</span> <span class="n">map</span><span class="o">);</span>
<span class="c1">//跳过header的输出</span>
<span class="c1">//通常应用场景是调用者的输出内容里已经包含了HTTP的响应头信息因此需要调用此方法避免重复输出HTTP响应头信息。</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">skipHeader</span><span class="o">();</span>
<span class="c1">//异步输出指定内容</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">sendBody</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">,</span> <span class="n">A</span> <span class="n">attachment</span><span class="o">,</span> <span class="n">AsyncHandler</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">A</span><span class="o">&gt;</span> <span class="n">handler</span><span class="o">);</span>
<span class="c1">//异步输出指定内容</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">sendBody</span><span class="o">(</span><span class="n">ByteBuffer</span><span class="o">[]</span> <span class="n">buffers</span><span class="o">,</span> <span class="n">A</span> <span class="n">attachment</span><span class="o">,</span> <span class="n">AsyncHandler</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">A</span><span class="o">&gt;</span> <span class="n">handler</span><span class="o">);</span>
<span class="c1">//关闭HTTP连接如果是keep-alive则不强制关闭</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">();</span>
<span class="c1">//强制关闭HTTP连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span><span class="o">...</span> <span class="n">objs</span><span class="o">);</span>
<span class="c1">//将RetResult对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">service</span><span class="o">.</span><span class="na">RetResult</span> <span class="n">ret</span><span class="o">);</span>
<span class="c1">//将RetResult对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">service</span><span class="o">.</span><span class="na">RetResult</span> <span class="n">ret</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将HttpResult的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpResult</span> <span class="n">result</span><span class="o">);</span>
<span class="c1">//将HttpResult的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">HttpResult</span> <span class="n">result</span><span class="o">)</span> <span class="o">;</span>
<span class="c1">//将指定字符串以响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">String</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//以指定响应码附带内容输出, message 可以为null</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">,</span> <span class="n">String</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//以304状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish304</span><span class="o">();</span>
<span class="c1">//以404状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish404</span><span class="o">();</span>
<span class="c1">//将指定byte[]按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">bs</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定文件按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">File</span> <span class="n">file</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//将文件按指定文件名输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">filename</span><span class="o">,</span> <span class="n">File</span> <span class="n">file</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//HttpResponse回收时回调的监听方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">recycleListener</span><span class="o">(</span><span class="n">BiConsumer</span><span class="o">&lt;</span><span class="n">HttpRequest</span><span class="o">,</span> <span class="n">HttpResponse</span><span class="o">&gt;</span> <span class="n">recycleListener</span><span class="o">);</span>
<span class="o">}</span>
</pre></div>
<p id="net_websocket">&nbsp;&nbsp;<b>. WebSocket 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">WebSocket</span><span class="o">&lt;</span><span class="n">G</span><span class="o">,</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="c1">//给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//获取用户在线的SNCP节点地址列表不是分布式则返回元素数量为1且元素值为null的列表</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Collection</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">&gt;&gt;</span> <span class="nf">getRpcNodeAddresses</span><span class="o">(</span><span class="kd">final</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取在线用户的详细连接信息</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;&gt;&gt;</span> <span class="nf">getRpcNodeWebSocketAddresses</span><span class="o">(</span><span class="kd">final</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//发送PING消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPing</span><span class="o">();</span>
<span class="c1">//发送PING消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//发送PONG消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户多连接模式</span>
<span class="kd">protected</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">WebSocket</span><span class="o">&gt;</span> <span class="nf">getLocalWebSockets</span><span class="o">(</span><span class="n">G</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户单连接模式</span>
<span class="kd">protected</span> <span class="n">WebSocket</span> <span class="nf">findLocalWebSocket</span><span class="o">(</span><span class="n">G</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取当前进程节点所有在线的WebSocket</span>
<span class="kd">protected</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">WebSocket</span><span class="o">&gt;</span> <span class="nf">getLocalWebSockets</span><span class="o">();</span>
<span class="c1">//返回sessionid, null表示连接不合法或异常,默认实现是request.sessionid(true),通常需要重写该方法</span>
<span class="kd">protected</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="nf">onOpen</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">);</span>
<span class="c1">//创建userid null表示异常 必须实现该方法</span>
<span class="kd">protected</span> <span class="kd">abstract</span> <span class="n">G</span> <span class="nf">createUserid</span><span class="o">();</span>
<span class="c1">//WebSokcet连接成功后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onConnected</span><span class="o">();</span>
<span class="c1">//ping后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">);</span>
<span class="c1">//pong后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">);</span>
<span class="c1">//接收到消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">T</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//接收到文本消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">String</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//接收到二进制消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//关闭的回调方法调用此方法时WebSocket已经被关闭</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClose</span><span class="o">(</span><span class="kt">int</span> <span class="n">code</span><span class="o">,</span> <span class="n">String</span> <span class="n">reason</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//移出当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="n">T</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//给当前WebSocket下的增加属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket所属的userid</span>
<span class="kd">public</span> <span class="n">G</span> <span class="nf">userid</span><span class="o">();</span>
<span class="c1">//获取当前WebSocket的会话ID 不会为null</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">getSessionid</span><span class="o">();</span>
<span class="c1">//获取客户端直接地址, 当WebSocket连接是由代理服务器转发的则该值固定为代理服务器的IP地址</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端真实地址 同 HttpRequest.getRemoteAddr()</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取WebSocket创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="c1">//获取最后一次发送消息的时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLastSendTime</span><span class="o">();</span>
<span class="c1">//显式地关闭WebSocket</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">close</span><span class="o">();</span>
<span class="o">}</span>
</pre></div>
<h3><a id="net_sncp" class="anchor" href="#" aria-hidden="true"></a>SNCP 协议</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP(Service Node Communicate Protocol)协议是Redkale独有的一种传输协议用于进程之间的通信即请求方的<a href="service.html#service_remote" target="_blank">远程模式Service</a>与响应方的Service之间的通信。是RPC(远程过程调用协议)的同类型协议主要区别在于Redkale里SNCP几乎是透明的写一个普通的Service通过配置即可实现远程调用而不需要专门针对远程写接口。SNCP服务的配置与HTTP差不多只是SNCP不需要ServletSncpServlet是通过Service动态生成的。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP的数据包分包头和包体。包头描述请求的Service信息请求包的包体描述参数的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>,响应包的包体描述回调的参数对象和结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;包头长度固定,其结构如下:
</p>
<table style="margin: auto;">
<tr><th>字 段</th><th>占用字节数</th><th>描 述</th></tr>
<tr><td>序列号</td><td style="text-align: center;">8</td><td>请求的唯一序列号</td></tr>
<tr><td>包头长度</td><td style="text-align: center;">2</td><td>值固定为60</td></tr>
<tr><td>Service版本号</td><td style="text-align: center;">4</td><td>值为Service.version()</td></tr>
<tr><td>Service资源hash值</td><td style="text-align: center;">16</td><td>Service资源名class.getName():@Resource.name()的MD5值</td></tr>
<tr><td>Service方法hash值</td><td style="text-align: center;">16</td><td>Service方法method.toString()的MD5值</td></tr>
<tr><td>发送方地址</td><td style="text-align: center;">6</td><td>前4字节为地址后2字节为端口号</td></tr>
<tr><td>包体长度</td><td style="text-align: center;">4</td><td>整个包体的长度</td></tr>
<tr><td>结果码</td><td style="text-align: center;">4</td><td>请求方的值固定为0响应方的值视为错误码为0表示成功非0为失败。</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;包体数据结构为 ([参数序号][参数BSON值])* N + [0][结果对象BSON]。 其中参数序号从1开始只有当Service的方法存在<a href="service.html#service_dyncall" target="_blank">@RpcCall回调</a>才会有参数<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>序号为0表示为结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>。若方法为<font color="blue">void</font>返回类型,则不存在结果对象<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>
</p>
<h3><a id="net_diy" class="anchor" href="#" aria-hidden="true"></a>自定义协议</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议的网络框架包含五种对象: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context &nbsp;&nbsp;&nbsp;&nbsp;: 协议上下文对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Request &nbsp;&nbsp;&nbsp;: 服务请求对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response : 服务响应对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Servlet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务逻辑处理对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务监听对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常自定义协议需要继承上面五种对象类同时为了让Redkale能识别和加载自定义协议服务需要继承 <b>org.redkale.boot.NodeServer</b> 并指明 <b>@NodeProtocol</b>,实现可以参考 <a href="https://github.com/redkale/redkale-plugins/tree/master/src/org/redkalex/socks" target="_blank" >基于SOCKS5协议的反向代理服务器</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?b4e05d7de8b5f3401dd93e3c6b35ffa5";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>