Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ea740edf1 | ||
|
|
716f4e6934 | ||
|
|
90ab302667 | ||
|
|
4695949362 | ||
|
|
4827893a0d | ||
|
|
9276f220b0 | ||
|
|
4071a5d165 | ||
|
|
da0ff24af6 | ||
|
|
afef635146 | ||
|
|
eda9d1c780 | ||
|
|
4b5749bc60 | ||
|
|
6bb23008c2 | ||
|
|
7746971b60 | ||
|
|
bc20c82fef | ||
|
|
fff70ed241 | ||
|
|
c590d45ce0 | ||
|
|
8bab9ad22b | ||
|
|
3c457dad2a | ||
|
|
eaae598234 | ||
|
|
606faf1bf8 | ||
|
|
ae9aa94323 | ||
|
|
2e41e44294 | ||
|
|
d806d9d6ff | ||
|
|
1260736c14 | ||
|
|
08c5cbbbf3 | ||
|
|
af0726cd79 | ||
|
|
ce2279030d | ||
|
|
83aba2ebee | ||
|
|
5c11742b51 | ||
|
|
5295e04275 | ||
|
|
47f723e63b | ||
|
|
54956e47d2 | ||
|
|
b2cbdf6642 | ||
|
|
989d1c6db9 | ||
|
|
e139b0cc5d | ||
|
|
66261e98b5 | ||
|
|
d9a268d30a | ||
|
|
a8bc50a947 | ||
|
|
6aa96daae2 | ||
|
|
293805a55e | ||
|
|
8b6319888c | ||
|
|
408676e97a | ||
|
|
1fabbae4f6 | ||
|
|
09a5b41d96 | ||
|
|
9d85a4dcaf | ||
|
|
9bc60c1c47 | ||
|
|
92aff864ef | ||
|
|
254e2e8ccd | ||
|
|
2480d127ac | ||
|
|
cc3d82e864 |
@@ -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>
|
||||
作为一个全新的微服务框架,不仅是使用了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/>
|
||||
与主流框架比,功能上Redkale显得很简单,这也是Redkale的一个特点并非不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,比如Redkale的HTTP服务不支持HTTPS和JSP,HTTPS比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很重要的一个思想。
|
||||
作为一个全新的微服务框架,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/>
|
||||
与主流框架比,功能上Redkale显得很简单,这体现了Redkale的简易性,而并非是不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持HTTPS和JSP,HTTPS比HTTP多了一层加密解密,这种密集型的计算不是Java的专长,通常提供HTTP服务的架构不会将Java动态服务器放在最前端,而是在前方会放nginx或apache,除了负载均衡还能静动分离,因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术,现在是一个多样化终端的时代,终端不只局限于桌面程序和PC浏览器,还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端,这些都不是JSP能方便兼顾的,而HTTP+JSON作为通用性接口可以避免重复开发,模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选,不会为了迎合主流而提供,而是以良好的设计思想为指导。这是Redkale的主导思维。
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
69
src/javax/persistence/Index.java
Normal file
69
src/javax/persistence/Index.java
Normal 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;
|
||||
|
||||
}
|
||||
@@ -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 "";
|
||||
|
||||
}
|
||||
|
||||
56
src/javax/persistence/UniqueConstraint.java
Normal file
56
src/javax/persistence/UniqueConstraint.java
Normal 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:
|
||||
* @Entity
|
||||
* @Table(
|
||||
* name="EMPLOYEE",
|
||||
* uniqueConstraints=
|
||||
* @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();
|
||||
}
|
||||
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;"> </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,"<").replace(/>/g,">").replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</td>');
|
||||
var rs = [];
|
||||
rs.push(action.result.replace(/</g, "<").replace(/>/g, ">").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,"<").replace(/>/g,">").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, "<").replace(/>/g, ">").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<') === 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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()) + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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 使用。
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值timeout=15秒)。
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
|
||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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值,鉴权时用到, 对应@WebAction.actionid
|
||||
|
||||
int cachetimeout() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应@HttpCacheable.timeout
|
||||
int cacheseconds() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应@HttpCacheable.seconds
|
||||
|
||||
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebAction.methods
|
||||
|
||||
//String contentType() default ""; //设置Response的ContentType 默认值为 text/plain; charset=utf-8
|
||||
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名,该值存在时则忽略contentType()的值
|
||||
}
|
||||
|
||||
@@ -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 ""; //备注描述
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* 根据指定参数查询对象某个字段的集合
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -54,4 +54,11 @@ public @interface FilterColumn {
|
||||
*/
|
||||
boolean itemand() default true;
|
||||
|
||||
/**
|
||||
* 备注描述
|
||||
*
|
||||
* @return 备注描述
|
||||
*/
|
||||
String comment() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,7 @@ public class HelloEntity {
|
||||
@RestAddress
|
||||
private String clientaddr;
|
||||
|
||||
/** 以下省略getter setter方法 */
|
||||
public int getHelloid() {
|
||||
return helloid;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
22
test/org/redkale/test/source/BaseEntity.java
Normal file
22
test/org/redkale/test/source/BaseEntity.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
138
test/org/redkale/test/source/LoginRecord.java
Normal file
138
test/org/redkale/test/source/LoginRecord.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
158
test/org/redkale/test/source/LoginRecord2.java
Normal file
158
test/org/redkale/test/source/LoginRecord2.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
92
test/org/redkale/test/source/LoginUserRecord.java
Normal file
92
test/org/redkale/test/source/LoginUserRecord.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
113
test/org/redkale/test/source/UserDetail.java
Normal file
113
test/org/redkale/test/source/UserDetail.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user