50 Commits
1.3.0 ... 1.4.0

Author SHA1 Message Date
Redkale
7ea740edf1 Update RestParam.java 2017-02-02 17:23:02 +08:00
Redkale
716f4e6934 Update RestParam.java 2017-02-02 17:21:43 +08:00
Redkale
90ab302667 2017-01-18 22:55:29 +08:00
Redkale
4695949362 2017-01-18 19:04:57 +08:00
Redkale
4827893a0d 2017-01-18 10:54:02 +08:00
Redkale
9276f220b0 2017-01-17 20:12:38 +08:00
Redkale
4071a5d165 2017-01-17 13:37:34 +08:00
Redkale
da0ff24af6 2017-01-17 13:28:23 +08:00
Redkale
afef635146 2017-01-17 13:23:11 +08:00
Redkale
eda9d1c780 2017-01-16 14:11:35 +08:00
Redkale
4b5749bc60 2017-01-16 11:50:19 +08:00
Redkale
6bb23008c2 2017-01-11 10:37:53 +08:00
Redkale
7746971b60 2017-01-11 10:35:56 +08:00
Redkale
bc20c82fef 2017-01-11 10:24:49 +08:00
Redkale
fff70ed241 2017-01-11 10:03:43 +08:00
Redkale
c590d45ce0 2017-01-10 20:01:09 +08:00
Redkale
8bab9ad22b 2017-01-10 18:10:02 +08:00
Redkale
3c457dad2a 2017-01-10 16:42:41 +08:00
Redkale
eaae598234 2017-01-09 15:05:14 +08:00
Redkale
606faf1bf8 2017-01-09 10:38:34 +08:00
Redkale
ae9aa94323 2017-01-09 10:27:13 +08:00
Redkale
2e41e44294 2016-12-29 11:15:21 +08:00
Redkale
d806d9d6ff 2016-12-29 10:34:43 +08:00
Redkale
1260736c14 2016-12-26 17:31:34 +08:00
Redkale
08c5cbbbf3 2016-12-26 15:16:20 +08:00
Redkale
af0726cd79 2016-12-25 15:47:46 +08:00
Redkale
ce2279030d 2016-12-25 15:45:41 +08:00
Redkale
83aba2ebee 2016-12-23 18:20:04 +08:00
Redkale
5c11742b51 2016-12-17 17:14:22 +08:00
Redkale
5295e04275 2016-12-15 14:38:33 +08:00
Redkale
47f723e63b 2016-12-15 09:54:23 +08:00
Redkale
54956e47d2 2016-12-15 09:11:28 +08:00
Redkale
b2cbdf6642 2016-12-14 20:43:41 +08:00
Redkale
989d1c6db9 解决updateColumn多表关联更新的BUG 2016-12-11 20:40:29 +08:00
Redkale
e139b0cc5d 2016-12-11 19:56:33 +08:00
Redkale
66261e98b5 2016-12-11 19:22:12 +08:00
Redkale
d9a268d30a 2016-12-11 19:10:51 +08:00
Redkale
a8bc50a947 2016-12-09 17:06:26 +08:00
Redkale
6aa96daae2 2016-12-09 14:17:16 +08:00
Redkale
293805a55e 2016-12-09 11:17:03 +08:00
Redkale
8b6319888c Update README.md 2016-12-02 11:10:54 +08:00
Redkale
408676e97a Update README.md 2016-12-02 11:09:15 +08:00
Redkale
1fabbae4f6 2016-11-28 10:43:38 +08:00
Redkale
09a5b41d96 2016-11-25 17:20:45 +08:00
Redkale
9d85a4dcaf 2016-11-25 17:06:03 +08:00
Redkale
9bc60c1c47 2016-11-25 15:53:37 +08:00
Redkale
92aff864ef 2016-11-25 11:40:49 +08:00
Redkale
254e2e8ccd 2016-11-25 11:28:11 +08:00
Redkale
2480d127ac 2016-11-25 10:16:58 +08:00
Redkale
cc3d82e864 2016-11-25 10:09:06 +08:00
45 changed files with 1745 additions and 301 deletions

View File

@@ -8,14 +8,14 @@
<li>提供HTTP服务同时内置JSON功能与限时缓存功能</li>
<li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li>
<li>提供分布式与集中式部署的无缝切换</li>
<li>提供类似JPA功能包含数据缓存自动同步与简洁的数据层操作接口</li>
<li>提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
<li>可以动态修改已依赖注入的资源</li>
</ol>
<strong>Redkale 设计理念</strong>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,不仅是使用了Java8的新语法,更多是设计上与主流框架有不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量而且也可以动态更改已注入的资源。Spring提倡控制反转思想偏偏自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者不想使用Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务开发者想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现。这其实包含了控制反转的思想让框架里的零件可以让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单也是Redkale的一个特点并非不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的数字计算不是Java的专长同时一个稍好的提供HTTP服务的架构不会将Java动态服务器放在最前端通常前面会放nginx或apache除了负载均衡还能静动分离既然Java服务器前面有C写的服务器那么HTTPS的加解密就应该交给前面的服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP(如果初级程序员还花大量时间去学习基于JSP的Struts或Spring MVC框架就有点跟不上时代了)。Redkale在功能上做了筛选不会只因为迎合主流而提供,而是以良好的设计思想为指导。这是Redkale很重要的一个思想
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,Redkale在接口定义上使用了Java 8大量的新语法,接口有默认实现、接口带静态方法、重复注解等特性,同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想,让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单体现了Redkale的简易性,而并非不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的计算不是Java的专长通常提供HTTP服务的架构不会将Java动态服务器放在最前端而是在前方会放nginx或apache除了负载均衡还能静动分离因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维
</p>

View File

@@ -137,7 +137,7 @@
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes="">
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
<!--
value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false

View File

@@ -0,0 +1,69 @@
/** *****************************************************************************
* Copyright (c) 2011 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
*
***************************************************************************** */
package javax.persistence;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Used in schema generation to specify creation of an index.
* <p>
* Note that it is not necessary to specify an index for a primary key,
* as the primary key index will be created automatically.
*
* <p>
* The syntax of the <code>columnList</code> element is a
* <code>column_list</code>, as follows:
*
* <pre>
* column::= index_column [,index_column]*
* index_column::= column_name [ASC | DESC]
* </pre>
*
* <p>
* If <code>ASC</code> or <code>DESC</code> is not specified,
* <code>ASC</code> (ascending order) is assumed.
*
* @since Java Persistence 2.1
*
*/
@Target({})
@Retention(RUNTIME)
public @interface Index {
/**
* (Optional) The name of the index; defaults to a provider-generated name.
*
* @return String
*/
String name() default "";
/**
* (Required) The names of the columns to be included in the index,
* in order.
*
* @return String
*/
String columnList();
/**
* (Optional) Whether the index is unique.
*
* @return boolean
*/
boolean unique() default false;
}

View File

@@ -59,4 +59,29 @@ public @interface Table {
*/
String catalog() default "";
/**
* (Optional) Unique constraints that are to be placed on
* the table. These are only used if table generation is in
* effect. These constraints apply in addition to any constraints
* specified by the <code>Column</code> and <code>JoinColumn</code>
* annotations and constraints entailed by primary key mappings.
* <p>
* Defaults to no additional constraints.
* @return UniqueConstraint[]
*/
UniqueConstraint[] uniqueConstraints() default {};
/**
* (Optional) Indexes for the table. These are only used if
* table generation is in effect. Note that it is not necessary
* to specify an index for a primary key, as the primary key
* index will be created automatically.
*
* @return indexes
* @since Java Persistence 2.1
*/
Index[] indexes() default {};
String comment() default "";
}

View File

@@ -0,0 +1,56 @@
/** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0
*
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Specifies that a unique constraint is to be included in
* the generated DDL for a primary or secondary table.
*
* <pre>
* Example:
* &#064;Entity
* &#064;Table(
* name="EMPLOYEE",
* uniqueConstraints=
* &#064;UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
* )
* public class Employee { ... }
* </pre>
*
* @since Java Persistence 1.0
*/
@Target({})
@Retention(RUNTIME)
public @interface UniqueConstraint {
/** (Optional) Constraint name. A provider-chosen name will be chosen
* if a name is not specified.
*
* @return String
* @since Java Persistence 2.0
*/
String name() default "";
/** (Required) An array of the column names that make up the constraint.
*
* @return String[]
*/
String[] columnNames();
}

View File

@@ -8,9 +8,10 @@ package org.redkale.boot;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.persistence.Column;
import javax.persistence.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
@@ -31,7 +32,7 @@ public class ApiDocs extends HttpBaseServlet {
public void run() throws Exception {
List<Map> serverList = new ArrayList<>();
Map<String, Map<String, Map<String, String>>> typesmap = new LinkedHashMap<>();
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue;
final Map<String, Object> map = new LinkedHashMap<>();
@@ -62,62 +63,116 @@ public class ApiDocs extends HttpBaseServlet {
List<Map> actionsList = new ArrayList<>();
servletmap.put("actions", actionsList);
for (Method method : servlet.getClass().getMethods()) {
if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
final Map<String, Object> actionmap = new LinkedHashMap<>();
actionmap.put("url", prefix + action.url());
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
actionmap.put("actionid", action.actionid());
actionmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
parammap.put("name", param.name());
parammap.put("radix", param.radix());
parammap.put("type", ptype.getName() + (isarray ? "[]" : ""));
parammap.put("src", param.src());
parammap.put("comment", param.comment());
paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue;
final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionurls = new HashSet<>();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final Map<String, Object> actionmap = new LinkedHashMap<>();
if (actionurls.contains(action.url())) continue;
actionmap.put("url", prefix + action.url());
actionurls.add(action.url());
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
actionmap.put("actionid", action.actionid());
actionmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList);
List<String> results = new ArrayList<>();
for (final Class rtype : action.results()) {
results.add(rtype.getName());
if (typesmap.containsKey(rtype.getName())) continue;
final boolean filter = FilterBean.class.isAssignableFrom(rtype);
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = rtype;
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
final Map<String, Map<String, String>> typemap = new LinkedHashMap<>();
Class loop = ptype;
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Map<String, String> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else {
Comment comment = field.getAnnotation(Comment.class);
Column col = field.getAnnotation(Column.class);
if (col != null) fieldmap.put("comment", col.comment());
FilterColumn fc = field.getAnnotation(FilterColumn.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typemap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap);
}
actionmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
parammap.put("name", param.name());
parammap.put("radix", param.radix());
parammap.put("type", ptype.getName() + (isarray ? "[]" : ""));
parammap.put("src", param.src());
parammap.put("comment", param.comment());
parammap.put("required", param.required());
paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue;
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop);
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typemap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typemap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(ptype.getName(), typemap);
typesmap.put(ptype.getName(), typemap);
}
actionmap.put("result", action.result());
actionsList.add(actionmap);
}
actionmap.put("result", action.result());
actionsList.add(actionmap);
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletmap);
}
@@ -140,7 +195,7 @@ public class ApiDocs extends HttpBaseServlet {
in = new FileInputStream(doctemplate);
}
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("${content}", json);
String content = Utility.read(in).replace("'${content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes("UTF-8"));

View File

@@ -189,6 +189,7 @@ public final class Application {
}
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
logger.log(Level.INFO, "------------------------------- Redkale ------------------------------");
//------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null;

View File

@@ -1,12 +1,12 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8"><title>Document</title>
<meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
<style type="text/css">
body {text-align: center;margin:auto;}
a{text-decoration: none;}
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
.table td,.table th{padding: 0.4rem 1.2rem 0.4rem 1.2rem;border: 1px solid #aaa;}
.table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
.table td {text-align: left;}
.s {font-size: 0.8rem; vertical-align: middle;}
.subtable {border-spacing: 0;border: 0;margin:0;}
@@ -25,11 +25,17 @@
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
html.push('<br/><br/><table class="table" align="center">');
for (var i = 0; i < jsoncontent.servers.length; i++) {
for (var j = 0; j < jsoncontent.servers[i].servlets.length; j++) {
var servlet = jsoncontent.servers[i].servlets[j];
var servlets = jsoncontent.servers[i].servlets;
if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
servlets.sort(function (a, b) {
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
});
}
for (var j = 0; j < servlets.length; j++) {
var servlet = servlets[j];
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>');
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
for (var k = 0; k < servlet.actions.length; k++) {
var action = servlet.actions[k];
html.push(' <tr>');
@@ -47,15 +53,22 @@
if (param.name == '&') {
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
} else {
var c = ' style="font-weight:bold;"';
if (param.src == "HEADER") c = ' style="color:red;font-weight:bold;"';
if (param.src == "COOKIE") c = ' style="color:blue;font-weight:bold;"';
var w = param.required ? "font-weight:bold;" : "";
var c = ' style="' + w + '"';
if (param.src == "HEADER") c = ' style="color:red;' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"';
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
}
}
paramshtml.push('</table>');
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
html.push('<td>' + action.result.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</td>');
var rs = [];
rs.push(action.result.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
var results = action.results || [];
for (var r = 0; r < results.length; r++) {
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
}
html.push('<td>' + rs.join("<br/>") + '</td>');
html.push('</tr>');
}
}
@@ -66,8 +79,20 @@
html.push(' <tr><td colspan="5"><table class="typetable">');
for (var fieldname in classmap[type]) {
var field = classmap[type][fieldname];
var t = field.type.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + (field.comment || '') + '</td></tr>');
var t = field.type.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
t = '<font color=blue>' + t + '</font>';
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map&lt;') === 0) {
t = '<font color=red>' + t + '</font>';
}
var c = (field.comment || '');
if (field.primary) {
c = '【主键】 ' + c;
} else if (!field.updatable) {
c = '【只读】 ' + c;
}
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
}
html.push(' </table></td></tr>');
}
@@ -78,7 +103,7 @@
</script>
<script>
var jsoncontent = ${content};
var jsoncontent = '${content}'; //这里必须要用单引号引起来
document.write(createhtml(jsoncontent));
</script>
</body>

View File

@@ -28,31 +28,53 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Class componentClass;
private final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
try {
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
}
if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
}
@Override
public T[] convertFrom(Reader in) {
final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList();
if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -29,19 +29,30 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
try {
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
}
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
}
@Override
@@ -55,6 +66,17 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.length);
final Type comp = this.componentType;
boolean first = true;

View File

@@ -30,18 +30,29 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
protected Creator<Collection<T>> creator;
private final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
try {
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@@ -49,6 +60,17 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Collection<T> result = this.creator.create();
if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -10,10 +10,12 @@ import java.util.Collection;
/**
* 对象集合的序列化.
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。
* 支持一定程度的泛型。
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 序列化的集合元素类型
*/
@@ -24,17 +26,28 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
try {
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.loadEncoder(t);
this.encoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} else {
this.encoder = factory.getAnyEncoder();
}
}
@@ -49,6 +62,17 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.size());
boolean first = true;
for (Object v : value) {

View File

@@ -88,6 +88,6 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
@Override
public String toString() {
return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + decoder + '}';
return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + (decoder == null ? null : decoder.getClass().getName()) + '}';
}
}

View File

@@ -81,6 +81,6 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
@Override
public String toString() {
return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + encoder + '}';
return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + (encoder == null ? null : encoder.getClass().getName()) + '}';
}
}

View File

@@ -12,7 +12,9 @@ import java.util.Map;
/**
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <K> Map key的数据类型
* @param <V> Map value的数据类型
@@ -28,27 +30,49 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected Creator<Map<K, V>> creator;
private final Decodeable<Reader, K> keyDecoder;
protected final Decodeable<Reader, K> keyDecoder;
private final Decodeable<Reader, V> valueDecoder;
protected final Decodeable<Reader, V> valueDecoder;
private boolean inited = false;
private final Object lock = new Object();
public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0];
this.valueType = pt.getActualTypeArguments()[1];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(this.keyType);
this.valueDecoder = factory.loadDecoder(this.valueType);
} else {
throw new ConvertException("mapdecoder not support the type (" + type + ")");
try {
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0];
this.valueType = pt.getActualTypeArguments()[1];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(this.keyType);
this.valueDecoder = factory.loadDecoder(this.valueType);
} else {
throw new ConvertException("mapdecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public Map<K, V> convertFrom(Reader in) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final int len = in.readMapB();
if (len == Reader.SIGN_NULL) return null;
final Map<K, V> result = this.creator.create();

View File

@@ -27,15 +27,26 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Encodeable<Writer, V> valencoder;
private boolean inited = false;
private final Object lock = new Object();
public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.keyencoder = factory.loadEncoder(pt[0]);
this.valencoder = factory.loadEncoder(pt[1]);
} else {
this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder();
try {
if (type instanceof ParameterizedType) {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.keyencoder = factory.loadEncoder(pt[0]);
this.valencoder = factory.loadEncoder(pt[1]);
} else {
this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@@ -46,6 +57,18 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
out.writeNull();
return;
}
if (this.keyencoder == null || this.valencoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeMapB(values.size());
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {

View File

@@ -89,6 +89,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
}
@Documented
@@ -121,13 +123,16 @@ public abstract class HttpBaseServlet extends HttpServlet {
String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}
/**
* 配合 HttpBaseServlet 使用。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值timeout=15秒)。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
*
* <p>
@@ -145,7 +150,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
*
* @return 超时秒数
*/
int timeout() default 15;
int seconds() default 15;
}
private Map.Entry<String, Entry>[] actions;
@@ -165,9 +170,9 @@ public abstract class HttpBaseServlet extends HttpServlet {
return;
}
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
if (entry.cachetimeout > 0) {//有缓存设置
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
@@ -219,29 +224,37 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>();
Set<String> nameset = new HashSet<>();
for (final Method method : this.getClass().getMethods()) {
//-----------------------------------------------
String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//-----------------------------------------------
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|| paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
HashMap<String, Class> nameset = new HashMap<>();
final Class selfClz = this.getClass();
Class clz = this.getClass();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (final Method method : clz.getMethods()) {
//-----------------------------------------------
String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//-----------------------------------------------
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|| paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
final int actionid = action.actionid();
final String name = action.url().trim();
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
nameset.add(name);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
}
final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = action.actionid();
final String name = action.url().trim();
if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpBaseServlet.class);
return map;
}
@@ -335,9 +348,9 @@ public abstract class HttpBaseServlet extends HttpServlet {
this.servlet = servlet;
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000;
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
this.cacheseconds = hc == null ? 0 : hc.seconds() * 1000;
this.cache = cacheseconds > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
@@ -362,7 +375,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cachetimeout;
public final int cacheseconds;
public final boolean ignore;

View File

@@ -43,7 +43,7 @@ public final class Rest {
EXCLUDERMETHODS.add(m.getName());
}
}
/**
* 用于标记由Rest.createRestServlet 方法创建的RestHttpServlet
*/
@@ -221,9 +221,9 @@ public final class Rest {
av0 = mv.visitAnnotation(authDesc, true);
av0.visitEnd();
}
if (entry.cachetimeout > 0) { //设置 HttpCacheable
if (entry.cacheseconds > 0) { //设置 HttpCacheable
av0 = mv.visitAnnotation(cacheDesc, true);
av0.visit("timeout", entry.cachetimeout);
av0.visit("seconds", entry.cacheseconds);
av0.visitEnd();
}
@@ -262,6 +262,7 @@ public final class Rest {
final Class ptype = param.getType();
String n = null;
String comment = "";
boolean required = true;
int radix = 10;
RestHeader annhead = param.getAnnotation(RestHeader.class);
@@ -297,6 +298,7 @@ public final class Rest {
RestParam annpara = param.getAnnotation(RestParam.class);
if (annpara != null) radix = annpara.radix();
if (annpara != null) comment = annpara.comment();
if (annpara != null) required = annpara.required();
if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
if (n == null && ptype == userType) n = "&"; //用户类型特殊处理
if (n == null) {
@@ -312,7 +314,7 @@ public final class Rest {
&& (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) {
if (ptype.isPrimitive() || ptype == String.class) n = "#";
}
paramlist.add(new Object[]{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie});
paramlist.add(new Object[]{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie});
}
Map<String, Object> actionMap = new LinkedHashMap<>();
@@ -343,7 +345,7 @@ public final class Rest {
av0.visitEnd();
actionMap.put("url", url);
actionMap.put("auth", entry.auth);
actionMap.put("cachetimeout", entry.cachetimeout);
actionMap.put("cachetimeout", entry.cacheseconds);
actionMap.put("actionid", entry.actionid);
actionMap.put("comment", entry.comment);
actionMap.put("methods", entry.methods);
@@ -354,9 +356,9 @@ public final class Rest {
av0 = mv.visitAnnotation(webparamsDesc, true);
AnnotationVisitor av1 = av0.visitArray("value");
//设置 WebParam
for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie}
final boolean ishead = ((RestHeader) ps[8]) != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = ((RestCookie) ps[9]) != null; //是否取getCookie
for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie}
final boolean ishead = ((RestHeader) ps[9]) != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = ((RestCookie) ps[10]) != null; //是否取getCookie
AnnotationVisitor av2 = av1.visitAnnotation(null, webparamDesc);
av2.visit("name", (String) ps[1]);
@@ -365,6 +367,7 @@ public final class Rest {
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name()
: (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name()));
av2.visit("comment", (String) ps[4]);
av2.visit("required", (Boolean) ps[5]);
av2.visitEnd();
}
av1.visitEnd();
@@ -377,11 +380,12 @@ public final class Rest {
Class ptype = (Class) ps[2];
int radix = (Integer) ps[3];
String comment = (String) ps[4];
RestParam annpara = (RestParam) ps[5];
RestSessionid annsid = (RestSessionid) ps[6];
RestAddress annaddr = (RestAddress) ps[7];
RestHeader annhead = (RestHeader) ps[8];
RestCookie anncookie = (RestCookie) ps[9];
boolean required = (Boolean) ps[5];
RestParam annpara = (RestParam) ps[6];
RestSessionid annsid = (RestSessionid) ps[7];
RestAddress annaddr = (RestAddress) ps[8];
RestHeader annhead = (RestHeader) ps[9];
RestCookie anncookie = (RestCookie) ps[10];
final boolean ishead = annhead != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = anncookie != null; //是否取getCookie
@@ -1014,8 +1018,7 @@ public final class Rest {
this.methods = mapping.methods();
this.auth = mapping.auth();
this.actionid = mapping.actionid();
this.cachetimeout = mapping.cachetimeout();
//this.contentType = mapping.contentType();
this.cacheseconds = mapping.cacheseconds();
this.comment = mapping.comment();
this.jsvar = mapping.jsvar();
}
@@ -1034,9 +1037,8 @@ public final class Rest {
public final int actionid;
public final int cachetimeout;
public final int cacheseconds;
//public final String contentType;
public final String jsvar;
@RestMapping()

View File

@@ -28,7 +28,7 @@ public @interface RestMapping {
/**
* 请求的方法名, 不能含特殊字符
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前)
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX、existsXXX且XXXService为Service的类名将只截取XXX之前)
*
* @return name
*/
@@ -40,10 +40,9 @@ public @interface RestMapping {
int actionid() default 0; //操作ID值鉴权时用到, 对应&#64;WebAction.actionid
int cachetimeout() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.timeout
int cacheseconds() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.seconds
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods
//String contentType() default ""; //设置Response的ContentType 默认值为 text/plain; charset=utf-8
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名该值存在时则忽略contentType()的值
}

View File

@@ -24,9 +24,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface RestParam {
String name(); //参数名
String name(); //参数名 name值不能是'&'; name='#'表示截取uri最后一段; name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
String comment() default ""; //备注描述
}

View File

@@ -48,6 +48,11 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
return source.delete(clazz, node);
}
@Override
public <T> int delete(final Class<T> clazz, final Flipper flipper, FilterNode node) {
return source.delete(clazz, flipper, node);
}
@Override
public <T> int update(T... values) {
return source.update(values);
@@ -73,6 +78,11 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
return source.updateColumn(clazz, node, values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
return source.updateColumn(clazz, node, flipper, values);
}
@Override
public <T> int updateColumns(T bean, final String... columns) {
return source.updateColumns(bean, columns);
@@ -163,6 +173,36 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
return source.find(clazz, selects, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk) {
return source.findColumn(clazz, column, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean) {
return source.findColumn(clazz, column, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node) {
return source.findColumn(clazz, column, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk) {
return source.findColumn(clazz, column, defValue, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean) {
return source.findColumn(clazz, column, defValue, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node) {
return source.findColumn(clazz, column, defValue, node);
}
@Override
public <T> boolean exists(final Class<T> clazz, final Serializable pk) {
return source.exists(clazz, pk);
@@ -208,6 +248,16 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
return source.queryColumnList(selectedColumn, clazz, node);
}
@Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, flipper, node);
}
@Override
public final <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));

View File

@@ -547,24 +547,49 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
public <T> int delete(Class<T> clazz, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return delete(null, info, node);
return delete(null, info, null, node);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, node);
return delete(conn, info, null, node);
} finally {
closeSQLConnection(conn);
}
}
private <T> int delete(final Connection conn, final EntityInfo<T> info, final FilterNode node) {
@Override
public <T> int delete(Class<T> clazz, final Flipper flipper, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return delete(null, info, flipper, node);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, flipper, node);
} finally {
closeSQLConnection(conn);
}
}
private <T> int delete(final Connection conn, final EntityInfo<T> info, final Flipper flipper, final FilterNode node) {
int c = -1;
try {
if (!info.isVirtualEntity()) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
String sql = "DELETE " + (this.readPool.isMysql() ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "DELETE " + (this.readPool.isMysql() ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1))
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper)
+ ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
@@ -573,7 +598,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
//------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
Serializable[] ids = cache.delete(node);
Serializable[] ids = cache.delete(flipper, node);
if (cacheListener != null) cacheListener.deleteCache(info.getType(), ids);
return c >= 0 ? c : (ids == null ? 0 : ids.length);
} catch (SQLException e) {
@@ -755,11 +780,20 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
int c = -1;
if (!info.isVirtualEntity()) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
String sql = "UPDATE " + info.getTable(node) + " a SET " + info.getSQLColumn("a", column) + " = "
+ info.formatToString(value) + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1))
+ " SET " + info.getSQLColumn("a", column) + " = " + info.formatToString(value)
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
@@ -853,17 +887,42 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, node, values);
return updateColumn(null, info, node, null, values);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, node, values);
return updateColumn(conn, info, node, null, values);
} finally {
closeSQLConnection(conn);
}
}
private <T> int updateColumn(final Connection conn, final EntityInfo<T> info, final FilterNode node, final ColumnValue... values) {
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param node 过滤条件
* @param flipper 翻页对象
* @param values 字段值
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, node, flipper, values);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, node, flipper, values);
} finally {
closeSQLConnection(conn);
}
}
private <T> int updateColumn(final Connection conn, final EntityInfo<T> info, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
if (values == null || values.length < 1) return -1;
try {
StringBuilder setsql = new StringBuilder();
@@ -884,10 +943,20 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
int c = -1;
if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
String sql = "UPDATE " + info.getTable(node) + " a SET " + setsql + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
//注LIMIT 仅支持MySQL 且在多表关联式会异常, 该BUG尚未解决
sql += info.createSQLOrderby(flipper) + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
@@ -896,7 +965,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T[] rs = cache.updateColumn(node, attrs, cols);
T[] rs = cache.updateColumn(node, flipper, attrs, cols);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
return c >= 0 ? c : (rs == null ? 0 : rs.length);
} catch (SQLException e) {
@@ -1007,11 +1076,18 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
int c = -1;
if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
String sql = "UPDATE " + info.getTable(node) + " a SET " + setsql
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
@@ -1092,7 +1168,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
}
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info);
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + func.getColumn((column == null || column.isEmpty() ? "*" : ("a." + column))) + " FROM " + info.getTable(node) + " a"
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
@@ -1139,7 +1215,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
final String sqlkey = info.getSQLColumn(null, keyColumn);
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info);
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a." + sqlkey + ", " + func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : ("a." + funcColumn)))
+ " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + sqlkey;
@@ -1238,7 +1314,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
try {
final SelectColumn sels = selects;
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info);
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a.* FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
@@ -1258,6 +1334,86 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk) {
return findColumn(clazz, column, null, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean) {
return findColumn(clazz, column, null, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node) {
return findColumn(clazz, column, null, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null) {
Serializable val = cache.findColumn(column, defValue, pk);
if (cache.isFullLoaded() || val != null) return val;
}
final Connection conn = createReadSQLConnection();
try {
final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
Serializable val = defValue;
if (set.next()) val = (Serializable) set.getObject(1);
set.close();
ps.close();
return val == null ? defValue : val;
} catch (SQLException sex) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + sex.getSQLState() + ';')) return defValue;
throw new RuntimeException(sex);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean) {
return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.findColumn(column, defValue, node);
final Connection conn = createReadSQLConnection();
try {
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
Serializable val = defValue;
if (set.next()) val = (Serializable) set.getObject(1);
set.close();
ps.close();
return val == null ? defValue : val;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return defValue;
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> boolean exists(Class<T> clazz, Serializable pk) {
final EntityInfo<T> info = loadEntityInfo(clazz);
@@ -1268,14 +1424,17 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
final Connection conn = createReadSQLConnection();
final boolean log = debug.get() && info.isLoggable(Level.FINEST);
String logstr = null;
try {
final String sql = "SELECT COUNT(*) FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " exists sql=" + sql);
if (log) logstr = clazz.getSimpleName() + " exists sql=" + sql;
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
set.close();
ps.close();
if (log) logstr = clazz.getSimpleName() + " exists (" + rs + ") sql=" + sql;
return rs;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return false;
@@ -1283,6 +1442,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (logstr != null) logger.finest(logstr);
closeSQLConnection(conn);
}
}
@@ -1299,17 +1459,20 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.exists(node);
final Connection conn = createReadSQLConnection();
final boolean log = debug.get() && info.isLoggable(Level.FINEST);
String logstr = null;
try {
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info);
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " exists sql=" + sql);
if (log) logstr = clazz.getSimpleName() + " exists sql=" + sql;
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
set.close();
ps.close();
if (log) logstr = clazz.getSimpleName() + " exists (" + rs + ") sql=" + sql;
return rs;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return false;
@@ -1317,6 +1480,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (logstr != null) logger.finest(logstr);
closeSQLConnection(conn);
}
}
@@ -1352,6 +1516,16 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
return (List<V>) queryColumnSheet(false, selectedColumn, clazz, null, node).list(true);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return (List<V>) queryColumnSheet(false, selectedColumn, clazz, flipper, node).list(true);
}
/**
* 根据指定参数查询对象某个字段的集合
* <p>
@@ -1534,16 +1708,17 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
final SelectColumn sels = selects;
final List<T> list = new ArrayList();
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, joinTabalis, info);
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a.* FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
if (debug.get() && info.isLoggable(Level.FINEST))
logger.finest(clazz.getSimpleName() + " query sql=" + sql + (flipper == null ? "" : (" LIMIT " + flipper.getOffset() + "," + flipper.getLimit())));
if (debug.get() && info.isLoggable(Level.FINEST)) {
logger.finest(clazz.getSimpleName() + " query sql=" + sql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getOffset() + "," + flipper.getLimit())));
}
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset());
final int limit = flipper == null ? Integer.MAX_VALUE : flipper.getLimit();
final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit();
int i = 0;
while (set.next()) {
i++;
@@ -1568,6 +1743,17 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
}
private static StringBuilder multisplit(char ch1, char ch2, String split, StringBuilder sb, String str, int from) {
if (str == null) return sb;
int pos1 = str.indexOf(ch1, from);
if (pos1 < 0) return sb;
int pos2 = str.indexOf(ch2, from);
if (pos2 < 0) return sb;
if (sb.length() > 0) sb.append(split);
sb.append(str.substring(pos1 + 1, pos2));
return multisplit(ch1, ch2, split, sb, str, pos2 + 1);
}
@Override
public final int[] directExecute(String... sqls) {
Connection conn = createWriteSQLConnection();

View File

@@ -56,6 +56,8 @@ public interface DataSource {
public <T> int delete(final Class<T> clazz, final Serializable... ids);
public <T> int delete(final Class<T> clazz, final FilterNode node);
public <T> int delete(final Class<T> clazz, final Flipper flipper, final FilterNode node);
//------------------------update---------------------------
/**
@@ -76,6 +78,8 @@ public interface DataSource {
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values);
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values);
public <T> int updateColumns(final T bean, final String... columns);
public <T> int updateColumns(final T bean, final FilterNode node, final String... columns);
@@ -124,6 +128,18 @@ public interface DataSource {
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean);
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node);
public <T> boolean exists(final Class<T> clazz, final Serializable pk);
public <T> boolean exists(final Class<T> clazz, final FilterBean bean);
@@ -155,6 +171,10 @@ public interface DataSource {
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterNode node);
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node);
/**
* 根据指定参数查询对象某个字段的集合
*

View File

@@ -17,13 +17,41 @@ import java.io.Serializable;
*/
public interface DistributeTableStrategy<T> {
/**
* 获取对象的表名
* 查询单个对象时调用本方法获取表名
*
* @param table 模板表的表名
* @param primary 记录主键
*
* @return 带库名的全表名
*/
default String getTable(String table, Serializable primary) {
return null;
}
/**
* 获取对象的表名
* 查询、修改、删除对象时调用本方法获取表名
* 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中
*
* @param table 模板表的表名
* @param node 过滤条件
*
* @return 带库名的全表名
*/
default String getTable(String table, FilterNode node) {
return null;
}
/**
* 获取对象的表名
* 新增对象或更新单个对象时调用本方法获取表名
*
* @param table 模板表的表名
* @param bean 实体对象
*
* @return 带库名的全表名
*/
public String getTable(String table, T bean);
}

View File

@@ -138,6 +138,35 @@ public final class EntityCache<T> {
return t;
}
public Serializable findColumn(final String column, final Serializable defValue, final Serializable id) {
if (id == null) return defValue;
T rs = map.get(id);
if (rs == null) return defValue;
for (Attribute attr : this.info.attributes) {
if (column.equals(attr.field())) {
Serializable val = (Serializable) attr.get(rs);
return val == null ? defValue : val;
}
}
return defValue;
}
public Serializable findColumn(final String column, final Serializable defValue, FilterNode node) {
final Predicate<T> filter = node == null ? null : node.createPredicate(this);
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
Optional<T> opt = stream.findFirst();
if (!opt.isPresent()) return defValue;
T rs = opt.get();
for (Attribute attr : this.info.attributes) {
if (column.equals(attr.field())) {
Serializable val = (Serializable) attr.get(rs);
return val == null ? defValue : val;
}
}
return defValue;
}
public boolean exists(Serializable id) {
if (id == null) return false;
final Class atype = this.primary.type();
@@ -321,7 +350,8 @@ public final class EntityCache<T> {
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null) stream = stream.skip(flipper.getOffset()).limit(flipper.getLimit());
if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset());
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
final List<T> rs = new ArrayList<>();
if (selects == null) {
Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x);
@@ -371,9 +401,14 @@ public final class EntityCache<T> {
return 1;
}
public Serializable[] delete(final FilterNode node) {
public Serializable[] delete(final Flipper flipper, final FilterNode node) {
if (node == null || this.list.isEmpty()) return new Serializable[0];
Object[] rms = this.list.stream().filter(node.createPredicate(this)).toArray();
final Comparator<T> comparator = createComparator(flipper);
Stream<T> stream = this.list.stream().filter(node.createPredicate(this));
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset());
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
Object[] rms = stream.toArray();
Serializable[] ids = new Serializable[rms.length];
int i = -1;
for (Object o : rms) {
@@ -449,9 +484,13 @@ public final class EntityCache<T> {
return rs;
}
public <V> T[] updateColumn(final FilterNode node, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
public <V> T[] updateColumn(final FilterNode node, final Flipper flipper, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0);
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
Stream<T> stream = this.list.stream();
final Comparator<T> comparator = createComparator(flipper);
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
T[] rms = stream.filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
for (T rs : rms) {
synchronized (rs) {
for (int i = 0; i < attrs.size(); i++) {

View File

@@ -108,7 +108,7 @@ public final class EntityInfo<T> {
final BiFunction<DataSource, Class, List> fullloader;
//------------------------------------------------------------
public static <T> EntityInfo<T> load(Class<T> clazz, final int nodeid, final boolean cacheForbidden, final Properties conf,
static <T> EntityInfo<T> load(Class<T> clazz, final int nodeid, final boolean cacheForbidden, final Properties conf,
DataSource source, BiFunction<DataSource, Class, List> fullloader) {
EntityInfo rs = entityInfos.get(clazz);
if (rs != null) return rs;
@@ -127,7 +127,7 @@ public final class EntityInfo<T> {
}
}
public static <T> EntityInfo<T> get(Class<T> clazz) {
static <T> EntityInfo<T> get(Class<T> clazz) {
return entityInfos.get(clazz);
}
@@ -153,7 +153,7 @@ public final class EntityInfo<T> {
this.fullloader = loader;
} else {
this.fullloader = fullloader;
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + t.name());
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name()));
}
DistributeTable dt = type.getAnnotation(DistributeTable.class);
DistributeTableStrategy dts = null;

View File

@@ -54,4 +54,11 @@ public @interface FilterColumn {
*/
boolean itemand() default true;
/**
* 备注描述
*
* @return 备注描述
*/
String comment() default "";
}

View File

@@ -243,7 +243,7 @@ public class FilterJoinNode extends FilterNode {
}
@Override
protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final Map<Class, String> joinTabalis, final EntityInfo<T> info) {
protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final boolean update, final Map<Class, String> joinTabalis, final Set<String> haset, final EntityInfo<T> info) {
boolean morejoin = false;
if (this.joinEntity == null) {
if (this.joinClass != null) this.joinEntity = func.apply(this.joinClass);
@@ -261,7 +261,8 @@ public class FilterJoinNode extends FilterNode {
}
StringBuilder sb = new StringBuilder();
if (this.joinClass != null) {
sb.append(createElementSQLJoin(joinTabalis, info, this));
CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, this);
if (cs != null) sb.append(cs);
}
if (morejoin) {
Set<Class> set = new HashSet<>();
@@ -270,7 +271,7 @@ public class FilterJoinNode extends FilterNode {
if (node instanceof FilterJoinNode) {
FilterJoinNode joinNode = ((FilterJoinNode) node);
if (!set.contains(joinNode.joinClass)) {
CharSequence cs = createElementSQLJoin(joinTabalis, info, joinNode);
CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, joinNode);
if (cs != null) {
sb.append(cs);
set.add(joinNode.joinClass);
@@ -282,17 +283,28 @@ public class FilterJoinNode extends FilterNode {
return sb;
}
private static CharSequence createElementSQLJoin(final Map<Class, String> joinTabalis, final EntityInfo info, final FilterJoinNode node) {
if (node.joinClass == null) return null;
private static CharSequence createElementSQLJoin(final boolean update, final Map<Class, String> joinTabalis, final Set<String> haset, final EntityInfo info, final FilterJoinNode node) {
if (node.joinClass == null || (haset != null && haset.contains(joinTabalis.get(node.joinClass)))) return null;
StringBuilder sb = new StringBuilder();
String[] joinColumns = node.joinColumns;
int pos = joinColumns[0].indexOf('=');
sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass))
.append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
for (int i = 1; i < joinColumns.length; i++) {
pos = joinColumns[i].indexOf('=');
sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i]));
if (update) {
sb.append("[").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)).append(']');
sb.append('{').append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
for (int i = 1; i < joinColumns.length; i++) {
pos = joinColumns[i].indexOf('=');
sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i]));
}
sb.append('}');
} else {
sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass))
.append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
for (int i = 1; i < joinColumns.length; i++) {
pos = joinColumns[i].indexOf('=');
sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i]));
}
}
if (haset != null) haset.add(joinTabalis.get(node.joinClass));
return sb;
}

View File

@@ -173,16 +173,18 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
*
* @param <T> Entity类的泛型
* @param func EntityInfo的加载器
* @param update 是否用于更新的JOIN
* @param joinTabalis 关联表集合
* @param haset 已拼接过的字段名
* @param info Entity类的EntityInfo
*
* @return SQL的join语句 不存在返回null
*/
protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final Map<Class, String> joinTabalis, final EntityInfo<T> info) {
protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final boolean update, final Map<Class, String> joinTabalis, final Set<String> haset, final EntityInfo<T> info) {
if (joinTabalis == null || this.nodes == null) return null;
StringBuilder sb = null;
for (FilterNode node : this.nodes) {
CharSequence cs = node.createSQLJoin(func, joinTabalis, info);
CharSequence cs = node.createSQLJoin(func, update, joinTabalis, haset, info);
if (cs == null) continue;
if (sb == null) sb = new StringBuilder();
sb.append(cs);

View File

@@ -463,7 +463,7 @@ public final class ResourceFactory {
try {
element.listener.invoke(dest, name, rs, oldVal);
} catch (Exception e) {
e.printStackTrace();
logger.log(Level.SEVERE, dest + " resource change listener error", e);
}
}
}

View File

@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.*;
import java.time.*;
import java.util.*;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.*;
/**
@@ -505,125 +506,241 @@ public final class Utility {
}
public static String postHttpContent(String url) throws IOException {
return remoteHttpContent(null, "POST", url, null, null).toString("UTF-8");
return remoteHttpContent(null, "POST", url, 0, null, null).toString("UTF-8");
}
public static String postHttpContent(String url, int timeout) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, null, null).toString("UTF-8");
}
public static String postHttpContent(String url, String body) throws IOException {
return remoteHttpContent(null, "POST", url, null, body).toString("UTF-8");
return remoteHttpContent(null, "POST", url, 0, null, body).toString("UTF-8");
}
public static String postHttpContent(String url, int timeout, String body) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, null, body).toString("UTF-8");
}
public static String postHttpContent(String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, headers, body).toString("UTF-8");
return remoteHttpContent(null, "POST", url, 0, headers, body).toString("UTF-8");
}
public static String postHttpContent(String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, headers, body).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url) throws IOException {
return remoteHttpContent(ctx, "POST", url, null, null).toString("UTF-8");
return remoteHttpContent(ctx, "POST", url, 0, null, null).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url, int timeout) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, null, null).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, null, body).toString("UTF-8");
return remoteHttpContent(ctx, "POST", url, 0, null, body).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url, int timeout, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, null, body).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, headers, body).toString("UTF-8");
return remoteHttpContent(ctx, "POST", url, 0, headers, body).toString("UTF-8");
}
public static String postHttpContent(SSLContext ctx, String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, headers, body).toString("UTF-8");
}
public static String postHttpContent(String url, Charset charset) throws IOException {
return remoteHttpContent(null, "POST", url, null, null).toString(charset.name());
return remoteHttpContent(null, "POST", url, 0, null, null).toString(charset.name());
}
public static String postHttpContent(String url, int timeout, Charset charset) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, null, null).toString(charset.name());
}
public static String postHttpContent(String url, Charset charset, String body) throws IOException {
return remoteHttpContent(null, "POST", url, null, body).toString(charset.name());
return remoteHttpContent(null, "POST", url, 0, null, body).toString(charset.name());
}
public static String postHttpContent(String url, int timeout, Charset charset, String body) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, null, body).toString(charset.name());
}
public static String postHttpContent(String url, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, headers, body).toString(charset.name());
return remoteHttpContent(null, "POST", url, 0, headers, body).toString(charset.name());
}
public static String postHttpContent(String url, int timeout, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, headers, body).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, Charset charset) throws IOException {
return remoteHttpContent(ctx, "POST", url, null, null).toString(charset.name());
return remoteHttpContent(ctx, "POST", url, 0, null, null).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, int timeout, Charset charset) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, null, null).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, Charset charset, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, null, body).toString(charset.name());
return remoteHttpContent(ctx, "POST", url, 0, null, body).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, int timeout, Charset charset, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, null, body).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, headers, body).toString(charset.name());
return remoteHttpContent(ctx, "POST", url, 0, headers, body).toString(charset.name());
}
public static String postHttpContent(SSLContext ctx, String url, int timeout, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, headers, body).toString(charset.name());
}
public static byte[] postHttpBytesContent(String url) throws IOException {
return remoteHttpContent(null, "POST", url, null, null).toByteArray();
return remoteHttpContent(null, "POST", url, 0, null, null).toByteArray();
}
public static byte[] postHttpBytesContent(String url, int timeout) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, null, null).toByteArray();
}
public static byte[] postHttpBytesContent(SSLContext ctx, String url) throws IOException {
return remoteHttpContent(ctx, "POST", url, null, null).toByteArray();
return remoteHttpContent(ctx, "POST", url, 0, null, null).toByteArray();
}
public static byte[] postHttpBytesContent(SSLContext ctx, String url, int timeout) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, null, null).toByteArray();
}
public static byte[] postHttpBytesContent(String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, headers, body).toByteArray();
return remoteHttpContent(null, "POST", url, 0, headers, body).toByteArray();
}
public static byte[] postHttpBytesContent(String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "POST", url, timeout, headers, body).toByteArray();
}
public static byte[] postHttpBytesContent(SSLContext ctx, String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, headers, body).toByteArray();
return remoteHttpContent(ctx, "POST", url, 0, headers, body).toByteArray();
}
public static byte[] postHttpBytesContent(SSLContext ctx, String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "POST", url, timeout, headers, body).toByteArray();
}
public static String getHttpContent(String url) throws IOException {
return remoteHttpContent(null, "GET", url, null, null).toString("UTF-8");
return remoteHttpContent(null, "GET", url, 0, null, null).toString("UTF-8");
}
public static String getHttpContent(String url, int timeout) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, null, null).toString("UTF-8");
}
public static String getHttpContent(SSLContext ctx, String url) throws IOException {
return remoteHttpContent(ctx, "GET", url, null, null).toString("UTF-8");
return remoteHttpContent(ctx, "GET", url, 0, null, null).toString("UTF-8");
}
public static String getHttpContent(SSLContext ctx, String url, int timeout) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, null, null).toString("UTF-8");
}
public static String getHttpContent(SSLContext ctx, String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, headers, body).toString("UTF-8");
return remoteHttpContent(ctx, "GET", url, 0, headers, body).toString("UTF-8");
}
public static String getHttpContent(SSLContext ctx, String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, headers, body).toString("UTF-8");
}
public static String getHttpContent(String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, headers, body).toString("UTF-8");
return remoteHttpContent(null, "GET", url, 0, headers, body).toString("UTF-8");
}
public static String getHttpContent(String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, headers, body).toString("UTF-8");
}
public static String getHttpContent(String url, Charset charset) throws IOException {
return remoteHttpContent(null, "GET", url, null, null).toString(charset.name());
return remoteHttpContent(null, "GET", url, 0, null, null).toString(charset.name());
}
public static String getHttpContent(String url, int timeout, Charset charset) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, null, null).toString(charset.name());
}
public static String getHttpContent(SSLContext ctx, String url, Charset charset) throws IOException {
return remoteHttpContent(ctx, "GET", url, null, null).toString(charset.name());
return remoteHttpContent(ctx, "GET", url, 0, null, null).toString(charset.name());
}
public static String getHttpContent(SSLContext ctx, String url, int timeout, Charset charset) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, null, null).toString(charset.name());
}
public static String getHttpContent(SSLContext ctx, String url, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, headers, body).toString(charset.name());
return remoteHttpContent(ctx, "GET", url, 0, headers, body).toString(charset.name());
}
public static String getHttpContent(SSLContext ctx, String url, int timeout, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, headers, body).toString(charset.name());
}
public static String getHttpContent(String url, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, headers, body).toString(charset.name());
return remoteHttpContent(null, "GET", url, 0, headers, body).toString(charset.name());
}
public static String getHttpContent(String url, int timeout, Charset charset, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, headers, body).toString(charset.name());
}
public static byte[] getHttpBytesContent(String url) throws IOException {
return remoteHttpContent(null, "GET", url, null, null).toByteArray();
return remoteHttpContent(null, "GET", url, 0, null, null).toByteArray();
}
public static byte[] getHttpBytesContent(String url, int timeout) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, null, null).toByteArray();
}
public static byte[] getHttpBytesContent(SSLContext ctx, String url) throws IOException {
return remoteHttpContent(ctx, "GET", url, null, null).toByteArray();
return remoteHttpContent(ctx, "GET", url, 0, null, null).toByteArray();
}
public static byte[] getHttpBytesContent(SSLContext ctx, String url, int timeout) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, null, null).toByteArray();
}
public static byte[] getHttpBytesContent(String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, headers, body).toByteArray();
return remoteHttpContent(null, "GET", url, 0, headers, body).toByteArray();
}
public static byte[] getHttpBytesContent(String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, "GET", url, timeout, headers, body).toByteArray();
}
public static byte[] getHttpBytesContent(SSLContext ctx, String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, headers, body).toByteArray();
return remoteHttpContent(ctx, "GET", url, 0, headers, body).toByteArray();
}
public static byte[] getHttpBytesContent(SSLContext ctx, String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(ctx, "GET", url, timeout, headers, body).toByteArray();
}
public static ByteArrayOutputStream remoteHttpContent(String method, String url, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, method, url, headers, body);
return remoteHttpContent(null, method, url, 0, headers, body);
}
public static ByteArrayOutputStream remoteHttpContent(SSLContext ctx, String method, String url, Map<String, String> headers, String body) throws IOException {
public static ByteArrayOutputStream remoteHttpContent(String method, String url, int timeout, Map<String, String> headers, String body) throws IOException {
return remoteHttpContent(null, method, url, timeout, headers, body);
}
public static ByteArrayOutputStream remoteHttpContent(SSLContext ctx, String method, String url, int timeout, Map<String, String> headers, String body) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
conn.setConnectTimeout(timeout > 0 ? timeout : 3000);
conn.setReadTimeout(timeout > 0 ? timeout : 3000);
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection httpsconn = ((HttpsURLConnection) conn);
httpsconn.setSSLSocketFactory((ctx == null ? DEFAULTSSL_CONTEXT : ctx).getSocketFactory());
@@ -645,9 +762,10 @@ public final class Utility {
if (rs == 301 || rs == 302) {
String newurl = conn.getHeaderField("Location");
conn.disconnect();
return remoteHttpContent(ctx, method, newurl, headers, body);
return remoteHttpContent(ctx, method, newurl, timeout, headers, body);
}
InputStream in = (rs < 400 || rs == 404) && rs != 405 ? conn.getInputStream() : conn.getErrorStream();
if ("gzip".equalsIgnoreCase(conn.getContentEncoding())) in = new GZIPInputStream(in);
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
byte[] bytes = new byte[1024];
int pos;

View File

@@ -40,8 +40,8 @@ public class FilterNodeTest {
System.out.println("bean.string = " + beanNode);
Map<Class, String> nodeJoinTabalis = node.getJoinTabalis();
Map<Class, String> beanJoinTabalis = beanNode.getJoinTabalis();
CharSequence nodeJoinsql = node.createSQLJoin(func, nodeJoinTabalis, carEntity);
CharSequence beanJoinsql = beanNode.createSQLJoin(func, beanJoinTabalis, carEntity);
CharSequence nodeJoinsql = node.createSQLJoin(func, false, nodeJoinTabalis, new HashSet<>(), carEntity);
CharSequence beanJoinsql = beanNode.createSQLJoin(func, false, beanJoinTabalis, new HashSet<>(), carEntity);
CharSequence nodeWhere = node.createSQLExpress(carEntity, nodeJoinTabalis);
CharSequence beanWhere = beanNode.createSQLExpress(carEntity, beanJoinTabalis);
System.out.println("node.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) + " WHERE " + nodeWhere);

View File

@@ -8,9 +8,19 @@ public class HelloBean implements FilterBean {
private int helloid;
@RestHeader(name = "hello-res")
private String res;
@RestHeader(name = "User-Agent")
private String useragent; //从Http Header中获取浏览器信息
@RestCookie(name = "hello-cookie")
private String rescookie; //从Cookie中获取名为hello-cookie的值
@RestAddress
private String clientaddr; //客户端请求IP
@RestSessionid
private String sessionid; //用户Sessionid, 未登录时为null
/** 以下省略getter setter方法 */
public int getHelloid() {
return helloid;
}
@@ -19,12 +29,36 @@ public class HelloBean implements FilterBean {
this.helloid = helloid;
}
public String getRes() {
return res;
public String getUseragent() {
return useragent;
}
public void setRes(String res) {
this.res = res;
public void setUseragent(String useragent) {
this.useragent = useragent;
}
public String getRescookie() {
return rescookie;
}
public void setRescookie(String rescookie) {
this.rescookie = rescookie;
}
public String getClientaddr() {
return clientaddr;
}
public void setClientaddr(String clientaddr) {
this.clientaddr = clientaddr;
}
public String getSessionid() {
return sessionid;
}
public void setSessionid(String sessionid) {
this.sessionid = sessionid;
}
@Override

View File

@@ -25,6 +25,7 @@ public class HelloEntity {
@RestAddress
private String clientaddr;
/** 以下省略getter setter方法 */
public int getHelloid() {
return helloid;
}

View File

@@ -14,9 +14,10 @@ import org.redkale.util.Sheet;
* Flipper : Source组件中的翻页对象
* UserInfo :当前用户类
* HelloEntity: Hello模块的实体类
* HelloBean: Hellow模块实现FilterBean的过滤Bean类
* HelloBean: Hello模块实现FilterBean的过滤Bean类
*
*/
@RestService
public class HelloService implements Service {
private int nodeid;
@@ -40,12 +41,12 @@ public class HelloService implements Service {
}
//删除记录
public void deleteHello(int id) { //通过 /hello/delete/1234 删除对象
public void deleteHello(int id) { //通过 /pipes/hello/delete/1234 删除对象
source.delete(HelloEntity.class, id);
}
//修改记录
public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /pipes/hello/update?bean={...} 修改对象
System.out.println("修改记录-" + nodeid + ": clientAddr = " + clientAddr + ", entity =" + entity);
if (entity != null) entity.setUpdatetime(System.currentTimeMillis());
if (source != null) source.update(entity);
@@ -53,26 +54,26 @@ public class HelloService implements Service {
//修改记录
@RestMapping(name = "partupdate")
public void updateHello(HelloEntity entity, @RestParam(name = "cols") String[] columns) { //通过 /hello/partupdate?bean={...} 修改对象
public void updateHello(HelloEntity entity, @RestParam(name = "cols") String[] columns) { //通过 /pipes/hello/partupdate?bean={...}&cols=... 修改对象
entity.setUpdatetime(System.currentTimeMillis());
source.updateColumns(entity, columns);
}
//查询Sheet列表
public Sheet<HelloEntity> queryHello(HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询Sheet列表
public Sheet<HelloEntity> queryHello(HelloBean bean, Flipper flipper) { //通过 /pipes/hello/query/offset:0/limit:20?bean={...} 查询Sheet列表
return source.querySheet(HelloEntity.class, flipper, bean);
}
//查询List列表
@RestMapping(name = "list")
public List<HelloEntity> queryHello(HelloBean bean) { //通过 /hello/list?bean={...} 查询List列表
public List<HelloEntity> queryHello(HelloBean bean) { //通过 /pipes/hello/list?bean={...} 查询List列表
return source.queryList(HelloEntity.class, bean);
}
//查询单个
@RestMapping(name = "find")
@RestMapping(name = "jsfind", jsvar = "varhello")
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /hello/find/1234 查询对象
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象
return source.find(HelloEntity.class, id);
}

View File

@@ -16,18 +16,18 @@ import org.redkale.util.Sheet;
* Flipper : Source组件中的翻页对象
* UserInfo :当前用户类
* HelloEntity: Hello模块的实体类
* HelloBean: Hellow模块实现FilterBean的过滤Bean类
* HelloBean: Hello模块实现FilterBean的过滤Bean类
*
*/
@RestService(name = "hello", moduleid = 0, repair = true, ignore = false)
@RestService(name = "hello", moduleid = 0, repair = true, ignore = false, comment = "Hello服务模块")
public class HelloService2 implements Service {
@Resource
private DataSource source;
//增加记录
@RestMapping(name = "create", auth = false)
public RetResult<HelloEntity> createHello(UserInfo info, @RestParam(name = "bean") HelloEntity entity) {
@RestMapping(name = "create", auth = false, comment = "创建Hello对象")
public RetResult<HelloEntity> createHello(UserInfo info, @RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) {
entity.setCreator(info == null ? 0 : info.getUserid()); //设置当前用户ID
entity.setCreatetime(System.currentTimeMillis());
source.insert(entity);
@@ -35,27 +35,27 @@ public class HelloService2 implements Service {
}
//删除记录
@RestMapping(name = "delete", auth = false)
public void deleteHello(@RestParam(name = "#") int id) { //通过 /hello/delete/1234 删除对象
@RestMapping(name = "delete", auth = false, comment = "根据id删除Hello对象")
public void deleteHello(@RestParam(name = "#", comment = "Hello对象id") int id) { //通过 /hello/delete/1234 删除对象
source.delete(HelloEntity.class, id);
}
//修改记录
@RestMapping(name = "update", auth = false)
public void updateHello(@RestParam(name = "bean") HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
@RestMapping(name = "update", auth = false, comment = "修改Hello对象")
public void updateHello(@RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
entity.setUpdatetime(System.currentTimeMillis());
source.update(entity);
}
//查询列表
@RestMapping(name = "query", auth = false)
public Sheet<HelloEntity> queryHello(@RestParam(name = "bean") HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询列表
@RestMapping(name = "query", auth = false, comment = "查询Hello对象列表")
public Sheet<HelloEntity> queryHello(@RestParam(name = "bean", comment = "过滤条件") HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询列表
return source.querySheet(HelloEntity.class, flipper, bean);
}
//查询单个
@RestMapping(name = "find", auth = false)
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /hello/find/1234 查询对象
@RestMapping(name = "find", auth = false, comment = "根据id查找单个Hello对象")
public HelloEntity findHello(@RestParam(name = "#", comment = "Hello对象id") int id) { //通过 /hello/find/1234 查询对象
return source.find(HelloEntity.class, id);
}
}

View File

@@ -46,6 +46,8 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setResname(req.getHeader("hello-res"));
UserInfo user = currentUser(req);
RetResult<HelloEntity> result = service.createHello(user, bean);
resp.finishJson(result);
@@ -66,6 +68,8 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
String clientaddr = req.getRemoteAddr();
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setResname(req.getHeader("hello-res"));
service.updateHello(clientaddr, bean);
resp.finishJson(RetResult.success());
}
@@ -75,6 +79,8 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setResname(req.getHeader("hello-res"));
String[] cols = req.getJsonParameter(String[].class, "cols");
service.updateHello(bean, cols);
resp.finishJson(RetResult.success());
@@ -85,6 +91,10 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setUseragent(req.getHeader("User-Agent"));
bean.setRescookie(req.getCookie("hello-cookie"));
bean.setSessionid(req.getSessionid(false));
Flipper flipper = req.getFlipper();
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
resp.finishJson(result);
@@ -95,6 +105,10 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
public void list(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setUseragent(req.getHeader("User-Agent"));
bean.setRescookie(req.getCookie("hello-cookie"));
bean.setSessionid(req.getSessionid(false));
List<HelloEntity> result = service.queryHello(bean);
resp.finishJson(result);
}

View File

@@ -27,17 +27,21 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
private Map<String, HelloService2> _servicemap;
@AuthIgnore
@WebAction(url = "/hello/create")
@WebAction(url = "/hello/create", comment = "创建Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setResname(req.getHeader("hello-res"));
UserInfo user = currentUser(req);
RetResult<HelloEntity> result = service.createHello(user, bean);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/delete/")
@WebAction(url = "/hello/delete/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
@@ -46,26 +50,35 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/update")
@WebAction(url = "/hello/update", comment = "修改Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setResname(req.getHeader("hello-res"));
service.updateHello(bean);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/query")
@WebAction(url = "/hello/query", comment = "查询Hello对象列表")
@WebParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
bean.setClientaddr(req.getRemoteAddr());
bean.setUseragent(req.getHeader("User-Agent"));
bean.setRescookie(req.getCookie("hello-cookie"));
bean.setSessionid(req.getSessionid(false));
Flipper flipper = req.getFlipper();
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/find/")
@WebAction(url = "/hello/find/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());

View File

@@ -0,0 +1,22 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.source;
import java.io.Serializable;
import org.redkale.convert.json.*;
/**
*
* @author zhangjx
*/
public abstract class BaseEntity implements Serializable {
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -5,6 +5,7 @@
*/
package org.redkale.test.source;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiFunction;
import javax.persistence.Id;
@@ -35,7 +36,11 @@ public class CacheTestBean {
Attribute nameattr = Attribute.create(CacheTestBean.class, "name");
Attribute priceattr = Attribute.create(CacheTestBean.class, "price");
BiFunction<DataSource, Class, List> fullloader = (s, z) -> list;
EntityCache<CacheTestBean> cache = new EntityCache(EntityInfo.load(CacheTestBean.class, 0, true, new Properties(), null, fullloader));
Method method = EntityInfo.class.getDeclaredMethod("load", Class.class, int.class, boolean.class, Properties.class,
DataSource.class, BiFunction.class);
method.setAccessible(true);
final EntityInfo<CacheTestBean> info = (EntityInfo<CacheTestBean>) method.invoke(null, CacheTestBean.class, 0, true, new Properties(), null, fullloader);
EntityCache<CacheTestBean> cache = new EntityCache(info);
cache.fullLoad();
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.COUNT, "name", null));

View File

@@ -0,0 +1,138 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.source;
import java.io.Serializable;
import javax.persistence.*;
import org.redkale.source.*;
/**
*
* @author zhangjx
*/
@DistributeTable(strategy = LoginRecord.TableStrategy.class)
public class LoginRecord extends BaseEntity {
@Id
@GeneratedValue
@Column(comment = "UUID")
private String loginid = ""; //UUID
@Column(updatable = false, comment = "C端用户ID")
private long userid; //C端用户ID
@Column(updatable = false, comment = "登录网络类型; wifi/4g/3g")
private String netmode = ""; //登录网络类型; wifi/4g/3g
@Column(updatable = false, comment = "APP版本信息")
private String appversion = ""; //APP版本信息
@Column(updatable = false, comment = "APP操作系统信息")
private String appos = ""; //APP操作系统信息
@Column(updatable = false, comment = "登录时客户端信息")
private String loginagent = ""; //登录时客户端信息
@Column(updatable = false, comment = "登录时的IP")
private String loginaddr = ""; //登录时的IP
@Column(updatable = false, comment = "创建时间")
private long createtime; //创建时间
/** 以下省略getter setter方法 */
//
public void setLoginid(String loginid) {
this.loginid = loginid;
}
public String getLoginid() {
return this.loginid;
}
public void setUserid(long userid) {
this.userid = userid;
}
public long getUserid() {
return this.userid;
}
public void setNetmode(String netmode) {
this.netmode = netmode;
}
public String getNetmode() {
return this.netmode;
}
public String getAppversion() {
return appversion;
}
public void setAppversion(String appversion) {
this.appversion = appversion;
}
public String getAppos() {
return appos;
}
public void setAppos(String appos) {
this.appos = appos;
}
public void setLoginagent(String loginagent) {
this.loginagent = loginagent;
}
public String getLoginagent() {
return this.loginagent;
}
public void setLoginaddr(String loginaddr) {
this.loginaddr = loginaddr;
}
public String getLoginaddr() {
return this.loginaddr;
}
public void setCreatetime(long createtime) {
this.createtime = createtime;
}
public long getCreatetime() {
return this.createtime;
}
public static class TableStrategy implements DistributeTableStrategy<LoginRecord> {
private static final String dayformat = "%1$tY%1$tm%1$td";
private static final String yearformat = "%1$tY";
//过滤查询时调用本方法
@Override
public String getTable(String table, FilterNode node) {
Serializable day = node.findValue("#day");
if (day != null) getTable(table, (Integer) day, 0L); //存在#day参数则直接使用day值
Serializable time = node.findValue("#createtime"); //存在createtime则使用最小时间且createtime的范围必须在一天内因为本表以天为单位建表
return getTable(table, 0, (time == null ? 0L : (time instanceof Range ? ((Range.LongRange) time).getMin() : (Long) time)));
}
//创建或单个查询时调用本方法
@Override
public String getTable(String table, LoginRecord bean) {
return getTable(table, 0, bean.getCreatetime());
}
private String getTable(String table, int day, long createtime) {
int pos = table.indexOf('.');
String year = (day > 0 ? "" + day / 10000 : String.format(yearformat, createtime));
return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime));
}
}
}

View File

@@ -0,0 +1,158 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.source;
import java.io.Serializable;
import javax.persistence.*;
import org.redkale.source.*;
import org.redkale.util.Utility;
/**
*
* @author zhangjx
*/
@DistributeTable(strategy = LoginRecord2.TableStrategy.class)
public class LoginRecord2 extends BaseEntity {
@Id
@Column(comment = "主键ID; 值=UUID+create36time")
private String loginid = ""; //主键ID; 值=UUID+create36time
@Column(updatable = false, comment = "C端用户ID")
private long userid; //C端用户ID
@Column(updatable = false, comment = "登录网络类型; wifi/4g/3g")
private String netmode = ""; //登录网络类型; wifi/4g/3g
@Column(updatable = false, comment = "APP版本信息")
private String appversion = ""; //APP版本信息
@Column(updatable = false, comment = "APP操作系统信息")
private String appos = ""; //APP操作系统信息
@Column(updatable = false, comment = "登录时客户端信息")
private String loginagent = ""; //登录时客户端信息
@Column(updatable = false, comment = "登录时的IP")
private String loginaddr = ""; //登录时的IP
@Column(updatable = false, comment = "创建时间")
private long createtime; //创建时间
/** 以下省略getter setter方法 */
//
public void setLoginid(String loginid) {
this.loginid = loginid;
}
public String getLoginid() {
return this.loginid;
}
public void setUserid(long userid) {
this.userid = userid;
}
public long getUserid() {
return this.userid;
}
public void setNetmode(String netmode) {
this.netmode = netmode;
}
public String getNetmode() {
return this.netmode;
}
public String getAppversion() {
return appversion;
}
public void setAppversion(String appversion) {
this.appversion = appversion;
}
public String getAppos() {
return appos;
}
public void setAppos(String appos) {
this.appos = appos;
}
public void setLoginagent(String loginagent) {
this.loginagent = loginagent;
}
public String getLoginagent() {
return this.loginagent;
}
public void setLoginaddr(String loginaddr) {
this.loginaddr = loginaddr;
}
public String getLoginaddr() {
return this.loginaddr;
}
public void setCreatetime(long createtime) {
this.createtime = createtime;
}
public long getCreatetime() {
return this.createtime;
}
//创建对象
public static void main(String[] args) throws Throwable {
LoginRecord2 record = new LoginRecord2();
long now = System.currentTimeMillis();
record.setCreatetime(now); //设置创建时间
String create36time = Long.toString(now, 36); //时间的36进制
if (create36time.length() < 9) create36time = "0" + create36time; //当前时间值的36进制只可能是8位或9位不足9位填充0
record.setLoginid(Utility.uuid() + create36time); //主键的生成策略
//.... 填充其他字段
//source.insert(record);
}
public static class TableStrategy implements DistributeTableStrategy<LoginRecord2> {
private static final String dayformat = "%1$tY%1$tm%1$td";
private static final String yearformat = "%1$tY";
//过滤查询时调用本方法
@Override
public String getTable(String table, FilterNode node) {
Serializable day = node.findValue("#day");
if (day != null) getTable(table, (Integer) day, 0L); //存在#day参数则直接使用day值
Serializable time = node.findValue("#createtime"); //存在createtime则使用最小时间且createtime的范围必须在一天内因为本表以天为单位建表
return getTable(table, 0, (time == null ? 0L : (time instanceof Range ? ((Range.LongRange) time).getMin() : (Long) time)));
}
//创建或单个查询时调用本方法
@Override
public String getTable(String table, LoginRecord2 bean) {
return getTable(table, 0, bean.getCreatetime());
}
//根据主键ID查询单个记录时调用本方法
@Override
public String getTable(String table, Serializable primary) {
String loginid = (String) primary;
String create36time = loginid.substring(loginid.length() - 9); //固定最后9位为创建时间的36进制值
return getTable(table, 0, Long.parseLong(create36time, 36));
}
private String getTable(String table, int day, long createtime) {
int pos = table.indexOf('.');
String year = (day > 0 ? "" + day / 10000 : String.format(yearformat, createtime));
return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime));
}
}
}

View File

@@ -0,0 +1,92 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.source;
import java.io.Serializable;
import javax.persistence.*;
import org.redkale.source.*;
/**
*
* @author zhangjx
*/
@DistributeTable(strategy = LoginUserRecord.TableStrategy.class)
public class LoginUserRecord extends BaseEntity {
@Id
@GeneratedValue
@Column(comment = "UUID")
private String seqid = ""; //UUID
@Column(updatable = false, comment = "C端用户ID")
private long userid; //C端用户ID
@Column(comment = "LoginRecord主键")
private String loginid = ""; //LoginRecord主键
@Column(updatable = false, comment = "创建时间")
private long createtime; //创建时间
/** 以下省略getter setter方法 */
//
public String getSeqid() {
return seqid;
}
public void setSeqid(String seqid) {
this.seqid = seqid;
}
public long getUserid() {
return userid;
}
public void setUserid(long userid) {
this.userid = userid;
}
public String getLoginid() {
return loginid;
}
public void setLoginid(String loginid) {
this.loginid = loginid;
}
public long getCreatetime() {
return createtime;
}
public void setCreatetime(long createtime) {
this.createtime = createtime;
}
public static class TableStrategy implements DistributeTableStrategy<LoginUserRecord> {
@Override
public String getTable(String table, LoginUserRecord bean) {
return getTable(table, bean.getUserid());
}
@Override
public String getTable(String table, FilterNode node) {
Serializable id = node.findValue("userid");
if (id != null) return getTable(table, id);
return getHashTable(table, (Integer) node.findValue("#hash"));
}
@Override
public String getTable(String table, Serializable userid) {
return getHashTable(table, (int) (((Long) userid) % 100));
}
private String getHashTable(String table, int hash) {
int pos = table.indexOf('.');
return "platf_login." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash));
}
}
}

View File

@@ -5,6 +5,7 @@
*/
package org.redkale.test.source;
import java.lang.reflect.Method;
import java.util.*;
import org.redkale.source.VirtualEntity;
import org.redkale.source.FilterNodeBean;
@@ -16,8 +17,10 @@ import org.redkale.source.Flipper;
import org.redkale.source.EntityInfo;
import org.redkale.source.FilterNode;
import java.util.concurrent.*;
import java.util.function.BiFunction;
import javax.persistence.*;
import org.redkale.convert.json.*;
import org.redkale.source.*;
/**
*
@@ -40,7 +43,11 @@ public class TestSourceCache {
}
public static void main(String[] args) throws Exception {
final EntityInfo<TestEntity> info = EntityInfo.load(TestEntity.class, 0, false, new Properties(), null, null);
final BiFunction<DataSource, Class, List> fullloader = (DataSource t, Class u) -> null;
Method method = EntityInfo.class.getDeclaredMethod("load", Class.class, int.class, boolean.class, Properties.class,
DataSource.class, BiFunction.class);
method.setAccessible(true);
final EntityInfo<TestEntity> info = (EntityInfo<TestEntity>) method.invoke(null, TestEntity.class, 0, false, new Properties(), null, fullloader);
TestEntity[] entitys = new TestEntity[10_0000];
for (int i = 0; i < entitys.length; i++) {
entitys[i] = new TestEntity(i + 1, "用户_" + (i + 1));

View File

@@ -0,0 +1,113 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.source;
import java.io.Serializable;
import javax.persistence.*;
import org.redkale.convert.*;
import org.redkale.source.*;
/**
*
* @author zhangjx
*/
@DistributeTable(strategy = UserDetail.TableStrategy.class)
public class UserDetail extends BaseEntity {
@Id
private long userid; //用户ID
@Column(length = 64, comment = "用户昵称")
private String username = ""; //用户昵称
@Column(length = 32, comment = "手机号码")
private String mobile = ""; //手机号码
@Column(length = 64, comment = "密码")
@ConvertColumn(ignore = true, type = ConvertType.ALL)
private String password = ""; //密码
@Column(length = 128, comment = "备注")
private String remark = ""; //备注
@Column(updatable = false, comment = "创建时间")
private long createtime; //创建时间
/** 以下省略getter setter方法 */
public long getUserid() {
return userid;
}
public void setUserid(long userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public long getCreatetime() {
return createtime;
}
public void setCreatetime(long createtime) {
this.createtime = createtime;
}
public static class TableStrategy implements DistributeTableStrategy<UserDetail> {
@Override
public String getTable(String table, UserDetail bean) {
return getTable(table, bean.getUserid());
}
@Override
public String getTable(String table, FilterNode node) {
Serializable id = node.findValue("userid");
if (id != null) return getTable(table, id);
return getHashTable(table, (Integer) node.findValue("#hash"));
}
@Override
public String getTable(String table, Serializable userid) {
return getHashTable(table, (int) (((Long) userid) % 100));
}
private String getHashTable(String table, int hash) {
int pos = table.indexOf('.');
return "platf_user." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash));
}
}
}