REST插件介绍

+

+         org.redkalex.rest 是基于HTTP服务的REST插件,提供了很简单的REST服务接口方便开发。REST根据加载的Service组件自动生成对应的HttpServlet。其接口比Spring Boot之类的REST服务框架要简化得多,不需要进行注解配置也可以按REST服务加载。 +

-

敬请期待……
+

快速上手

+

+         为了让REST生效,必须配置 application.xml 中 HTTP 的 <server> 节点的nodeInterceptor属性值为 org.redkalex.rest.RestNodeInterceptor
+         同时必须在<server> 节点 里增加 <rest> 子节点。配置介绍如下:
+

+
<application port="5001">   
+    
+    <resources>  
+        <!-- ... -->
+    </resources> 
+    <!-- 
+           nodeInterceptor: 值必须要是 org.redkalex.rest.RestNodeInterceptor,且只能配置在protocol="HTTP"的server节点上,REST服务才会生效。
+    -->
+    <server protocol="HTTP" port="6060" nodeInterceptor="org.redkalex.rest.RestNodeInterceptor"> 
+        <!-- 
+           REST的核心配置项
+           base:     REST服务的BaseServlet,必须是 org.redkalex.rest.RestHttpServlet 的子类,该属性值没有默认值,必须指定。
+           autoload:默认值"true"  默认值. 加载当前server所能使用的Servce对象;    
+           mustsign:默认值"true" 是否只加载标记为RestController的Service类,默认值为true
+           includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
+           excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
+        -->
+        <rest base="org.redkalex.test.rest.SimpleRestServlet" mustsign="true" autoload="true" includes="" excludes="">
+            <!-- 
+               value:  Service类名,列出的表示必须被加载的Service对象, 且对象的Resource资源名称只能是""。
+            -->
+            <service value="com.xxx.XXXXService"/>
+        </rest>
+        <!-- 其他配置... -->
+    </server>
+</application>
+                
+

+         通常配置都需要编写一个 org.redkalex.rest.RestHttpServlet 子类,主要用于获取当前用户信息和鉴权,且必须指定具体的User对象类。开发者的实现类可以参考 redkale-demo 中的BaseServlet类,以下是一个简单的范例:
+

+
public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
+
+    @Resource
+    private UserService userService;
+
+    //获取当前用户信息
+    @Override
+    protected UserInfo currentUser(HttpRequest req) throws IOException {
+        String sessionid = req.getSessionid(false);
+        if (sessionid == null || sessionid.isEmpty()) return null;
+        return userService.current(sessionid);
+    }
+
+    //普通鉴权
+    @Override
+    public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException {
+        UserInfo info = currentUser(request);
+        if (info == null) {
+            response.addHeader("retcode", RetCodes.RET_USER_UNLOGIN);
+            response.addHeader("retmessage", "Not Login");
+            response.setStatus(203);
+            response.finish("{'success':false, 'message':'Not Login'}");
+            return false;
+        } else if (!info.checkAuth(module, actionid)) { // 根据module、actionid进行鉴权
+            response.addHeader("retcode", RetCodes.RET_USER_AUTH_ILLEGAL);
+            response.addHeader("retmessage", "No Authority");
+            response.setStatus(203);
+            response.finish("{'success':false, 'message':'No Authority'}");
+            return false;
+        }
+        return true;
+    }
+
+}
+                
+ + +

+         编写完 org.redkalex.rest.RestHttpServlet 子类后就需要对Service进行设置,设置需要三大注解:@RestController、@RestMapping、@RestParam。
+
@RestController :
+

+
/**
+ * 只能依附在Service类上,value默认为Service的类名去掉Service字样的字符串 (如HelloService,的默认路径为 hello)。
+ */
+@Target({TYPE})
+public @interface RestController {
+
+    boolean ignore() default false; //是否屏蔽该类的转换
+
+    String value() default ""; //模块名, 只能是模板名,不能含特殊字符
+
+    boolean repair() default true; //同@WebServlet的repair属性
+
+    int module() default 0; //模块ID值,鉴权时用到
+
+}
+                
+

+
@RestMapping :
+

+
/**
+ * 只能依附在Service实现类的public方法上
+ * value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService,的默认路径为/hello)。
+ */
+@Target({METHOD})
+public @interface RestMapping {
+
+    boolean ignore() default false; //是否屏蔽该方法的转换
+
+    //请求的方法名, 不能含特殊字符
+    //默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前)
+    String name() default "";
+
+    boolean authignore() default true; //是否跳过鉴权,默认跳过 
+
+    int actionid() default 0; //操作ID值,鉴权时用到
+
+    String contentType() default "";  //设置Response的ContentType 默认值为 text/plain; charset=utf-8
+
+    String jsvar() default ""; //以application/javascript输出对象是指明js的对象名,该值存在时则忽略contentType()的值
+}
+                
+ +

+
@RestParam :
+

+
/**
+ * 只能依附在Service类的方法的参数上, http请求的参数名
+ */
+@Target({PARAMETER})
+public @interface RestParam {
+
+    String value(); //参数名
+
+}
+                
+ + +

+         REST的设置方式有两大种: 一种是采用默认REST注解,一种是显式的设置。
+ 第一种方式需要开发者对Service中的方法命名需要遵循一定规则, 如下范例,模块为Hello,Service类命名为HelloService,增删改查的方法采用createHello、deleteHello、updateHello、queryHello或其他xxxHello命名。REST插件加载任何没有标记@RestController、@RestMapping、@RestParam 的Service将按照一定规则生成默认值:
+         1、@RestController.value() 默认值为Service类名的小写化并去掉service字样, 视为模块名
+         2、@RestMapping.name() 默认值为Service的方法名小写化并去掉模块名字样
+         2、@RestParam.value() 如果方法名以find、delete开头且方法的参数只有一个且参数类型是基本数据类型或String,则默认值为"#";若使用Java 8中带上 -parameters 编译项的新特性,默认值为参数名, 若没使用新特性则采用bean、bean2、bean3...的命名规则。
+

+
/**
+ * 类说明:
+ * Flipper : Source组件中的翻页对象, 只要Service方法中的参数类与该类相同,则不需要设定 @RestParam
+ * UserInfo :当前用户类, 只要Service方法中的参数类与该类相同,则不需要设定 @RestParam
+ * HelloEntity: Hello模块的实体类
+ * HelloBean: Hellow模块实现FilterBean的过滤Bean类
+ *
+ */
+@RestController(value = "hello", module = 0, repair = true, ignore = false)
+public class HelloService implements Service {
+
+    @Resource
+    private DataSource source;
+
+    //增加记录
+    @RestMapping(name = "create", authignore = true)
+    public RetResult<HelloEntity> createHello(UserInfo info, @RestParam("bean") HelloEntity entity) { //通过 /hello/create?bean={...} 增加对象
+        entity.setCreator(info == null ? 0 : info.getUserid()); //设置当前用户ID
+        entity.setCreatetime(System.currentTimeMillis());
+        source.insert(entity);
+        return new RetResult<>(entity);
+    }
+
+    //删除记录
+    @RestMapping(name = "delete", authignore = true)
+    public void deleteHello(@RestParam("#") int id) { //通过 /hello/delete/1234 删除对象
+        source.delete(HelloEntity.class, id);
+    }
+
+    //修改记录
+    @RestMapping(name = "update", authignore = true)
+    public void updateHello(@RestParam("bean") HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
+        entity.setUpdatetime(System.currentTimeMillis());
+        source.update(entity);
+    }
+
+    //查询列表
+    @RestMapping(name = "query", authignore = true)
+    public Sheet<HelloEntity> queryHello(@RestParam("bean") HelloBean bean, Flipper flipper) { //通过 /hello/query/start:0/size:20?bean={...} 查询列表
+        return source.querySheet(HelloEntity.class, flipper, bean);
+    }
+
+    //查询单个
+    @RestMapping(name = "find", authignore = true)
+    public HelloEntity findHello(@RestParam("#") int id) {  //通过 /hello/find/1234 查询对象
+        return source.find(HelloEntity.class, id);
+    }
+}
+                
+

+         根据默认命名规则可以看出,以上范例生成的RestServlet与去掉所有@RestController、@RestMapping、@RestParam后的Service生成的是完全相同的。