From e6486a0f6b3ade0dc92e9ddc1fb9e515e814eb68 Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Fri, 12 May 2017 14:17:27 +0800 Subject: [PATCH] --- net.html | 20 ++++++++++---------- redkale.html | 2 +- service.html | 38 +++++++++++++++++++------------------- source.html | 37 +++++++++++++++++++++---------------- 4 files changed, 51 insertions(+), 46 deletions(-) diff --git a/net.html b/net.html index 6876e0696..146bcb459 100644 --- a/net.html +++ b/net.html @@ -37,10 +37,10 @@                 7、内置WebSocket的集群与组功能,且提供伪WebSocket连接功能。
                8、HttpResponse只能异步输出。

-

        编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, Redkale也提供了更友好的基类 org.redkale.net.http.HttpBaseServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类,这样方便以后加入类似javax.servlet.Filter的功能。

+

        编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类,这样方便以后加入类似javax.servlet.Filter的功能。

        一个典型的BaseSerlvet实现:

-
public class BaseSerlvet extends org.redkale.net.http.HttpBaseServlet {
+            
public class BaseSerlvet extends org.redkale.net.http.HttpServlet {
 
     protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
 
@@ -69,7 +69,7 @@
     //在调用authenticate之前调用, 返回false表示请求不合法
     //该方法可以用于判断请求源是否合法或加入一些全局的拦截操作
     @Override
-    public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
+    public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
         if (!request.getHeader("User-Agent", "").contains("Redkale-Agent")) {  //只用移动APP的接口可以判断User-Agent是否正确
             response.addHeader("retcode", "10001");
             response.addHeader("retmessage", "User-Agent error");
@@ -77,32 +77,32 @@
             return;
         }
         //可以加上一些统计操作
-        if (fine) response.setRecycleListener((req, resp) -> {  //记录处理时间太长的请求操作
+        if (fine) response.recycleListener((req, resp) -> {  //记录处理时间太长的请求操作
                 long e = System.currentTimeMillis() - request.getCreatetime();
                 if (e > 500) logger.fine("耗时居然用了 " + e + " 毫秒. 请求为: " + req);
             });
-        next.execute(request, response);
+        response.nextEvent();
     }
 
     //标记为@AuthIgnore 的方法将不会调用authenticate方法
     //一般用于判断用户的登录态, 返回false表示鉴权失败
-    //moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@WebMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值
+    //moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@HttpMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值
     @Override
-    public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
+    public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
         UserInfo info = currentUser(request);
         if (info == null) {
             response.finishJson(RetCodes.retResult(RetCodes.RET_USER_UNLOGIN));
             return;
-        } else if (!info.checkAuth(module, actionid)) {
+        } else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
             response.finishJson(RetCodes.retResult(RetCodes.RET_USER_AUTH_ILLEGAL));
             return;
         }
-        next.execute(request, response);
+        response.nextEvent();
     }
 }
                 
-

        继承HttpBaseServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能, 一个典型的操作用户HttpServlet:

+

        继承HttpServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能, 一个典型的操作用户HttpServlet:

@WebServlet(value = {"/user/*"}, comment = "用户模块服务")  //拦截所有 /user/ 开头的请求
 public class UserServlet extends BaseSerlvet {
 
diff --git a/redkale.html b/redkale.html
index b4e78e9cb..48ac93a4a 100644
--- a/redkale.html
+++ b/redkale.html
@@ -633,7 +633,7 @@
         
         <!-- 
            REST的核心配置项, 存在[rest]节点则Server启动时会加载REST服务, 当Server为SNCP协议时,则SncpServer会变成REST的HttpServer, 节点可以多个
-           base:     REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
+           base:     REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.RestHttpServlet。
            autoload:默认值"true"  默认值. 加载当前server所能使用的Servce对象;    
            mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
            includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
diff --git a/service.html b/service.html
index a6e8c7187..fbd7ac20c 100644
--- a/service.html
+++ b/service.html
@@ -290,7 +290,7 @@
             

        生成远程模式Service时发现参数带有@RpcCall注解的方法,在远程调用返回结果时会进行回调处理。

Service REST

-

        RestService提供类似Spring Boot的功能。开启REST功能的HTTP Server在实例化标记为@RestService的Service后自动生成对应的HttpServlet,免去开发人员编写HttpServlet的工作量。RestService生成的HttpServlet均是RestHttpServlet的子类。主要通过@RestService@RestMapping@RestParam这三个注解来实现,同时为了获取其他类型的参数也有@RestAddress@RestCookie@RestHeader@RestSessionidRestOutput 提供其扩展功能。

+

        RestService提供类似Spring Boot的功能。开启REST功能的HTTP Server在实例化标记为@RestService的Service后自动生成对应的HttpServlet,免去开发人员编写HttpServlet的工作量。RestService生成的HttpServlet均是RestHttpServlet的子类。主要通过@RestService@RestMapping@RestParam这三个注解来实现,同时为了获取其他类型的参数也有@RestAddress@RestCookie@RestHeader@RestSessionid@RestBody 提供其扩展功能。

    @RestService :

@@ -354,15 +354,15 @@ //默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前) String name() default ""; - String comment() default ""; //备注描述, 对应@WebMapping.comment + String comment() default ""; //备注描述, 对应@HttpMapping.comment boolean authignore() default true; //是否鉴权,默认不鉴权, 对应@AuthIgnore int cacheseconds() default 0; //结果缓存的秒数, 为0表示不缓存, 对应@HttpCacheable.seconds - int actionid() default 0; //操作ID值,鉴权时用到, 对应@WebMapping.actionid + int actionid() default 0; //操作ID值,鉴权时用到, 对应@HttpMapping.actionid - String[] methods() default {}; //允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebMapping.methods + String[] methods() default {}; //允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@HttpMapping.methods }
@@ -383,7 +383,7 @@ int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制 - String comment() default ""; //备注描述, 对应@WebMapping.comment + String comment() default ""; //备注描述, 对应@HttpMapping.comment }

        开启REST功能的步骤很简单:在 application.xml<server> 节点下增加<rest>指明RestHttpServlet的子类。

@@ -391,13 +391,13 @@
         <!-- 
            REST的核心配置项, 存在[rest]节点则Server启动时会加载REST服务, 当Server为SNCP协议时,则SncpServer会变成REST的HttpServer, 节点可以多个
-           base:     REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
+           base:     REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.RestHttpServlet。
            autoload:默认值"true"  默认值. 加载当前server所能使用的Servce对象;    
            mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
            includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
            excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
         -->
-        <rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
+        <rest base="org.redkale.net.http.RestHttpServlet" mustsign="true" autoload="true" includes="" excludes="">
             <!-- 
                value:  Service类名,列出的表示必须被加载的Service对象
                ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
@@ -428,7 +428,7 @@
 
     //普通鉴权
     @Override
-    public void authenticate(int module, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
+    public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
         UserInfo info = currentUser(request);
         if (info == null) {
             response.finishJson(RET_UNLOGIN);
@@ -437,7 +437,7 @@
             response.finishJson(RET_AUTHILLEGAL);
             return;
         }
-        next.execute(request, response);
+        response.nextEvent();
     }
 
 }
@@ -539,8 +539,8 @@
 
     //异步查询单个
     @RestMapping(name = "asyncfind", auth = false, comment = "根据id查找单个Hello对象")
-    public HelloEntity findHello(AsyncHandler handler, @RestParam(name = "#") int id) {  //通过 /pipes/hello/asyncfind/1234 查询对象
-        return source.findAsync(handler, HelloEntity.class, id);
+    public CompletableFuture<HelloEntity> findAsyncHello(@RestParam(name = "#") int id) {  //通过 /pipes/hello/asyncfind/1234 查询对象
+        return source.findAsync(HelloEntity.class, id);
     }
 }
                 
@@ -559,7 +559,7 @@ private Map<String, HelloService> _servicemap; @AuthIgnore - @WebMapping(url = "/hello/create", comment = "创建Hello对象") + @HttpMapping(url = "/hello/create", comment = "创建Hello对象") @WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") public void create(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); @@ -572,7 +572,7 @@ } @AuthIgnore - @WebMapping(url = "/hello/delete/", comment = "根据id删除Hello对象") + @HttpMapping(url = "/hello/delete/", comment = "根据id删除Hello对象") @WebParam(name = "#", type = int.class, comment = "Hello对象id") public void delete(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); @@ -582,7 +582,7 @@ } @AuthIgnore - @WebMapping(url = "/hello/update", comment = "修改Hello对象") + @HttpMapping(url = "/hello/update", comment = "修改Hello对象") @WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") public void update(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); @@ -594,7 +594,7 @@ } @AuthIgnore - @WebMapping(url = "/hello/query", comment = "查询Hello对象列表") + @HttpMapping(url = "/hello/query", comment = "查询Hello对象列表") @WebParam(name = "bean", type = HelloBean.class, comment = "过滤条件") public void query(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); @@ -609,7 +609,7 @@ } @AuthIgnore - @WebMapping(url = "/hello/find/", comment = "根据id查找单个Hello对象") + @HttpMapping(url = "/hello/find/", comment = "根据id查找单个Hello对象") @WebParam(name = "#", type = int.class, comment = "Hello对象id") public void find(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); @@ -619,12 +619,12 @@ } @AuthIgnore - @WebMapping(url = "/hello/asyncfind/", comment = "根据id查找单个Hello对象") + @HttpMapping(url = "/hello/asyncfind/", comment = "根据id查找单个Hello对象") @WebParam(name = "#", type = int.class, comment = "Hello对象id") public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException { HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, "")); int id = Integer.parseInt(req.getRequstURILastPath()); - service.findHello(resp.createAsyncHandler(), id); + resp.finishJson(service.findAsyncHello(id)); } } @@ -638,7 +638,7 @@ if (handler != null) handler.completed(null, values); }

-         如上图DataSourceService的源码,当DataSource为本地实例时,异步接口(含AsyncHandler参数或返回类型为CompletableFuture)与同步接口执行流程相同。当DataSource为远程模式时,调用异步接口时,通信接口发到远程服务器时AsyncHandler参数的值传null,返回数据后再调用本地的AsyncHandler参数值执行。
+         如上图源码,异步接口(含AsyncHandler参数或返回类型为CompletableFuture)与同步接口执行流程相同。当Service为远程模式时,调用异步接口时,通信接口发到远程服务器时AsyncHandler参数的值传null,返回数据后再调用本地的AsyncHandler参数值执行。
        异步调用方式是提高服务并发性的有效手段,特别是在远程模式Service比较多的情况下效果更明显。以HTTP服务为例,在Tomcat刚刚改版成NIO的时候,网上随处可见都是大谈NIO性能比BIO多好,认为BIO与NIO的不同,是BIO往往会引入多线程,每个连接一个单独的线程;NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。而事实上呢,通常还是通过增加线程数来提高并发量。为什么NIO作用不大呢, 因为一个HTTP动态请求耗时最多是业务逻辑层,特别是操作数据库,IO操作的耗时比重小得多,只有在静态资源请求这种纯IO操作才能体现NIO、AIO(NIO.2)的优势。举例一个简单的数据查询请求,采用BIO方式耗时(为了方便比较将所耗时间扩大几倍)如下:
                1、服务器TCP连接开始到进入HttpServlet,耗时 10ms
                2、用户态判断和参数验证,                         耗时 10ms
diff --git a/source.html b/source.html index 327165afe..54cb1aade 100644 --- a/source.html +++ b/source.html @@ -404,14 +404,19 @@

        以上是个简单的范例,用于用户模块存放sessionid。

persistence.xml 配置说明

-
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
+            
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
 <persistence>	
     <!-- 系统基本库 -->
-    <persistence-unit name="demouser">
+    <persistence-unit name="demouser">
         <!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
         <shared-cache-mode>NONE</shared-cache-mode>
         <properties>
-            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
+            <!-- 
+                DataSource的实现类,没有设置默认为org.redkale.source.DataJdbcSource的实现,使用常规基于JDBC的数据库驱动一般无需设置
+            -->
+            <property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
+            
+            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
             <!-- 
                 javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。 
                 为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
@@ -423,32 +428,32 @@
                 因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
                 并且如果JDBC驱动是以上几个版本,javax.persistence.jdbc.driver属性都可以省略,Redkale会根据javax.persistence.jdbc.url的值来识别驱动
             -->
-            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
-            <property name="javax.persistence.jdbc.user" value="root"/>
-            <property name="javax.persistence.jdbc.password" value="123456"/>
+            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
+            <property name="javax.persistence.jdbc.user" value="root"/>
+            <property name="javax.persistence.jdbc.password" value="123456"/>
             
             <!-- 最大连接数,默认值:CPU数*16  -->
-            <property name="javax.persistence.connections.limit" value="32"/>
+            <property name="javax.persistence.connections.limit" value="32"/>
             
             <!--  包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句 -->
-            <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
-            <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
+            <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
+            <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
             
             <!--  复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
-            <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
-            <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
+            <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
+            <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
            
         </properties>
     </persistence-unit>
     <!-- IM消息库 -->
-    <persistence-unit name="demoim">
+    <persistence-unit name="demoim">
         <shared-cache-mode>NONE</shared-cache-mode>
         <properties>
             <!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
-            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
-            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
-            <property name="javax.persistence.jdbc.user" value="root"/>
-            <property name="javax.persistence.jdbc.password" value="123456"/>
+            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
+            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
+            <property name="javax.persistence.jdbc.user" value="root"/>
+            <property name="javax.persistence.jdbc.password" value="123456"/>
         </properties>
     </persistence-unit>
 </persistence>