40 Commits
1.5.0 ... 1.5.1

Author SHA1 Message Date
Redkale
d891c6c8dc 2017-03-08 14:25:03 +08:00
Redkale
0a4a88ed5a 2017-03-08 14:03:05 +08:00
Redkale
3c02219da0 2017-03-08 09:57:08 +08:00
Redkale
65efc3372e 2017-03-07 17:44:50 +08:00
Redkale
3acea66788 2017-03-07 15:47:39 +08:00
Redkale
b448514e40 2017-03-07 11:58:27 +08:00
Redkale
024147344b 2017-03-07 10:09:26 +08:00
Redkale
52a34d3871 2017-03-07 09:42:03 +08:00
Redkale
1ada26e4dd 2017-03-07 09:39:16 +08:00
Redkale
94d1b61f81 2017-03-06 15:18:50 +08:00
Redkale
29299edb90 2017-03-06 14:45:35 +08:00
Redkale
a2e2c5e178 2017-03-06 12:02:00 +08:00
Redkale
8ae39df2e8 2017-03-06 09:29:25 +08:00
Redkale
508b269a82 2017-03-03 18:40:45 +08:00
Redkale
a8627b6105 2017-03-03 18:21:09 +08:00
Redkale
8fee6b2c68 2017-03-03 18:05:11 +08:00
Redkale
dd58571ffd 2017-03-03 17:50:50 +08:00
Redkale
8c25683cc5 增加javadoc注释 2017-03-03 14:49:32 +08:00
Redkale
a96f003b8c 2017-03-03 11:45:55 +08:00
Redkale
ff01443246 2017-03-02 19:59:42 +08:00
Redkale
e915a253f8 2017-03-02 16:03:29 +08:00
Redkale
b463389733 2017-03-02 15:43:34 +08:00
Redkale
41c97b92c7 删除DataSource.updateColumns方法,使用 DataSource.updateColumn代替 2017-03-02 14:21:47 +08:00
Redkale
1142f81e9c 删掉HttpResponse.finishJsResult方法 2017-03-02 14:13:29 +08:00
Redkale
5bc9f77b7b 修复HttpRequest.getBody由于URLDecode导致的BUG 2017-03-02 12:35:14 +08:00
Redkale
c5d0582807 修复HttpRequest.getBody由于URLDecode导致内容多余的BUG 2017-03-02 11:52:22 +08:00
Redkale
525e65d152 增加javadoc注释 2017-03-02 10:41:15 +08:00
Redkale
d948c7af47 增加javadoc注释 2017-03-02 10:02:45 +08:00
Redkale
11a29b4ed6 2017-03-01 20:59:00 +08:00
Redkale
e31c4a3041 DataSource增加支持Blob(byte[])类型字段功能 2017-02-28 13:37:38 +08:00
Redkale
2928d5fc93 2017-02-28 10:01:13 +08:00
Redkale
12fc6f7f10 2017-02-27 17:30:03 +08:00
Redkale
4bd8c207b4 增加javadoc注释 2017-02-27 17:15:14 +08:00
Redkale
be030a3640 增加javadoc注释 2017-02-27 17:11:23 +08:00
Redkale
ebaa250f7b 增加javadoc注释 2017-02-27 17:07:00 +08:00
Redkale
826a2d7ee6 增加javadoc注释 2017-02-27 15:06:31 +08:00
Redkale
e476cf8176 2017-02-27 13:54:23 +08:00
Redkale
03115694f9 增加javadoc注释 2017-02-27 12:01:39 +08:00
Redkale
26ffb04834 增加javadoc注释 2017-02-27 11:56:18 +08:00
Redkale
2979fcc33d 增加javadoc注释 2017-02-27 11:19:40 +08:00
101 changed files with 2400 additions and 1064 deletions

View File

@@ -42,8 +42,8 @@
一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内 一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。 一个group节点对应一个 Transport 对象。
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。 name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol只能是UDP TCP 默认TCP protocol范围:UDP TCP 默认TCP
kind: 与SNCP服务连接时的数据传输类型可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空 subprotocol: 子协议,预留字段。默认值为空
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。 注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
--> -->
<group name="" protocol="TCP"> <group name="" protocol="TCP">

View File

@@ -15,15 +15,17 @@ import org.redkale.source.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 WebAction 信息 * 继承 HttpBaseServlet 是为了获取 WebAction 信息
* *
* <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class ApiDocs extends HttpBaseServlet { public class ApiDocs extends HttpBaseServlet {
private final Application app; private final Application app; //Application全局对象
public ApiDocs(Application app) { public ApiDocs(Application app) {
this.app = app; this.app = app;

View File

@@ -30,9 +30,17 @@ import org.redkale.watch.WatchFactory;
import org.w3c.dom.*; import org.w3c.dom.*;
/** /**
* 编译时需要加入: -XDignore.symbol.file=true *
* 进程启动类,全局对象。 <br>
* <pre>
* 程序启动执行步骤:
* 1、读取application.xml
* 2、进行classpath扫描动态加载Service与Servlet
* 3、优先加载所有SNCP协议的服务再加载其他协议服务
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
* </pre>
* <p> * <p>
* 进程启动类程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet 优先加载所有SNCP协议的服务 再加载其他协议服务, 最后进行Service、Servlet与其他资源之间的依赖注入。 * 编译时需要加入: -XDignore.symbol.file=true
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -40,65 +48,99 @@ import org.w3c.dom.*;
*/ */
public final class Application { public final class Application {
//当前进程启动的时间, 类型: long /**
* 当前进程启动的时间, 类型: long
*/
public static final String RESNAME_APP_TIME = "APP_TIME"; public static final String RESNAME_APP_TIME = "APP_TIME";
//当前进程的根目录, 类型String、File、Path /**
* 当前进程的根目录, 类型String、File、Path
*/
public static final String RESNAME_APP_HOME = "APP_HOME"; public static final String RESNAME_APP_HOME = "APP_HOME";
//application.xml 文件中resources节点的内容 类型: AnyValue /**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
public static final String RESNAME_APP_GRES = "APP_GRES"; public static final String RESNAME_APP_GRES = "APP_GRES";
//当前进程节点的name 类型String /**
* 当前进程节点的name 类型String
*/
public static final String RESNAME_APP_NODE = "APP_NODE"; public static final String RESNAME_APP_NODE = "APP_NODE";
//当前进程节点的IP地址 类型InetAddress、String /**
* 当前进程节点的IP地址 类型InetAddress、String
*/
public static final String RESNAME_APP_ADDR = "APP_ADDR"; public static final String RESNAME_APP_ADDR = "APP_ADDR";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String /**
* 当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
*/
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR"; public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
//当前SNCP Server所属的组 类型: String /**
* 当前SNCP Server所属的组 类型: String
*/
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP"; public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
//当前Server的ROOT目录 类型String、File、Path /**
* 当前Server的ROOT目录 类型String、File、Path
*/
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT; public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
//每个地址对应的Group名
final Map<InetSocketAddress, String> globalNodes = new HashMap<>(); final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
//协议地址的Group集合
final Map<String, GroupInfo> globalGroups = new HashMap<>(); final Map<String, GroupInfo> globalGroups = new HashMap<>();
//本地IP地址
final InetAddress localAddress; final InetAddress localAddress;
//CacheSource 资源
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>(); final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
//DataSource 资源
final List<DataSource> dataSources = new CopyOnWriteArrayList<>(); final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
//NodeServer 资源
final List<NodeServer> servers = new CopyOnWriteArrayList<>(); final List<NodeServer> servers = new CopyOnWriteArrayList<>();
//传输端的ByteBuffer对象池
final ObjectPool<ByteBuffer> transportBufferPool; final ObjectPool<ByteBuffer> transportBufferPool;
//传输端的线程池
final ExecutorService transportExecutor; final ExecutorService transportExecutor;
//传输端的ChannelGroup
final AsynchronousChannelGroup transportChannelGroup; final AsynchronousChannelGroup transportChannelGroup;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root(); final ResourceFactory resourceFactory = ResourceFactory.root();
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值 CountDownLatch servicecdl; //会出现两次赋值
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun; private final boolean singletonrun;
//根WatchFactory
private final WatchFactory watchFactory = WatchFactory.root(); private final WatchFactory watchFactory = WatchFactory.root();
//进程根目录
private final File home; private final File home;
//日志
private final Logger logger; private final Logger logger;
//服务配置项
private final AnyValue config; private final AnyValue config;
//服务启动时间
private final long startTime = System.currentTimeMillis(); private final long startTime = System.currentTimeMillis();
//Server启动的计数器用于确保所有Server都启动完后再进行下一步处理
private final CountDownLatch serversLatch; private final CountDownLatch serversLatch;
private Application(final AnyValue config) { private Application(final AnyValue config) {
@@ -164,7 +206,8 @@ public final class Application {
Properties prop = new Properties(); Properties prop = new Properties();
final String handlers = properties.getProperty("handlers"); final String handlers = properties.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass)); //singletonrun模式下不输出文件日志
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", singletonrun ? "" : fileHandlerClass));
} }
if (!prop.isEmpty()) { if (!prop.isEmpty()) {
String prefix = fileHandlerClass + "."; String prefix = fileHandlerClass + ".";
@@ -189,7 +232,7 @@ public final class Application {
} }
this.logger = Logger.getLogger(this.getClass().getSimpleName()); this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1); this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
logger.log(Level.INFO, "------------------------------- Redkale ------------------------------"); logger.log(Level.INFO, "------------------------------- Redkale -------------------------------");
//------------------配置 <transport> 节点 ------------------ //------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null; ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null; ExecutorService transportExec = null;
@@ -333,7 +376,7 @@ public final class Application {
} }
GroupInfo ginfo = globalGroups.get(group); GroupInfo ginfo = globalGroups.get(group);
if (ginfo == null) { if (ginfo == null) {
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>()); ginfo = new GroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
globalGroups.put(group, ginfo); globalGroups.put(group, ginfo);
} }
for (AnyValue node : conf.getAnyValues("node")) { for (AnyValue node : conf.getAnyValues("node")) {
@@ -423,6 +466,7 @@ public final class Application {
channel.write(buffer); channel.write(buffer);
buffer.clear(); buffer.clear();
channel.configureBlocking(false); channel.configureBlocking(false);
try {
channel.read(buffer); channel.read(buffer);
buffer.flip(); buffer.flip();
byte[] bytes = new byte[buffer.remaining()]; byte[] bytes = new byte[buffer.remaining()];
@@ -430,6 +474,19 @@ public final class Application {
channel.close(); channel.close();
logger.info(new String(bytes)); logger.info(new String(bytes));
Thread.sleep(500); Thread.sleep(500);
} catch (Exception e) {
if (e instanceof PortUnreachableException) {
if ("APIDOC".equalsIgnoreCase(command)) {
final Application application = Application.create(true);
application.init();
application.start();
new ApiDocs(application).run();
logger.info("APIDOC OK");
return;
}
}
throw e;
}
} }
public void start() throws Exception { public void start() throws Exception {

View File

@@ -28,9 +28,9 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class ClassFilter<T> { public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER); private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果 private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果

View File

@@ -9,6 +9,7 @@ import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
/** /**
* 协议地址组合对象, 对应application.xml 中 resources-&#62;group 节点信息
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,21 +18,21 @@ import java.util.*;
*/ */
public class GroupInfo { public class GroupInfo {
protected String name; protected String name; //地址
protected String protocol; protected String protocol; //协议 取值范围: TCP、UDP
protected String kind; protected String subprotocol; //子协议,预留使用
protected Set<InetSocketAddress> addrs; protected Set<InetSocketAddress> addrs; //地址列表, 对应 resources-&#62;group-&#62;node节点信息
public GroupInfo() { public GroupInfo() {
} }
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) { public GroupInfo(String name, String protocol, String subprotocol, Set<InetSocketAddress> addrs) {
this.name = name; this.name = name;
this.protocol = protocol; this.protocol = protocol;
this.kind = kind; this.subprotocol = subprotocol;
this.addrs = addrs; this.addrs = addrs;
} }
@@ -51,12 +52,12 @@ public class GroupInfo {
this.protocol = protocol; this.protocol = protocol;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void setKind(String kind) { public void setSubprotocol(String subprotocol) {
this.kind = kind; this.subprotocol = subprotocol;
} }
public Set<InetSocketAddress> getAddrs() { public Set<InetSocketAddress> getAddrs() {

View File

@@ -29,7 +29,7 @@ import org.redkale.util.*;
@NodeProtocol({"HTTP"}) @NodeProtocol({"HTTP"})
public class NodeHttpServer extends NodeServer { public class NodeHttpServer extends NodeServer {
protected final boolean rest; protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestHttpServlet
protected final HttpServer httpServer; protected final HttpServer httpServer;

View File

@@ -9,6 +9,7 @@ import java.util.Objects;
import org.redkale.service.Service; import org.redkale.service.Service;
/** /**
* NodeServer的拦截类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,10 +18,22 @@ import org.redkale.service.Service;
*/ */
public class NodeInterceptor { public class NodeInterceptor {
/** *
* Server.start之前调用 <br>
* NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法
*
* @param server NodeServer
*/
public void preStart(NodeServer server) { public void preStart(NodeServer server) {
} }
/**
* Server.shutdown之前调用 <br>
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.sshutdown 方法
*
* @param server NodeServer
*/
public void preShutdown(NodeServer server) { public void preShutdown(NodeServer server) {
} }

View File

@@ -276,8 +276,8 @@ public abstract class NodeServer {
if (WebSocketNode.class.isAssignableFrom(type)) continue; if (WebSocketNode.class.isAssignableFrom(type)) continue;
} }
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty()); if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (resourceFactory.find(entry.getName(), type) != null) { //Server加载Service时需要判断是否已经加载过了。
Service oldother = resourceFactory.find(entry.getName(), type); Service oldother = resourceFactory.find(entry.getName(), type);
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother)); interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother));
continue; continue;
} }
@@ -403,7 +403,7 @@ public abstract class NodeServer {
Transport first = transports.get(0); Transport first = transports.get(0);
GroupInfo ginfo = application.findGroupInfo(first.getName()); GroupInfo ginfo = application.findGroupInfo(first.getName());
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(), Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.resourceFactory) { synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(groupid, Transport.class); transport = application.resourceFactory.find(groupid, Transport.class);
if (transport == null) { if (transport == null) {
@@ -429,7 +429,7 @@ public abstract class NodeServer {
Set<InetSocketAddress> addrs = ginfo.copyAddrs(); Set<InetSocketAddress> addrs = ginfo.copyAddrs();
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> "); if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(), transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport); application.resourceFactory.register(group, transport);
} }
return transport; return transport;

View File

@@ -9,9 +9,9 @@ import java.lang.reflect.*;
import java.util.*; import java.util.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有采用int存储。 * 对象数组的反序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,9 +8,9 @@ package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有必要采用int存储。 * 对象数组的序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -11,9 +11,8 @@ import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的反序列化. * Collection的反序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -9,9 +9,8 @@ import java.lang.reflect.*;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的序列化. * Collection的序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -6,7 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化操作类 * 序列化/反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -10,11 +10,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 用于类名的别名 类似javax.persistence.Table * 用于类名的别名, 该值必须是全局唯一 <br>
* 该值必须是全局唯一
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。 * 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@@ -23,5 +24,10 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ConvertEntity { public @interface ConvertEntity {
/**
* 别名值
*
* @return String
*/
String value(); String value();
} }

View File

@@ -5,8 +5,11 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化自定义异常类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class ConvertException extends RuntimeException { public class ConvertException extends RuntimeException {

View File

@@ -17,6 +17,7 @@ import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -104,6 +105,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(double[].class, DoubleArraySimpledCoder.instance); this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance); this.register(String[].class, StringArraySimpledCoder.instance);
//--------------------------------------------------------- //---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() { this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override @Override
@Creator.ConstructorParameters({"name", "value"}) @Creator.ConstructorParameters({"name", "value"})

View File

@@ -6,8 +6,11 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化类型枚举,结合&#64;ConvertColumn使用
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public enum ConvertType { public enum ConvertType {

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -11,6 +11,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -10,6 +10,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -13,6 +13,7 @@ import java.util.Set;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 自定义对象的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -85,6 +86,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (method.isSynthetic()) continue; if (method.isSynthetic()) continue;
if (method.getName().length() < 4) continue; if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue; if (!method.getName().startsWith("set")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 1) continue; if (method.getParameterTypes().length != 1) continue;
if (method.getReturnType() != void.class) continue; if (method.getReturnType() != void.class) continue;
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) { if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {

View File

@@ -10,6 +10,7 @@ import java.util.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 自定义对象的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -77,6 +78,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (method.getName().length() < 3) continue; if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue; if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 0) continue; if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue; if (method.getReturnType() == void.class) continue;
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) { if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {

View File

@@ -6,6 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 反序列化的数据读取流
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -42,6 +43,7 @@ public abstract class Reader {
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。 * 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
* *
* @param clazz 类名 * @param clazz 类名
*
* @return 返回字段数 * @return 返回字段数
*/ */
public String readObjectB(final Class clazz) { public String readObjectB(final Class clazz) {
@@ -86,6 +88,7 @@ public abstract class Reader {
* 根据字段读取字段对应的DeMember * 根据字段读取字段对应的DeMember
* *
* @param members DeMember的全量集合 * @param members DeMember的全量集合
*
* @return 匹配的DeMember * @return 匹配的DeMember
*/ */
public abstract DeMember readFieldName(final DeMember[] members); public abstract DeMember readFieldName(final DeMember[] members);

View File

@@ -9,6 +9,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 简易类的序列化和反序列化操作类
* 能序列化为Boolean、Number或者字符串的类视为简易类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 序列化的数据输出流
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -15,21 +15,21 @@ import org.redkale.util.*;
/** /**
* <blockquote><pre> * <blockquote><pre>
* BSON协议格式: * BSON协议格式:
* 1). 基本数据类型: 直接转换成byte[] * 1) 基本数据类型: 直接转换成byte[]
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 * 2) SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3). String: length(4 bytes) + byte[](utf8); * 3) String: length(4 bytes) + byte[](utf8);
* 4). 数组: length(4 bytes) + byte[]... * 4) 数组: length(4 bytes) + byte[]...
* 5). Object: * 5) Object:
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名) * 1 realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2. 空字符串(SmallString) * 2 空字符串(SmallString)
* 3. SIGN_OBJECTB 标记位值固定为0xBB (short) * 3 SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4. 循环字段值: * 4 循环字段值:
* 4.1 SIGN_HASNEXT 标记位值固定为1 (byte) * 4.1 SIGN_HASNEXT 标记位值固定为1 (byte)
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object * 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
* 4.3 字段名 (SmallString) * 4.3 字段名 (SmallString)
* 4.4 字段的值Object * 4.4 字段的值Object
* 5. SIGN_NONEXT 标记位值固定为0 (byte) * 5 SIGN_NONEXT 标记位值固定为0 (byte)
* 6. SIGN_OBJECTE 标记位值固定为0xEE (short) * 6 SIGN_OBJECTE 标记位值固定为0xEE (short)
* *
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>

View File

@@ -7,6 +7,7 @@ package org.redkale.convert.bson;
import java.io.Serializable; import java.io.Serializable;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.util.AnyValue;
/** /**
* *
@@ -27,6 +28,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
static { static {
instance.register(Serializable.class, objectDecoder); instance.register(Serializable.class, objectDecoder);
instance.register(Serializable.class, objectEncoder); instance.register(Serializable.class, objectEncoder);
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private BsonFactory(BsonFactory parent, boolean tiny) { private BsonFactory(BsonFactory parent, boolean tiny) {

View File

@@ -5,7 +5,6 @@
*/ */
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.util.function.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL; import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
@@ -42,19 +41,7 @@ public class BsonReader extends Reader {
} }
public static ObjectPool<BsonReader> createPool(int max) { public static ObjectPool<BsonReader> createPool(int max) {
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() { return new ObjectPool<>(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle());
@Override
public BsonReader create(Object... params) {
return new BsonReader();
}
}, null, new Predicate<BsonReader>() {
@Override
public boolean test(BsonReader t) {
return t.recycle();
}
});
} }
public BsonReader(byte[] bytes) { public BsonReader(byte[] bytes) {

View File

@@ -6,7 +6,6 @@
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.Predicate;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -28,19 +27,7 @@ public class BsonWriter extends Writer {
protected boolean tiny; protected boolean tiny;
public static ObjectPool<BsonWriter> createPool(int max) { public static ObjectPool<BsonWriter> createPool(int max) {
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() { return new ObjectPool<>(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
@Override
public BsonWriter create(Object... params) {
return new BsonWriter();
}
}, null, new Predicate<BsonWriter>() {
@Override
public boolean test(BsonWriter t) {
return t.recycle();
}
});
} }
public byte[] toArray() { public byte[] toArray() {
@@ -82,6 +69,7 @@ public class BsonWriter extends Writer {
* 扩充指定长度的缓冲区 * 扩充指定长度的缓冲区
* *
* @param len 扩容长度 * @param len 扩容长度
*
* @return 固定0 * @return 固定0
*/ */
protected int expand(int len) { protected int expand(int len) {

View File

@@ -10,7 +10,7 @@ import java.math.BigInteger;
import java.net.*; import java.net.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
import org.redkale.util.DLong; import org.redkale.util.*;
/** /**
* *
@@ -29,6 +29,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance); instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
instance.register(Serializable.class, instance.loadEncoder(Object.class)); instance.register(Serializable.class, instance.loadEncoder(Object.class));
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private JsonFactory(JsonFactory parent, boolean tiny) { private JsonFactory(JsonFactory parent, boolean tiny) {

View File

@@ -17,42 +17,60 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* 服务器上下文对象
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class Context { public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Charset UTF8 = Charset.forName("UTF-8");
//服务启动时间
protected final long serverStartTime; protected final long serverStartTime;
//Server的线程池
protected final ExecutorService executor; protected final ExecutorService executor;
//ByteBuffer的容量默认8K
protected final int bufferCapacity; protected final int bufferCapacity;
//ByteBuffer对象池
protected final ObjectPool<ByteBuffer> bufferPool; protected final ObjectPool<ByteBuffer> bufferPool;
//Response对象池
protected final ObjectPool<Response> responsePool; protected final ObjectPool<Response> responsePool;
//服务的根Servlet
protected final PrepareServlet prepare; protected final PrepareServlet prepare;
//服务的监听地址
private final InetSocketAddress address; private final InetSocketAddress address;
//字符集
protected final Charset charset; protected final Charset charset;
//请求内容的大小上限, 默认64K
protected final int maxbody; protected final int maxbody;
//IO读取的超时时间
protected final int readTimeoutSecond; protected final int readTimeoutSecond;
//IO写入的超时时间
protected final int writeTimeoutSecond; protected final int writeTimeoutSecond;
//日志Logger
protected final Logger logger; protected final Logger logger;
//BSON操作工厂
protected final BsonFactory bsonFactory; protected final BsonFactory bsonFactory;
//JSON操作工厂
protected final JsonFactory jsonFactory; protected final JsonFactory jsonFactory;
//监控对象
protected final WatchFactory watch; protected final WatchFactory watch;
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,

View File

@@ -11,8 +11,11 @@ import java.util.logging.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 根Servlet的处理逻辑类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -14,6 +14,9 @@ import java.util.logging.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 根Servlet 一个Server只能存在一个根Servlet
*
* 用于分发Request请求
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -13,6 +13,7 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议底层Server
* *
* <p> 详情见: https://redkale.org * <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
/** /**
* 协议请求对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -10,6 +10,7 @@ import java.nio.channels.CompletionHandler;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/** /**
* 协议响应对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -147,6 +148,15 @@ public abstract class Response<C extends Context, R extends Request<C>> {
return output; return output;
} }
/**
* 是否已关闭
*
* @return boolean
*/
public boolean isClosed() {
return !this.inited;
}
public void finish() { public void finish() {
this.finish(false); this.finish(false);
} }
@@ -157,6 +167,17 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.context.responsePool.offer(this); this.context.responsePool.offer(this);
} }
public void finish(final byte[] bs) {
if (this.context.bufferCapacity == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(buffer);
} else {
this.finish(ByteBuffer.wrap(bs));
}
}
public void finish(ByteBuffer buffer) { public void finish(ByteBuffer buffer) {
this.channel.write(buffer, buffer, finishHandler); this.channel.write(buffer, buffer, finishHandler);
} }

View File

@@ -9,6 +9,7 @@ import org.redkale.util.AnyValue;
import java.io.IOException; import java.io.IOException;
/** /**
* 协议请求处理类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -44,7 +44,7 @@ public final class Transport {
protected final String name; //即<group>的name属性 protected final String name; //即<group>的name属性
protected final String kind; //即<group>的kind属性 protected final String subprotocol; //即<group>的subprotocol属性
protected final boolean tcp; protected final boolean tcp;
@@ -62,16 +62,16 @@ public final class Transport {
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
public Transport(String name, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool, public Transport(String name, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses); this(name, DEFAULT_PROTOCOL, watch, subprotocol, transportBufferPool, transportChannelGroup, clientAddress, addresses);
} }
public Transport(String name, String protocol, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool, public Transport(String name, String protocol, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name; this.name = name;
this.watch = watch; this.watch = watch;
this.kind = kind == null ? "" : kind.trim(); this.subprotocol = subprotocol == null ? "" : subprotocol.trim();
this.protocol = protocol; this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol); this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup; this.group = transportChannelGroup;
@@ -83,14 +83,17 @@ public final class Transport {
public Transport(final Collection<Transport> transports) { public Transport(final Collection<Transport> transports) {
Transport first = null; Transport first = null;
List<String> tmpgroup = new ArrayList<>(); List<String> tmpgroup = new ArrayList<>();
if (transports != null) {
for (Transport t : transports) { for (Transport t : transports) {
if (first == null) first = t; if (first == null) first = t;
tmpgroup.add(t.name); tmpgroup.add(t.name);
} }
}
if (first == null) throw new NullPointerException("Collection<Transport> is null or empty");
//必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name //必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";")); this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
this.watch = first.watch; this.watch = first.watch;
this.kind = first.kind; this.subprotocol = first.subprotocol;
this.protocol = first.protocol; this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol); this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group; this.group = first.group;
@@ -118,8 +121,8 @@ public final class Transport {
return name; return name;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void close() { public void close() {

View File

@@ -8,8 +8,11 @@ package org.redkale.net;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议处理的自定义线程类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class WorkThread extends Thread { public class WorkThread extends Thread {

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP服务的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -17,6 +17,8 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP Servlet的总入口请求在HttpPrepareServlet中进行分流。 <br>
* 一个HttpServer只有一个HttpPrepareServlet 用于管理所有HttpServlet。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -89,6 +91,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
} }
//找不到匹配的HttpServlet则使用静态资源HttpResourceServlet
if (servlet == null) servlet = this.resourceHttpServlet; if (servlet == null) servlet = this.resourceHttpServlet;
servlet.execute(request, response); servlet.execute(request, response);
} catch (Exception e) { } catch (Exception e) {
@@ -97,6 +100,14 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param prefix url前缀
* @param conf 配置信息
* @param mappings 匹配规则
*/
@Override @Override
public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) { public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) {
if (prefix == null) prefix = ""; if (prefix == null) prefix = "";
@@ -107,12 +118,12 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix
} }
} }
synchronized (allMapStrings) { synchronized (allMapStrings) { //需要整段锁住
for (String mapping : mappings) { for (String mapping : mappings) {
if (mapping == null) continue; if (mapping == null) continue;
if (!prefix.toString().isEmpty()) mapping = prefix + mapping; if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式)) if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.charAt(0) != '^') mapping = '^' + mapping; if (mapping.charAt(0) != '^') mapping = '^' + mapping;
if (mapping.endsWith("/*")) { if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*"; mapping = mapping.substring(0, mapping.length() - 1) + ".*";
@@ -141,22 +152,22 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
private static boolean contains(String string, char... values) { /**
if (string == null) return false; * 设置静态资源HttpServlet
for (char ch : Utility.charArray(string)) { *
for (char ch2 : values) { * @param servlet HttpServlet
if (ch == ch2) return true; */
}
}
return false;
}
public void setResourceServlet(HttpServlet servlet) { public void setResourceServlet(HttpServlet servlet) {
if (servlet != null) { if (servlet != null) {
this.resourceHttpServlet = servlet; this.resourceHttpServlet = servlet;
} }
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() { public HttpServlet getResourceServlet() {
return this.resourceHttpServlet; return this.resourceHttpServlet;
} }

View File

@@ -22,7 +22,7 @@ import org.redkale.util.ByteArray;
* 例如简单的翻页查询 <br> * 例如简单的翻页查询 <br>
* /pipes/record/query/offset:0/limit:20 <br> * /pipes/record/query/offset:0/limit:20 <br>
* 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br> * 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br>
* 获取行数: int limit = request.getRequstURIPath("limit:", 10); * 获取行数: int limit = request.getRequstURIPath("limit:", 10); <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -352,7 +352,7 @@ public class HttpRequest extends Request<HttpContext> {
public String getSessionid(boolean create) { public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null); String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) { if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid(); sessionid = context.createSessionid();
this.newsessionid = sessionid; this.newsessionid = sessionid;
} }
return sessionid; return sessionid;
@@ -368,6 +368,18 @@ public class HttpRequest extends Request<HttpContext> {
return newsessionid; return newsessionid;
} }
/**
* 指定值更新sessionid
*
* @param newsessionid 新sessionid值
*
* @return 新的sessionid值
*/
public String changeSessionid(String newsessionid) {
this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim();
return newsessionid;
}
/** /**
* 使sessionid失效 * 使sessionid失效
*/ */
@@ -1109,17 +1121,18 @@ public class HttpRequest extends Request<HttpContext> {
* @return Flipper翻页对象 * @return Flipper翻页对象
*/ */
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) { public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name);
if (flipper == null) { if (flipper == null) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
int limit = getRequstURIPath("limit:", maxLimit); int limit = getRequstURIPath("limit:", maxLimit);
int offset = getRequstURIPath("offset:", 0); int offset = getRequstURIPath("offset:", 0);
String sort = getRequstURIPath("sort:", ""); String sort = getRequstURIPath("sort:", "");
if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, sort); if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, sort);
} else if (flipper.getLimit() < 1 || flipper.getLimit() > maxLimit) { } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) {
flipper.setLimit(maxLimit); flipper.setLimit(maxLimit);
} }
if (flipper != null || !needcreate) return flipper; if (flipper != null || !needcreate) return flipper;
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
return new org.redkale.source.Flipper(maxLimit); return new org.redkale.source.Flipper(maxLimit);
} }
} }

View File

@@ -18,6 +18,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
/** /**
* 静态资源HttpServlet
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -21,9 +21,9 @@ import org.redkale.util.AnyValue.Entry;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 * Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 <br>
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) * 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) <br>
* Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 * Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -290,31 +290,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
finish(convert.convertTo(context.getBufferSupplier(), ret)); finish(convert.convertTo(context.getBufferSupplier(), ret));
} }
/**
* 将对象以JavaScript格式输出
*
* @param var js变量名
* @param result 输出对象
*/
public void finishJsResult(String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
if (this.recycleListener != null) this.output = result;
finish("var " + var + " = " + request.getJsonConvert().convertTo(result) + ";");
}
/**
* 将对象以JavaScript格式输出
*
* @param jsonConvert 指定的JsonConvert
* @param var js变量名
* @param result 输出对象
*/
public void finishJsResult(JsonConvert jsonConvert, String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
if (this.recycleListener != null) this.output = result;
finish("var " + var + " = " + jsonConvert.convertTo(result) + ";");
}
/** /**
* 将指定字符串以响应结果输出 * 将指定字符串以响应结果输出
* *
@@ -381,6 +356,23 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
super.finish(buffer404.duplicate()); super.finish(buffer404.duplicate());
} }
/**
* 将指定byte[]按响应结果输出
*
* @param bs 输出内容
*/
@Override
public void finish(final byte[] bs) {
if (this.context.getBufferCapacity() == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(false, buffer);
} else {
this.finish(false, ByteBuffer.wrap(bs));
}
}
/** /**
* 将指定ByteBuffer按响应结果输出 * 将指定ByteBuffer按响应结果输出
* *

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.WatchFactory; import org.redkale.watch.WatchFactory;
/** /**
* Http服务器
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -37,24 +38,88 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
super.init(config); super.init(config);
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() {
return ((HttpPrepareServlet) this.prepare).resourceHttpServlet;
}
/**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, prefix, null, mappings); this.prepare.addServlet(servlet, prefix, null, mappings);
return this; return this;
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, null, null, mappings); this.prepare.addServlet(servlet, null, null, mappings);
return this; return this;
} }
public void addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) { /**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param conf 配置信息
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) {
this.prepare.addServlet(servlet, prefix, conf, mappings); this.prepare.addServlet(servlet, prefix, conf, mappings);
return this;
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) { public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) {
return addRestServlet(name, serviceType, service, baseServletClass, prefix, null); return addRestServlet(name, serviceType, service, baseServletClass, prefix, null);
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
* @param conf 配置信息
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet( public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(
final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) { final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
RestHttpServlet servlet = null; RestHttpServlet servlet = null;

View File

@@ -8,6 +8,7 @@ package org.redkale.net.http;
import java.util.*; import java.util.*;
/** /**
* MimeType
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -100,6 +101,7 @@ public class MimeType {
contentTypes.put("oda", "application/oda"); contentTypes.put("oda", "application/oda");
contentTypes.put("ogg", "application/ogg"); contentTypes.put("ogg", "application/ogg");
contentTypes.put("out", "text/plain"); contentTypes.put("out", "text/plain");
contentTypes.put("pac", "application/x-javascript-config");
contentTypes.put("pbm", "image/x-portable-bitmap"); contentTypes.put("pbm", "image/x-portable-bitmap");
contentTypes.put("pct", "image/pict"); contentTypes.put("pct", "image/pict");
contentTypes.put("pdf", "application/pdf"); contentTypes.put("pdf", "application/pdf");

View File

@@ -15,6 +15,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* HTTP的文件上传请求的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -77,10 +78,21 @@ public final class MultiContext {
return null; return null;
} }
/**
* 判断请求是否包含上传文件
*
* @return boolean
*/
public boolean isMultipart() { public boolean isMultipart() {
return this.boundary != null; return this.boundary != null;
} }
/**
* 获取上传文件信息列表
*
* @return Iterable
* @throws IOException IOException
*/
public Iterable<MultiPart> parts() throws IOException { public Iterable<MultiPart> parts() throws IOException {
if (!isMultipart()) return emptyIterable; if (!isMultipart()) return emptyIterable;
final String boundarystr = "--" + this.boundary; final String boundarystr = "--" + this.boundary;

View File

@@ -254,7 +254,6 @@ public final class Rest {
final int maxStack = 3 + params.length; final int maxStack = 3 + params.length;
List<int[]> varInsns = new ArrayList<>(); List<int[]> varInsns = new ArrayList<>();
int maxLocals = 4; int maxLocals = 4;
final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar;
int argIndex = 0; int argIndex = 0;
List<Object[]> paramlist = new ArrayList<>(); List<Object[]> paramlist = new ArrayList<>();
@@ -731,214 +730,110 @@ public final class Rest {
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
} else if (returnType == boolean.class) { } else if (returnType == boolean.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == byte.class) { } else if (returnType == byte.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == short.class) { } else if (returnType == short.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == char.class) { } else if (returnType == char.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == int.class) { } else if (returnType == int.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == float.class) { } else if (returnType == float.class) {
mv.visitVarInsn(FSTORE, maxLocals); mv.visitVarInsn(FSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(FLOAD, maxLocals); mv.visitVarInsn(FLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(FLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == long.class) { } else if (returnType == long.class) {
mv.visitVarInsn(LSTORE, maxLocals); mv.visitVarInsn(LSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(LLOAD, maxLocals); mv.visitVarInsn(LLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(LLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == double.class) { } else if (returnType == double.class) {
mv.visitVarInsn(DSTORE, maxLocals); mv.visitVarInsn(DSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(DLOAD, maxLocals); mv.visitVarInsn(DLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(DLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == String.class) { } else if (returnType == String.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == File.class) { } else if (returnType == File.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false);
} else {
throw new RuntimeException(method + " cannot set return Type (java.io.File) to jsvar");
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RetResult.class.isAssignableFrom(returnType)) { } else if (RetResult.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RestOutput.class.isAssignableFrom(returnType)) { } else if (RestOutput.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJsResult", "(" + respDesc + "Ljava/lang/String;" + restoutputDesc + ")V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面 } else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else { } else {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} }
@@ -1020,7 +915,6 @@ public final class Rest {
this.actionid = mapping.actionid(); this.actionid = mapping.actionid();
this.cacheseconds = mapping.cacheseconds(); this.cacheseconds = mapping.cacheseconds();
this.comment = mapping.comment(); this.comment = mapping.comment();
this.jsvar = mapping.jsvar();
} }
public final Method mappingMethod; public final Method mappingMethod;
@@ -1039,8 +933,6 @@ public final class Rest {
public final int cacheseconds; public final int cacheseconds;
public final String jsvar;
@RestMapping() @RestMapping()
void mapping() { //用于获取Mapping 默认值 void mapping() { //用于获取Mapping 默认值
} }

View File

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestCookie { public @interface RestCookie {
String name(); //cookie名 /**
* cookie名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestHeader { public @interface RestHeader {
String name(); //参数名 /**
* Header参数名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -23,22 +23,17 @@ public abstract class RestHttpServlet<T> extends HttpBaseServlet {
response.finishJson(output); response.finishJson(output);
return; return;
} }
if (output.getContentType() != null) response.setContentType(output.getContentType());
response.addHeader(output.getHeaders()); response.addHeader(output.getHeaders());
response.addCookie(output.getCookies()); response.addCookie(output.getCookies());
if (output.getResult() instanceof File) { if (output.getResult() instanceof File) {
response.finish((File) output.getResult()); response.finish((File) output.getResult());
} else if (output.getResult() instanceof String) {
response.finish((String) output.getResult());
} else { } else {
response.finishJson(output.getResult()); response.finishJson(output.getResult());
} }
} }
protected void finishJsResult(final HttpResponse response, final String var, RestOutput output) throws IOException {
if (output != null) {
response.addHeader(output.getHeaders());
response.addCookie(output.getCookies());
}
response.finishJsResult(var, output == null ? null : output.getResult());
}
} }

View File

@@ -10,8 +10,8 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*; import static java.lang.annotation.RetentionPolicy.*;
/** /**
* 只能依附在Service实现类的public方法上 * 只能依附在Service实现类的public方法上 <br>
* value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。 * value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -24,25 +24,54 @@ import static java.lang.annotation.RetentionPolicy.*;
@Repeatable(RestMappings.class) @Repeatable(RestMappings.class)
public @interface RestMapping { public @interface RestMapping {
boolean ignore() default false; //是否屏蔽该方法的转换 /**
* 是否屏蔽该方法的转换
*
* @return boolean
*/
boolean ignore() default false;
/** /**
* 请求的方法名, 不能含特殊字符 * 请求的方法名, 不能含特殊字符
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX、existsXXX且XXXService为Service的类名将只截取XXX之前) * 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX、existsXXX且XXXService为Service的类名将只截取XXX之前)
* *
* @return name * @return String
*/ */
String name() default ""; String name() default "";
String comment() default ""; //备注描述, 对应&#64;WebAction.comment /**
* 备注描述, 对应&#64;WebAction.comment
*
* @return String
*/
String comment() default "";
boolean auth() default false; //是否鉴权,默认不鉴权, 对应&#64;AuthIgnore /**
* 是否鉴权,默认不鉴权, 对应&#64;AuthIgnore
*
* @return boolean
*/
boolean auth() default false;
int actionid() default 0; //操作ID值鉴权时用到, 对应&#64;WebAction.actionid /**
* 操作ID值鉴权时用到, 对应&#64;WebAction.actionid
*
* @return int
*/
int actionid() default 0;
int cacheseconds() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.seconds /**
* 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.seconds
*
* @return int
*/
int cacheseconds() default 0;
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods /**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods
*
* @return String[]
*/
String[] methods() default {};
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名该值存在时则忽略contentType()的值
} }

View File

@@ -23,6 +23,8 @@ public class RestOutput<T> {
private List<HttpCookie> cookies; private List<HttpCookie> cookies;
private String contentType;
private T result; private T result;
public RestOutput() { public RestOutput() {
@@ -58,6 +60,14 @@ public class RestOutput<T> {
this.cookies = cookies; this.cookies = cookies;
} }
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() { public T getResult() {
return result; return result;
} }

View File

@@ -11,10 +11,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* *
* 依附在RestService类的方法的参数上 * 依附在RestService类的方法的参数上 <br>
* name='&#38;' 表示当前用户 * name='&#38;' 表示当前用户 <br>
* name='#'表示截取uri最后一段 * name='#'表示截取uri最后一段 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 * name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -26,11 +26,35 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestParam { public @interface RestParam {
String name(); //参数名 name='&'表示当前用户; name='#'表示截取uri最后一段; name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 //name='&'表示当前用户;
/**
* 参数名 <br>
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
boolean required() default true; //参数是否必传 /**
* 参数是否必传
*
* @return boolean
*/
boolean required() default true;
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -10,7 +10,9 @@ import java.lang.annotation.*;
/** /**
* 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam * 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@@ -18,9 +20,24 @@ import java.lang.annotation.*;
@Documented @Documented
public @interface WebInitParam { public @interface WebInitParam {
/**
* 参数名
*
* @return String
*/
String name(); String name();
/**
* 参数值
*
* @return String
*/
String value(); String value();
/**
* 参数描述
*
* @return String
*/
String description() default ""; String description() default "";
} }

View File

@@ -21,15 +21,45 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface WebServlet { public @interface WebServlet {
/**
* HttpServlet资源名
*
* @return String
*/
String name() default ""; String name() default "";
/**
* 是否自动添加url前缀, 对应application.xml中servlets节点的path属性
*
* @return boolean
*/
boolean repair() default true; boolean repair() default true;
/**
* url匹配规则
*
* @return String[]
*/
String[] value() default {}; String[] value() default {};
/**
* 模块ID一个HttpServlet尽量只有提供一个模块的服务
*
* @return int
*/
int moduleid() default 0; int moduleid() default 0;
/**
* 参数
*
* @return WebInitParam[]
*/
WebInitParam[] initParams() default {}; WebInitParam[] initParams() default {};
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -11,6 +11,7 @@ import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.util.Comment;
/** /**
* <blockquote><pre> * <blockquote><pre>
@@ -22,15 +23,13 @@ import org.redkale.net.*;
* 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。 * 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。
* 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。 * 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。
* 1.5 onClose WebSocket被关闭后回调此方法。 * 1.5 onClose WebSocket被关闭后回调此方法。
* * 普通模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* *
* 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下: * 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下:
* 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。 * 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。
* 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。 * 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。
* 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 同时业务代码去控制WebSocket的关闭。 * 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 需要业务代码去控制WebSocket的关闭。
* * 二进制模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -39,24 +38,28 @@ import org.redkale.net.*;
*/ */
public abstract class WebSocket { public abstract class WebSocket {
//消息不合法 @Comment("消息不合法")
public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2 public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2
//ws已经关闭 @Comment("WebSocket已经关闭")
public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4 public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4
//socket的buffer不合法 @Comment("Socket的buffer不合法")
public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8 public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8
//ws发送消息异常 @Comment("WebSocket发送消息异常")
public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16 public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16
@Comment("WebSocketEngine实例不存在")
public static final int RETCODE_ENGINE_NULL = 1 << 5; //32 public static final int RETCODE_ENGINE_NULL = 1 << 5; //32
@Comment("WebSocketNode实例不存在")
public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64 public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64
@Comment("WebSocket组为空, 表示无WebSocket连接")
public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128 public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128
@Comment("WebSocket已离线")
public static final int RETCODE_WSOFFLINE = 1 << 8; //256 public static final int RETCODE_WSOFFLINE = 1 << 8; //256
WebSocketRunner _runner; //不可能为空 WebSocketRunner _runner; //不可能为空
@@ -85,6 +88,7 @@ public abstract class WebSocket {
* 发送消息体, 包含二进制/文本 * 发送消息体, 包含二进制/文本
* *
* @param packet WebSocketPacket * @param packet WebSocketPacket
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(WebSocketPacket packet) { public final int send(WebSocketPacket packet) {
@@ -98,6 +102,7 @@ public abstract class WebSocket {
* 发送单一的文本消息 * 发送单一的文本消息
* *
* @param text 不可为空 * @param text 不可为空
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text) { public final int send(String text) {
@@ -109,6 +114,7 @@ public abstract class WebSocket {
* *
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text, boolean last) { public final int send(String text, boolean last) {
@@ -136,6 +142,7 @@ public abstract class WebSocket {
* 发送单一的二进制消息 * 发送单一的二进制消息
* *
* @param data byte[] * @param data byte[]
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data) { public final int send(byte[] data) {
@@ -147,6 +154,7 @@ public abstract class WebSocket {
* *
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data, boolean last) { public final int send(byte[] data, boolean last) {
@@ -158,6 +166,7 @@ public abstract class WebSocket {
* *
* @param message 不可为空, 只能是String或者byte[] * @param message 不可为空, 只能是String或者byte[]
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(Serializable message, boolean last) { public final int send(Serializable message, boolean last) {
@@ -170,6 +179,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text) { public final int sendEachMessage(Serializable groupid, String text) {
@@ -181,6 +191,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data) { public final int sendEachMessage(Serializable groupid, byte[] data) {
@@ -193,6 +204,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text, boolean last) { public final int sendEachMessage(Serializable groupid, String text, boolean last) {
@@ -205,6 +217,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) { public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) {
@@ -216,6 +229,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text) { public final int sendRecentMessage(Serializable groupid, String text) {
@@ -227,6 +241,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data) { public final int sendRecentMessage(Serializable groupid, byte[] data) {
@@ -239,6 +254,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text, boolean last) { public final int sendRecentMessage(Serializable groupid, String text, boolean last) {
@@ -251,6 +267,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) { public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) {
@@ -275,6 +292,7 @@ public abstract class WebSocket {
* 获取在线用户的节点地址列表 * 获取在线用户的节点地址列表
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址列表 * @return 地址列表
*/ */
protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) { protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) {
@@ -285,6 +303,7 @@ public abstract class WebSocket {
* 获取在线用户的详细连接信息 * 获取在线用户的详细连接信息
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址集合 * @return 地址集合
*/ */
protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) { protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) {
@@ -296,6 +315,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -308,6 +328,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
public final <T> T removeAttribute(String name) { public final <T> T removeAttribute(String name) {
@@ -374,6 +395,7 @@ public abstract class WebSocket {
* 获取指定groupid的WebSocketGroup, 没有返回null * 获取指定groupid的WebSocketGroup, 没有返回null
* *
* @param groupid groupid * @param groupid groupid
*
* @return WebSocketGroup * @return WebSocketGroup
*/ */
protected final WebSocketGroup getWebSocketGroup(Serializable groupid) { protected final WebSocketGroup getWebSocketGroup(Serializable groupid) {
@@ -394,6 +416,7 @@ public abstract class WebSocket {
* 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法 * 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法
* *
* @param request HttpRequest * @param request HttpRequest
*
* @return sessionid * @return sessionid
*/ */
public Serializable onOpen(final HttpRequest request) { public Serializable onOpen(final HttpRequest request) {

View File

@@ -23,7 +23,8 @@ import org.redkale.util.*;
* WebSocketServlet * WebSocketServlet
* | * |
* | * |
* WebSocketEngine &#38; WebSocketNode * WebSocketEngine
* WebSocketNode
* / \ * / \
* / \ * / \
* / \ * / \
@@ -41,8 +42,10 @@ import org.redkale.util.*;
*/ */
public abstract class WebSocketServlet extends HttpServlet { public abstract class WebSocketServlet extends HttpServlet {
@Comment("WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒")
public static final String WEBPARAM__LIVEINTERVAL = "liveinterval"; public static final String WEBPARAM__LIVEINTERVAL = "liveinterval";
@Comment("WebScoket服务器给客户端进行ping操作的默认间隔时间, 单位: 秒")
public static final int DEFAILT_LIVEINTERVAL = 60; public static final int DEFAILT_LIVEINTERVAL = 60;
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@@ -57,7 +60,7 @@ public abstract class WebSocketServlet extends HttpServlet {
} }
} }
//是否用于二进制流传输 @Comment("是否用于二进制流传输")
protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null; protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null;
@Resource(name = "$") @Resource(name = "$")

View File

@@ -287,7 +287,7 @@ public final class SncpClient {
} }
private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
if ("rest".equalsIgnoreCase(transport.getKind())) { if ("rest".equalsIgnoreCase(transport.getSubprotocol())) {
return remoteRest0(jsonConvert, transport, addr0, action, params); return remoteRest0(jsonConvert, transport, addr0, action, params);
} }
return remoteSncp0(bsonConvert, transport, addr0, action, params); return remoteSncp0(bsonConvert, transport, addr0, action, params);

View File

@@ -94,13 +94,13 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
} }
@Override @Override
public <T> int updateColumns(T bean, final String... columns) { public <T> int updateColumn(T bean, final SelectColumn selects) {
return source.updateColumn(bean, columns); return source.updateColumn(bean, selects);
} }
@Override @Override
public <T> int updateColumns(T bean, final FilterNode node, final String... columns) { public <T> int updateColumn(T bean, final FilterNode node, final SelectColumn selects) {
return source.updateColumn(bean, node, columns); return source.updateColumn(bean, node, selects);
} }
@Override @Override

View File

@@ -10,12 +10,12 @@ import java.lang.reflect.*;
import java.util.*; import java.util.*;
/** /**
* 用于定义错误码的注解 * 用于定义错误码的注解 <br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx

View File

@@ -8,13 +8,13 @@ package org.redkale.service;
import org.redkale.convert.json.*; import org.redkale.convert.json.*;
/** /**
* 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 * 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 <br>
* 通常前四位为模块,后四位为操作。 * 结果码定义通常前四位为模块,后四位为操作。<br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -112,10 +112,20 @@ public class RetResult<T> {
this.retcode = retcode; this.retcode = retcode;
} }
/**
* 结果信息通常retcode != 0时值为错误信息
*
* @return 结果信息
*/
public String getRetinfo() { public String getRetinfo() {
return retinfo; return retinfo;
} }
/**
* 设置结果信息
*
* @param retinfo 结果信息
*/
public void setRetinfo(String retinfo) { public void setRetinfo(String retinfo) {
this.retinfo = retinfo; this.retinfo = retinfo;
} }
@@ -129,6 +139,11 @@ public class RetResult<T> {
return result; return result;
} }
/**
* 设置结果对象
*
* @param result T
*/
public void setResult(T result) { public void setResult(T result) {
this.result = result; this.result = result;
} }

View File

@@ -14,9 +14,24 @@ package org.redkale.source;
* @author zhangjx * @author zhangjx
*/ */
public enum ColumnExpress { public enum ColumnExpress {
MOV, //直接赋值 col = val /**
INC, //追加值 col = col + val * 直接赋值 col = val
MUL, //乘值 col = col * val */
MOV,
/**
* 追加值 col = col + val
*/
INC,
/**
* 乘值 col = col * val
*/
MUL,
/**
* 与值 col = col &#38; val
*/
AND, //与值 col = col & val AND, //与值 col = col & val
ORR; //或值 col = col | val /**
* 或值 col = col | val
*/
ORR;
} }

View File

@@ -10,6 +10,7 @@ import static org.redkale.source.ColumnExpress.*;
/** /**
* ColumnValue主要用于多个字段更新的表达式。 * ColumnValue主要用于多个字段更新的表达式。
* 用于 DataSource.updateColumn 方法
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -37,26 +38,74 @@ public class ColumnValue {
this.value = value; this.value = value;
} }
/**
* 同 mov 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue create(String column, Serializable value) { public static ColumnValue create(String column, Serializable value) {
return new ColumnValue(column, value); return new ColumnValue(column, value);
} }
/**
* 返回 {column} = {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue mov(String column, Serializable value) { public static ColumnValue mov(String column, Serializable value) {
return new ColumnValue(column, MOV, value); return new ColumnValue(column, MOV, value);
} }
/**
* 返回 {column} = {column} + {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue inc(String column, Serializable value) { public static ColumnValue inc(String column, Serializable value) {
return new ColumnValue(column, INC, value); return new ColumnValue(column, INC, value);
} }
/**
* 返回 {column} = {column} * {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue mul(String column, Serializable value) { public static ColumnValue mul(String column, Serializable value) {
return new ColumnValue(column, MUL, value); return new ColumnValue(column, MUL, value);
} }
/**
* 返回 {column} = {column} &#38; {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue and(String column, Serializable value) { public static ColumnValue and(String column, Serializable value) {
return new ColumnValue(column, AND, value); return new ColumnValue(column, AND, value);
} }
/**
* 返回 {column} = {column} | {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue orr(String column, Serializable value) { public static ColumnValue orr(String column, Serializable value) {
return new ColumnValue(column, ORR, value); return new ColumnValue(column, ORR, value);
} }

View File

@@ -6,7 +6,6 @@
package org.redkale.source; package org.redkale.source;
import java.io.*; import java.io.*;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
@@ -14,11 +13,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.*; import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.sql.ConnectionPoolDataSource;
import javax.xml.stream.*; import javax.xml.stream.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* DataSource的JDBC实现类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -30,26 +29,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH";
static final String JDBC_CONNECTIONSMAX = "javax.persistence.connections.limit";
static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate";
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates";
static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
static final String JDBC_URL = "javax.persistence.jdbc.url";
static final String JDBC_USER = "javax.persistence.jdbc.user";
static final String JDBC_PWD = "javax.persistence.jdbc.password";
static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
static final String JDBC_SOURCE = "javax.persistence.jdbc.source";
private static final Flipper FLIPPER_ONE = new Flipper(1); private static final Flipper FLIPPER_ONE = new Flipper(1);
final Logger logger = Logger.getLogger(DataDefaultSource.class.getSimpleName()); final Logger logger = Logger.getLogger(DataDefaultSource.class.getSimpleName());
@@ -66,9 +45,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
private final JDBCPoolSource writePool; private final JDBCPoolSource writePool;
@Resource(name = "property.datasource.nodeid")
private int nodeid;
@Resource(name = "$") @Resource(name = "$")
private DataCacheListener cacheListener; private DataCacheListener cacheListener;
@@ -182,77 +158,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
return map; return map;
} }
static ConnectionPoolDataSource createDataSource(Properties property) {
try {
return createDataSource(property.getProperty(JDBC_SOURCE, property.getProperty(JDBC_DRIVER)),
property.getProperty(JDBC_URL), property.getProperty(JDBC_USER), property.getProperty(JDBC_PWD));
} catch (Exception ex) {
throw new RuntimeException("(" + property + ") have no jdbc parameters", ex);
}
}
static ConnectionPoolDataSource createDataSource(String source0, String url, String user, String password) throws Exception {
String source = source0;
if (source0 == null || source0.isEmpty()) {
if (url.startsWith("jdbc:mysql:")) {
source0 = "com.mysql.jdbc.Driver";
} else if (url.startsWith("jdbc:mariadb:")) {
source0 = "org.mariadb.jdbc.Driver";
} else if (url.startsWith("jdbc:oracle:")) {
source0 = "oracle.jdbc.driver.OracleDriver";
} else if (url.startsWith("jdbc:postgresql:")) {
source0 = "org.postgresql.Driver";
} else if (url.startsWith("jdbc:microsoft:sqlserver:")) {
source0 = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
}
}
if (source0 != null && source0.contains("Driver")) { //为了兼容JPA的配置文件
switch (source0) {
case "org.mariadb.jdbc.Driver":
source = "org.mariadb.jdbc.MySQLDataSource";
break;
case "com.mysql.cj.jdbc.Driver":
case "com.mysql.jdbc.Driver":
try {
Class.forName("com.mysql.cj.jdbc.MysqlConnectionPoolDataSource");
source = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource";
} catch (Exception e) {
source = "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource";
}
break;
case "oracle.jdbc.driver.OracleDriver":
source = "oracle.jdbc.pool.OracleConnectionPoolDataSource";
break;
case "org.postgresql.Driver":
source = "org.postgresql.ds.PGConnectionPoolDataSource";
break;
case "com.microsoft.sqlserver.jdbc.SQLServerDriver":
source = "com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource";
break;
}
}
final Class clazz = Class.forName(source);
Object pdsource = clazz.newInstance();
if (source.contains(".postgresql.")) {
Class driver = Class.forName("org.postgresql.Driver");
Properties properties = (Properties) driver.getMethod("parseURL", String.class, Properties.class).invoke(null, url, new Properties());
clazz.getMethod("setServerName", String.class).invoke(pdsource, properties.getProperty("PGHOST"));
clazz.getMethod("setDatabaseName", String.class).invoke(pdsource, properties.getProperty("PGDBNAME"));
clazz.getMethod("setPortNumber", int.class).invoke(pdsource, Integer.parseInt(properties.getProperty("PGPORT", "5432")));
} else {
Method seturlm;
try {
seturlm = clazz.getMethod("setUrl", String.class);
} catch (Exception e) {
seturlm = clazz.getMethod("setURL", String.class);
}
seturlm.invoke(pdsource, url);
}
clazz.getMethod("setUser", String.class).invoke(pdsource, user);
clazz.getMethod("setPassword", String.class).invoke(pdsource, password);
return (ConnectionPoolDataSource) pdsource;
}
public final String name() { public final String name() {
return name; return name;
} }
@@ -316,6 +221,18 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
@Override @Override
public <T> void insert(T... values) { public <T> void insert(T... values) {
if (values.length == 0) return; if (values.length == 0) return;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.insert must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass()); final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) { if (info.isVirtualEntity()) {
insert(null, info, values); insert(null, info, values);
@@ -439,7 +356,14 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
int i = 0; int i = 0;
if (info.autouuid) info.createPrimaryValue(value); if (info.autouuid) info.createPrimaryValue(value);
for (Attribute<T, Serializable> attr : attrs) { for (Attribute<T, Serializable> attr : attrs) {
prestmt.setObject(++i, attr.get(value)); Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++i, blob);
} else {
prestmt.setObject(++i, val);
}
} }
prestmt.addBatch(); prestmt.addBatch();
} }
@@ -468,6 +392,18 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
@Override @Override
public <T> int delete(T... values) { public <T> int delete(T... values) {
if (values.length == 0) return -1; if (values.length == 0) return -1;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.delete must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass()); final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) { //虚拟表只更新缓存Cache if (info.isVirtualEntity()) { //虚拟表只更新缓存Cache
return delete(null, info, values); return delete(null, info, values);
@@ -628,6 +564,18 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
@Override @Override
public <T> int update(T... values) { public <T> int update(T... values) {
if (values.length == 0) return 0; if (values.length == 0) return 0;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.update must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass()); final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) { if (info.isVirtualEntity()) {
return update(null, info, values); return update(null, info, values);
@@ -655,7 +603,14 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
for (final T value : values) { for (final T value : values) {
int k = 0; int k = 0;
for (Attribute<T, Serializable> attr : attrs) { for (Attribute<T, Serializable> attr : attrs) {
prestmt.setObject(++k, attr.get(value)); Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++k, blob);
} else {
prestmt.setObject(++k, val);
}
} }
prestmt.setObject(++k, primary.get(value)); prestmt.setObject(++k, primary.get(value));
prestmt.addBatch();//------------------------------------------------------------ prestmt.addBatch();//------------------------------------------------------------
@@ -724,10 +679,21 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} }
} }
private <T> int updateColumn(Connection conn, final EntityInfo<T> info, Serializable id, String column, Serializable value) { private <T> int updateColumn(Connection conn, final EntityInfo<T> info, Serializable id, String column, final Serializable value) {
try { try {
int c = -1; int c = -1;
if (!info.isVirtualEntity()) { if (!info.isVirtualEntity()) {
if (value instanceof byte[]) {
String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = ? WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
final PreparedStatement stmt = conn.prepareStatement(sql);
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) value);
stmt.setBlob(1, blob);
c = stmt.executeUpdate(sql);
stmt.close();
} else {
String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = " String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = "
+ info.formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id); + info.formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
@@ -736,6 +702,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -774,7 +741,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} }
} }
private <T> int updateColumn(Connection conn, final EntityInfo<T> info, String column, Serializable value, FilterNode node) { private <T> int updateColumn(Connection conn, final EntityInfo<T> info, String column, final Serializable value, FilterNode node) {
try { try {
int c = -1; int c = -1;
if (!info.isVirtualEntity()) { if (!info.isVirtualEntity()) {
@@ -789,6 +756,20 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
} }
if (value instanceof byte[]) {
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1))
+ " SET " + info.getSQLColumn("a", column) + " = ?"
+ ((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);
conn.setReadOnly(false);
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) value);
final PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setBlob(1, blob);
c = stmt.executeUpdate(sql);
stmt.close();
} else {
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1))
+ " SET " + info.getSQLColumn("a", column) + " = " + info.formatToString(value) + " SET " + info.getSQLColumn("a", column) + " = " + info.formatToString(value)
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
@@ -799,6 +780,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -843,6 +825,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>(); final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity(); final boolean virtual = info.isVirtualEntity();
List<byte[]> blobs = null;
for (ColumnValue col : values) { for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue; if (attr == null) continue;
@@ -851,18 +834,36 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (!virtual) { if (!virtual) {
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
String c = info.getSQLColumn(null, col.getColumn()); String c = info.getSQLColumn(null, col.getColumn());
if (col.getValue() instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) col.getValue());
setsql.append(c).append(" = ?");
} else {
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col)); setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
} }
} }
}
int c = -1; int c = -1;
if (!virtual) { if (!virtual) {
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id); String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + ": " + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + ": " + sql);
conn.setReadOnly(false); conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement(); final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -930,6 +931,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>(); final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity(); final boolean virtual = info.isVirtualEntity();
List<byte[]> blobs = null;
for (ColumnValue col : values) { for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue; if (attr == null) continue;
@@ -938,9 +940,15 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (!virtual) { if (!virtual) {
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
String c = info.getSQLColumn("a", col.getColumn()); String c = info.getSQLColumn("a", col.getColumn());
if (col.getValue() instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) col.getValue());
setsql.append(c).append(" = ?");
} else {
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col)); setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
} }
} }
}
int c = -1; int c = -1;
if (!virtual) { if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis(); Map<Class, String> joinTabalis = node.getJoinTabalis();
@@ -960,10 +968,22 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
sql += info.createSQLOrderby(flipper) + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())); 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); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false); conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement(); final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -976,48 +996,47 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} }
@Override @Override
public <T> int updateColumns(final T bean, final String... columns) { public <T> int updateColumn(final T bean, final String... columns) {
return updateColumn(bean, columns); return updateColumn(bean, SelectColumn.createIncludes(columns));
} }
/**
* 更新对象指定的一些字段, 必须是Entity对象
*
* @param <T> Entity类的泛型
* @param bean Entity对象
* @param columns 需要更新的字段
*
* @return 更新的数据条数
*/
@Override @Override
public <T> int updateColumn(final T bean, final String... columns) { public <T> int updateColumn(final T bean, final SelectColumn selects) {
final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass()); final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass());
if (info.isVirtualEntity()) { if (info.isVirtualEntity()) {
return updateColumns(null, info, bean, columns); return updateColumns(null, info, bean, selects);
} }
Connection conn = createWriteSQLConnection(); Connection conn = createWriteSQLConnection();
try { try {
return updateColumns(conn, info, bean, columns); return updateColumns(conn, info, bean, selects);
} finally { } finally {
closeSQLConnection(conn); closeSQLConnection(conn);
} }
} }
private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final String... columns) { private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final SelectColumn selects) {
if (bean == null || columns.length < 1) return -1; if (bean == null || selects == null) return -1;
try { try {
final Class<T> clazz = (Class<T>) bean.getClass(); final Class<T> clazz = (Class<T>) bean.getClass();
StringBuilder setsql = new StringBuilder(); StringBuilder setsql = new StringBuilder();
final Serializable id = info.getPrimary().get(bean); final Serializable id = info.getPrimary().get(bean);
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
List<byte[]> blobs = null;
final boolean virtual = info.isVirtualEntity(); final boolean virtual = info.isVirtualEntity();
for (String col : columns) { for (Attribute<T, Serializable> attr : info.updateAttributes) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col); if (!selects.test(attr.field())) continue;
if (attr == null) continue;
attrs.add(attr); attrs.add(attr);
if (!virtual) { if (!virtual) {
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn(null, col)).append(" = ").append(info.formatToString(attr.get(bean))); setsql.append(info.getSQLColumn(null, attr.field()));
Serializable val = attr.get(bean);
if (val instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) val);
setsql.append(" = ?");
} else {
setsql.append(" = ").append(info.formatToString(val));
}
} }
} }
int c = -1; int c = -1;
@@ -1025,10 +1044,22 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id); String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(bean.getClass().getSimpleName() + ": " + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(bean.getClass().getSimpleName() + ": " + sql);
conn.setReadOnly(false); conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement(); final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -1041,49 +1072,47 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} }
@Override @Override
public <T> int updateColumns(final T bean, final FilterNode node, final String... columns) { public <T> int updateColumn(final T bean, final FilterNode node, final String... columns) {
return updateColumn(bean, node, columns); return updateColumn(bean, node, SelectColumn.createIncludes(columns));
} }
/**
* 更新对象指定的一些字段, 必须是Entity对象
*
* @param <T> Entity类的泛型
* @param bean Entity对象
* @param node 过滤node 不能为null
* @param columns 需要更新的字段
*
* @return 更新的数据条数
*/
@Override @Override
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns) { public <T> int updateColumn(final T bean, final FilterNode node, final SelectColumn selects) {
final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass()); final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass());
if (info.isVirtualEntity()) { if (info.isVirtualEntity()) {
return updateColumns(null, info, bean, node, columns); return updateColumns(null, info, bean, node, selects);
} }
Connection conn = createWriteSQLConnection(); Connection conn = createWriteSQLConnection();
try { try {
return updateColumns(conn, info, bean, node, columns); return updateColumns(conn, info, bean, node, selects);
} finally { } finally {
closeSQLConnection(conn); closeSQLConnection(conn);
} }
} }
private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final FilterNode node, final String... columns) { private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final FilterNode node, final SelectColumn selects) {
if (bean == null || node == null || columns.length < 1) return -1; if (bean == null || node == null || selects == null) return -1;
try { try {
final Class<T> clazz = (Class<T>) bean.getClass(); final Class<T> clazz = (Class<T>) bean.getClass();
StringBuilder setsql = new StringBuilder(); StringBuilder setsql = new StringBuilder();
final Serializable id = info.getPrimary().get(bean); final Serializable id = info.getPrimary().get(bean);
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
List<byte[]> blobs = null;
final boolean virtual = info.isVirtualEntity(); final boolean virtual = info.isVirtualEntity();
for (String col : columns) { for (Attribute<T, Serializable> attr : info.updateAttributes) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col); if (!selects.test(attr.field())) continue;
if (attr == null) continue;
attrs.add(attr); attrs.add(attr);
if (!virtual) { if (!virtual) {
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn("a", col)).append(" = ").append(info.formatToString(attr.get(bean))); setsql.append(info.getSQLColumn("a", attr.field()));
Serializable val = attr.get(bean);
if (val instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) val);
setsql.append(" = ?");
} else {
setsql.append(" = ").append(info.formatToString(val));
}
} }
} }
int c = -1; int c = -1;
@@ -1103,10 +1132,22 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false); conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement(); final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql); c = stmt.executeUpdate(sql);
stmt.close(); stmt.close();
} }
}
//--------------------------------------------------- //---------------------------------------------------
final EntityCache<T> cache = info.getCache(); final EntityCache<T> cache = info.getCache();
if (cache == null) return c; if (cache == null) return c;
@@ -1360,6 +1401,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true); conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery(); final ResultSet set = ps.executeQuery();
T rs = set.next() ? info.getValue(sels, set) : null; T rs = set.next() ? info.getValue(sels, set) : null;
set.close(); set.close();
@@ -1411,6 +1453,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true); conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery(); final ResultSet set = ps.executeQuery();
T rs = set.next() ? info.getValue(sels, set) : null; T rs = set.next() ? info.getValue(sels, set) : null;
set.close(); set.close();
@@ -1452,13 +1495,22 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
final Connection conn = createReadSQLConnection(); final Connection conn = createReadSQLConnection();
try { try {
final Attribute<T, Serializable> attr = info.getAttribute(column);
final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk); 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); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true); conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery(); final ResultSet set = ps.executeQuery();
Serializable val = defValue; Serializable val = defValue;
if (set.next()) val = (Serializable) set.getObject(1); if (set.next()) {
if (attr.type() == byte[].class) {
Blob blob = set.getBlob(1);
if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else {
val = (Serializable) set.getObject(1);
}
}
set.close(); set.close();
ps.close(); ps.close();
return val == null ? defValue : val; return val == null ? defValue : val;
@@ -1485,6 +1537,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
final Connection conn = createReadSQLConnection(); final Connection conn = createReadSQLConnection();
try { try {
final Attribute<T, Serializable> attr = info.getAttribute(column);
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis(); 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 join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis); final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
@@ -1492,9 +1545,17 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true); conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery(); final ResultSet set = ps.executeQuery();
Serializable val = defValue; Serializable val = defValue;
if (set.next()) val = (Serializable) set.getObject(1); if (set.next()) {
if (attr.type() == byte[].class) {
Blob blob = set.getBlob(1);
if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else {
val = (Serializable) set.getObject(1);
}
}
set.close(); set.close();
ps.close(); ps.close();
return val == null ? defValue : val; return val == null ? defValue : val;
@@ -1659,16 +1720,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
return rs; return rs;
} }
private <K extends Serializable, T> Map<K, T> formatMap(final Class<T> clazz, final Collection<T> list) {
Map<K, T> map = new LinkedHashMap<>();
if (list == null || list.isEmpty()) return map;
final Attribute<T, K> attr = (Attribute<T, K>) loadEntityInfo(clazz).getPrimary();
for (T t : list) {
map.put(attr.get(t), t);
}
return map;
}
/** /**
* 根据指定字段值查询对象集合 * 根据指定字段值查询对象集合
* *
@@ -1813,6 +1864,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
} }
conn.setReadOnly(true); conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit());
final ResultSet set = ps.executeQuery(); final ResultSet set = ps.executeQuery();
if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset()); if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset());
final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit(); final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit();

View File

@@ -25,7 +25,7 @@ public interface DataSource {
//----------------------insert----------------------------- //----------------------insert-----------------------------
/** /**
* 新增对象, 必须是Entity对象 * 新增记录, 多对象必须是同一个Entity类 <br>
* *
* @param <T> 泛型 * @param <T> 泛型
* @param values Entity对象 * @param values Entity对象
@@ -34,114 +34,385 @@ public interface DataSource {
//-------------------------delete-------------------------- //-------------------------delete--------------------------
/** /**
* 删除对象, 必须是Entity对象 * 删除指定主键值的记录, 多对象必须是同一个Entity类 <br>
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
* *
* @param <T> 泛型 * @param <T> 泛型
* @param values Entity对象 * @param values Entity对象
* *
* @return 删除的数据条数 * @return 影响的记录条数
*/ */
public <T> int delete(final T... values); public <T> int delete(final T... values);
/** /**
* 根据主键值删除数据 * 删除指定主键值的记录 <br>
* 等价SQL: DELETE FROM WHERE {primary} IN {ids} * 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids} <br>
* *
* @param <T> Entity类的泛型 * @param <T> Entity泛型
* @param clazz Entity类 * @param clazz Entity类
* @param ids 主键值 * @param ids 主键值
* *
* @return 删除的数据条数 * @return 影响的记录条数
*/ */
public <T> int delete(final Class<T> clazz, final Serializable... ids); public <T> int delete(final Class<T> clazz, final Serializable... ids);
/**
* 删除符合过滤条件的记录 <br>
* 等价SQL: DELETE FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 影响的记录条数
*/
public <T> int delete(final Class<T> clazz, final FilterNode node); public <T> int delete(final Class<T> clazz, final FilterNode node);
/**
* 删除符合过滤条件且指定最大影响条数的记录 <br>
* Flipper中offset字段将被忽略 <br>
* 等价SQL: DELETE FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return 影响的记录条数
*/
public <T> int delete(final Class<T> clazz, final Flipper flipper, final FilterNode node); public <T> int delete(final Class<T> clazz, final Flipper flipper, final FilterNode node);
//------------------------update--------------------------- //------------------------update---------------------------
/** /**
* 更新对象, 必须是Entity对象 * 更新记录, 多对象必须是同一个Entity类 <br>
* 等价SQL: <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id1} <br>
* UPDATE {table} SET column1 = value1, column2 = value2, &#183;&#183;&#183; WHERE {primary} = {id2} <br>
* &#183;&#183;&#183; <br>
* *
* @param <T> 泛型 * @param <T> 泛型
* @param values Entity对象 * @param values Entity对象
* *
* @return 更新的数据条数 * @return 影响的记录条数
*/ */
public <T> int update(final T... values); public <T> int update(final T... values);
/**
* 更新单个记录的单个字段 <br>
* <b>注意</b>:即使字段标记为&#064;Column(updatable=false)也会被更新 <br>
* 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param column 待更新的字段名
* @param value 更新值
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value); public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value);
/**
* 更新符合过滤条件记录的单个字段 <br>
* <b>注意</b>:即使字段标记为&#064;Column(updatable=false)也会被更新 <br>
* 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 待更新的字段名
* @param value 更新值
* @param node 过滤条件
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node); public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node);
/**
* 更新指定主键值记录的部分字段 <br>
* 字段赋值操作选项见 ColumnExpress <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param id 主键
* @param values 更新字段
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values); public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values);
/**
* 更新符合过滤条件记录的部分字段 <br>
* 字段赋值操作选项见 ColumnExpress <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
* @param values 更新字段
*
* @return 影响的记录条数
*/
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 ColumnValue... values);
/**
* 更新符合过滤条件的记录的指定字段 <br>
* Flipper中offset字段将被忽略 <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, &#183;&#183;&#183; WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
* @param flipper 翻页对象
* @param values 更新字段
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values); public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values);
/**
* 更新单个记录的指定字段 <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param columns 需更新的字段名
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final String... columns); public <T> int updateColumn(final T bean, final String... columns);
/**
* 更新符合过滤条件记录的指定字段 <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param bean 待更新的Entity对象
* @param node 过滤条件
* @param columns 需更新的字段名
*
* @return 影响的记录条数
*/
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns); public <T> int updateColumn(final T bean, final FilterNode node, final String... columns);
/** /**
* 由 public int updateColumn(final T bean, final String... columns); 代替 * 更新单个记录的指定字段 <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {primary} = {bean.id} <br>
* *
* @param <T> T * @param <T> Entity泛型
* @param bean bean * @param bean 待更新的Entity对象
* @param columns columns * @param selects 指定字段
* *
* @return int * @return 影响的记录条数
* @deprecated
*/ */
@Deprecated public <T> int updateColumn(final T bean, final SelectColumn selects);
public <T> int updateColumns(final T bean, final String... columns);
/** /**
* 由 public int updateColumn(final T bean, final FilterNode node, final String... columns); 代替 * 更新符合过滤条件记录的指定字段 <br>
* <b>注意</b>Entity类中标记为&#064;Column(updatable=false)不会被更新 <br>
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, &#183;&#183;&#183; WHERE {filter node} <br>
* *
* @param <T> T * @param <T> Entity泛型
* @param bean bean * @param bean 待更新的Entity对象
* @param node node * @param node 过滤条件
* @param columns columns * @param selects 指定字段
* *
* @return int * @return 影响的记录条数
* @deprecated
*/ */
@Deprecated public <T> int updateColumn(final T bean, final FilterNode node, final SelectColumn selects);
public <T> int updateColumns(final T bean, final FilterNode node, final String... columns);
//############################################# 查询接口 ############################################# //############################################# 查询接口 #############################################
//-----------------------getXXXXResult----------------------------- //-----------------------getXXXXResult-----------------------------
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回null <br>
* 等价SQL: SELECT FUNC{column} FROM {table} <br>
* 如 getNumberResult(Record.class, FilterFunc.COUNT, null) 等价于: SELECT COUNT(*) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param column 指定字段
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column); public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column);
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回null <br>
* 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean} <br>
* 如 getNumberResult(Record.class, FilterFunc.COUNT, null, (FilterBean)null) 等价于: SELECT COUNT(*) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param column 指定字段
* @param bean 过滤条件
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean); public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean);
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回null <br>
* 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node} <br>
* 如 getNumberResult(Record.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param column 指定字段
* @param node 过滤条件
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node); public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node);
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回默认值 <br>
* 等价SQL: SELECT FUNC{column} FROM {table} <br>
* 如 getNumberResult(Record.class, FilterFunc.MAX, "createtime") 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param defVal 默认值
* @param column 指定字段
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column); public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column);
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回默认值 <br>
* 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean} <br>
* 如 getNumberResult(Record.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param defVal 默认值
* @param column 指定字段
* @param bean 过滤条件
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean); public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean);
/**
* 获取符合过滤条件记录的聚合结果, 无结果返回默认值 <br>
* 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node} <br>
* 如 getNumberResult(Record.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param entityClass Entity类
* @param func 聚合函数
* @param defVal 默认值
* @param column 指定字段
* @param node 过滤条件
*
* @return 聚合结果
*/
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node); public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node);
/**
* 获取符合过滤条件记录的聚合结果Map <br>
* 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, &#183;&#183;&#183; FROM {table} <br>
* 如 getNumberMap(Record.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param <N> Number
* @param entityClass Entity类
* @param columns 聚合字段
*
* @return 聚合结果Map
*/
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterFuncColumn... columns); public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterFuncColumn... columns);
/**
* 获取符合过滤条件记录的聚合结果Map <br>
* 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter bean} <br>
* 如 getNumberMap(Record.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param <N> Number
* @param entityClass Entity类
* @param bean 过滤条件
* @param columns 聚合字段
*
* @return 聚合结果Map
*/
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns); public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns);
/**
* 获取符合过滤条件记录的聚合结果Map <br>
* 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter node} <br>
* 如 getNumberMap(Record.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) FROM {table} <br>
*
* @param <N> Number
* @param entityClass Entity类
* @param node 过滤条件
* @param columns 聚合字段
*
* @return 聚合结果Map
*/
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns); public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns);
/**
* 查询符合过滤条件记录的GROUP BY聚合结果Map <br>
* 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn} <br>
* 如 queryColumnMap(Record.class, "name", FilterFunc.MAX, "createtime") 等价于: SELECT name, MAX(createtime) FROM record GROUP BY name<br>
*
* @param <T> Entity泛型
* @param <K> Key字段的数据类型
* @param <N> Number
* @param entityClass Entity类
* @param keyColumn Key字段
* @param func 聚合函数
* @param funcColumn 聚合字段
*
* @return 聚合结果Map
*/
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn); public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn);
/**
* 查询符合过滤条件记录的GROUP BY聚合结果Map <br>
* 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn} <br>
* 如 queryColumnMap(Record.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 等价于: SELECT name, MAX(createtime) FROM record GROUP BY name<br>
*
* @param <T> Entity泛型
* @param <K> Key字段的数据类型
* @param <N> Number
* @param entityClass Entity类
* @param keyColumn Key字段
* @param func 聚合函数
* @param funcColumn 聚合字段
* @param bean 过滤条件
*
* @return 聚合结果Map
*/
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean); public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean);
/**
* 查询符合过滤条件记录的GROUP BY聚合结果Map <br>
* 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn} <br>
* 如 queryColumnMap(Record.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT name, MAX(createtime) FROM record GROUP BY name<br>
*
* @param <T> Entity泛型
* @param <K> Key字段的数据类型
* @param <N> Number
* @param entityClass Entity类
* @param keyColumn Key字段
* @param func 聚合函数
* @param funcColumn 聚合字段
* @param node 过滤条件
*
* @return 聚合结果Map
*/
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node); public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node);
//-----------------------find---------------------------- //-----------------------find----------------------------
/** /**
* 根据主键获取对象 * 获取指定主键值的单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT * FROM {table} WHERE {primary} = {id} <br>
* *
* @param <T> 泛型 * @param <T> Entity泛型
* @param clazz Entity类 * @param clazz Entity类
* @param pk 主键值 * @param pk 主键值
* *
@@ -149,43 +420,207 @@ public interface DataSource {
*/ */
public <T> T find(final Class<T> clazz, final Serializable pk); public <T> T find(final Class<T> clazz, final Serializable pk);
/**
* 获取指定主键值的单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {primary} = {id} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param pk 主键值
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final SelectColumn selects, final Serializable pk); public <T> T find(final Class<T> clazz, final SelectColumn selects, final Serializable pk);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT * FROM {table} WHERE {column} = {key} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final String column, final Serializable key); public <T> T find(final Class<T> clazz, final String column, final Serializable key);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param bean 过滤条件
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final FilterBean bean); public <T> T find(final Class<T> clazz, final FilterBean bean);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final FilterNode node); public <T> T find(final Class<T> clazz, final FilterNode node);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param bean 过滤条件
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterBean bean); public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterBean bean);
/**
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param node 过滤条件
*
* @return Entity对象
*/
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node); public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node);
/**
* 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param pk 主键值
*
* @return Entity对象
*/
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 Serializable pk);
/**
* 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param bean 过滤条件
*
* @return 字段值
*/
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 FilterBean bean);
/**
* 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param node 过滤条件
*
* @return 字段值
*/
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 FilterNode node);
/**
* 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param defValue 默认值
* @param pk 主键值
*
* @return 字段值
*/
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 Serializable pk);
/**
* 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param defValue 默认值
* @param bean 过滤条件
*
* @return 字段值
*/
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 FilterBean bean);
/**
* 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值 <br>
* 等价SQL: SELECT {column} FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param column 字段名
* @param defValue 默认值
* @param node 过滤条件
*
* @return 字段值
*/
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node); public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node);
/**
* 判断是否存在主键值的记录 <br>
* 等价SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param pk 主键值
*
* @return 是否存在
*/
public <T> boolean exists(final Class<T> clazz, final Serializable pk); public <T> boolean exists(final Class<T> clazz, final Serializable pk);
/**
* 判断是否存在符合过滤条件的记录 <br>
* 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param bean 过滤条件
*
* @return 是否存在
*/
public <T> boolean exists(final Class<T> clazz, final FilterBean bean); public <T> boolean exists(final Class<T> clazz, final FilterBean bean);
/**
* 判断是否存在符合过滤条件的记录 <br>
* 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return 是否存在
*/
public <T> boolean exists(final Class<T> clazz, final FilterNode node); public <T> boolean exists(final Class<T> clazz, final FilterNode node);
//-----------------------list set---------------------------- //-----------------------list set----------------------------
/** /**
* 根据指定字段值查询对象某个字段的集合 * 查询符合过滤条件记录的某个字段Set集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key} <br>
* *
* @param <T> Entity泛型 * @param <T> Entity泛型
* @param <V> 字段类型 * @param <V> 字段类型
* @param selectedColumn 字段 * @param selectedColumn 指定字段
* @param clazz Entity类 * @param clazz Entity类
* @param column 过滤字段名 * @param column 过滤字段名
* @param key 过滤字段值 * @param key 过滤字段值
@@ -194,89 +629,327 @@ public interface DataSource {
*/ */
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key); public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final FilterBean bean);
public <T, V extends Serializable> HashSet<V> queryColumnSet(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 String column, final Serializable key);
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterBean bean);
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);
/** /**
* 根据指定参数查询对象某个字段的集合 * 查询符合过滤条件记录的某个字段Set集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} <br>
* *
* @param <T> Entity泛型 * @param <T> Entity泛型
* @param <V> 字段类型 * @param <V> 字段类型
* @param selectedColumn 字段 * @param selectedColumn 指定字段
* @param clazz Entity类
* @param bean 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final FilterBean bean);
/**
* 查询符合过滤条件记录的某个字段Set集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param node 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final FilterNode node);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
*
* @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param bean 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterBean bean);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param node 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterNode node);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类 * @param clazz Entity类
* @param flipper 翻页对象 * @param flipper 翻页对象
* @param bean 过滤Bean * @param bean 过滤条件
* *
* @return 结果集合 * @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的某个字段List集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node);
/**
* 查询符合过滤条件记录的某个字段Sheet集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param flipper 翻页对象
* @param bean 过滤条件
*
* @return 字段值的集合
*/ */
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean); public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的某个字段Sheet集合 <br>
* 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param <V> 字段类型
* @param selectedColumn 指定字段
* @param clazz Entity类
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return 字段值的集合
*/
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node); public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node);
/** /**
* 根据指定字段值查询对象集合 * 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
* *
* @param <T> Entity泛型 * @param <T> Entity泛型
* @param clazz Entity类 * @param clazz Entity类
* @param column 过滤字段名 * @param column 过滤字段名
* @param key 过滤字段值 * @param key 过滤字段值
* *
* @return Entity的List * @return Entity的集合
*/ */
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key); public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param bean 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final FilterBean bean); public <T> List<T> queryList(final Class<T> clazz, final FilterBean bean);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node); public <T> List<T> queryList(final Class<T> clazz, final FilterNode node);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter bean} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param bean 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean); public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter node} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node); public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param column 过滤字段名
* @param key 过滤字段值
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key); public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param bean 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean); public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node); public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param flipper 翻页对象
* @param bean 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean); public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的List集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
//-----------------------sheet---------------------------- //-----------------------sheet----------------------------
/** /**
* 根据指定参数查询对象某个对象的集合页 * 查询符合过滤条件记录的Sheet集合 <br>
* <p> * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型 * @param <T> Entity泛型
* @param clazz Entity类 * @param clazz Entity类
* @param flipper 翻页对象 * @param flipper 翻页对象
* @param bean 过滤Bean * @param bean 过滤条件
* *
* @return Entity的Sheet * @return Entity的集合
*/ */
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean); public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的Sheet集合 <br>
* 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node); public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node);
/**
* 查询符合过滤条件记录的Sheet集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param flipper 翻页对象
* @param bean 过滤条件
*
* @return Entity的集合
*/
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean); public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean);
/**
* 查询符合过滤条件记录的Sheet集合 <br>
* 等价SQL: SELECT {column1},{column2}, &#183;&#183;&#183; FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} <br>
*
* @param <T> Entity泛型
* @param clazz Entity类
* @param selects 指定字段
* @param flipper 翻页对象
* @param node 过滤条件
*
* @return Entity的集合
*/
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
//-----------------------direct---------------------------- //-----------------------direct----------------------------
/** /**
* 直接本地执行SQL语句进行查询远程模式不可用 * 直接本地执行SQL语句进行查询远程模式不可用 <br>
* 通常用于复杂的关联查询 * 通常用于复杂的关联查询 <br>
* *
* @param sql SQL语句 * @param sql SQL语句
* @param consumer 回调函数 * @param consumer 回调函数
@@ -284,8 +957,8 @@ public interface DataSource {
public void directQuery(String sql, final Consumer<ResultSet> consumer); public void directQuery(String sql, final Consumer<ResultSet> consumer);
/** /**
* 直接本地执行SQL语句进行增删改操作远程模式不可用 * 直接本地执行SQL语句进行增删改操作远程模式不可用 <br>
* 通常用于复杂的更新操作 * 通常用于复杂的更新操作 <br>
* *
* @param sqls SQL语句 * @param sqls SQL语句
* *

View File

@@ -10,6 +10,8 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* Entity分库分表的注解需要结合DistributeTableStrategy使用 <br>
* 标记为 &#64;DistributeTable的Entity类视为需要进行分库分表操作 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,9 +8,9 @@ package org.redkale.source;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 分表分库策略,结合&#64;DistributeTable使用 * 分表分库策略,结合&#64;DistributeTable使用 <br>
* 不能与&#64;Cacheable同时使用 * 不能与&#64;Cacheable同时使用 <br>
* 使用分表分库功能重点是主键的生成策略,不同场景生成策略不一样 * 使用分表分库功能重点是主键的生成策略,不同场景生成策略不一样 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -21,35 +21,19 @@ import java.io.Serializable;
public interface DistributeTableStrategy<T> { public interface DistributeTableStrategy<T> {
/** /**
* 获取对象的表名 * 获取对象的表名 <br>
* 查询单个对象DataSource.find时调用本方法获取表名 * 查询单个对象DataSource.find时调用本方法获取表名 <br>
* *
* @param table 模板表的表名 * @param table 模板表的表名
* @param primary 记录主键 * @param primary 记录主键
* *
* @return 带库名的全表名 * @return 带库名的全表名
*/ */
default String getTable(String table, Serializable primary) { public String getTable(String table, Serializable primary);
return null;
}
/** /**
* 获取对象的表名 * 获取对象的表名 <br>
* 查询、修改、删除对象DataSource.find、DataSource.query、DataSource.delete、DataSource.update时调用本方法获取表名 * 新增对象或更新单个对象DataSource.insert、DataSource.update时调用本方法获取表名 <br>
* 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中
*
* @param table 模板表的表名
* @param node 过滤条件
*
* @return 带库名的全表名
*/
default String getTable(String table, FilterNode node) {
return null;
}
/**
* 获取对象的表名
* 新增对象或更新单个对象DataSource.insert、DataSource.update时调用本方法获取表名
* *
* @param table 模板表的表名 * @param table 模板表的表名
* @param bean 实体对象 * @param bean 实体对象
@@ -57,4 +41,17 @@ public interface DistributeTableStrategy<T> {
* @return 带库名的全表名 * @return 带库名的全表名
*/ */
public String getTable(String table, T bean); public String getTable(String table, T bean);
/**
* 获取对象的表名 <br>
* 查询、修改、删除对象DataSource.find、DataSource.query、DataSource.delete、DataSource.update时调用本方法获取表名 <br>
* 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中 <br>
*
* @param table 模板表的表名
* @param node 过滤条件
*
* @return 带库名的全表名
*/
public String getTable(String table, FilterNode node);
} }

View File

@@ -17,6 +17,7 @@ import static org.redkale.source.FilterFunc.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Entity数据的缓存类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,33 +28,46 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class EntityCache<T> { public final class EntityCache<T> {
//日志
private static final Logger logger = Logger.getLogger(EntityCache.class.getName()); private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
//主键与对象的键值对
private ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap(); private ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
// CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%; // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%;
private Collection<T> list = new ConcurrentLinkedQueue(); private Collection<T> list = new ConcurrentLinkedQueue();
//Flipper.sort转换成Comparator的缓存
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>(); private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
//Entity类
private final Class<T> type; private final Class<T> type;
//接口返回的对象是否需要复制一份
private final boolean needcopy; private final boolean needcopy;
//Entity构建器
private final Creator<T> creator; private final Creator<T> creator;
//主键字段
private final Attribute<T, Serializable> primary; private final Attribute<T, Serializable> primary;
//新增时的复制器, 排除了标记为&#064;Transient的字段
private final Reproduce<T, T> newReproduce; private final Reproduce<T, T> newReproduce;
//修改时的复制器, 排除了标记为&#064;Transient或&#064;Column(updatable=false)的字段
private final Reproduce<T, T> chgReproduce; private final Reproduce<T, T> chgReproduce;
//是否已经全量加载过
private volatile boolean fullloaded; private volatile boolean fullloaded;
//Entity信息
final EntityInfo<T> info; final EntityInfo<T> info;
//&#064;Cacheable的定时更新秒数为0表示不定时更新
final int interval; final int interval;
//&#064;Cacheable的定时器
private ScheduledThreadPoolExecutor scheduler; private ScheduledThreadPoolExecutor scheduler;
public EntityCache(final EntityInfo<T> info, final Cacheable c) { public EntityCache(final EntityInfo<T> info, final Cacheable c) {

View File

@@ -14,10 +14,10 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.*; import java.util.function.*;
import java.util.logging.Level; import java.util.logging.Level;
import javax.persistence.*; import javax.persistence.*;
import static org.redkale.source.DataDefaultSource.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Entity操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -28,75 +28,108 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class EntityInfo<T> { public final class EntityInfo<T> {
//全局静态资源
private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>();
//日志
private static final Logger logger = Logger.getLogger(EntityInfo.class); private static final Logger logger = Logger.getLogger(EntityInfo.class);
//Entity类的类 //Entity类名
private final Class<T> type; private final Class<T> type;
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null //类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
final String table; final String table;
//Entity构建器
private final Creator<T> creator; private final Creator<T> creator;
//主键 //主键
final Attribute<T, Serializable> primary; final Attribute<T, Serializable> primary;
//Entity缓存对象
private final EntityCache<T> cache; private final EntityCache<T> cache;
//key是field的name 不是sql字段。 //key是field的name 不是sql字段。
//存放所有与数据库对应的字段, 包括主键 //存放所有与数据库对应的字段, 包括主键
private final HashMap<String, Attribute<T, Serializable>> attributeMap = new HashMap<>(); private final HashMap<String, Attribute<T, Serializable>> attributeMap = new HashMap<>();
//存放所有与数据库对应的字段, 包括主键
final Attribute<T, Serializable>[] attributes; final Attribute<T, Serializable>[] attributes;
//key是field的name value是Column的别名即数据库表的字段名 //key是field的name value是Column的别名即数据库表的字段名
//只有field.name 与 Column.name不同才存放在aliasmap里. //只有field.name 与 Column.name不同才存放在aliasmap里.
private final Map<String, String> aliasmap; private final Map<String, String> aliasmap;
//所有可更新字段,即排除了主键字段和标记为&#064;Column(updatable=false)的字段
private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>(); private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>();
final String containSQL; //用于反向LIKE使用 //用于反向LIKE使用
final String containSQL;
final String notcontainSQL; //用于反向LIKE使用 //用于反向LIKE使用
final String notcontainSQL;
final String tablenotexistSqlstates; //用于判断表不存在的使用, 多个SQLState用;隔开 //用于判断表不存在的使用, 多个SQLState用;隔开
final String tablenotexistSqlstates;
final String tablecopySQL; //用于复制表结构使用 //用于复制表结构使用
final String tablecopySQL;
final Set<String> tables = new HashSet<>(); //用于存在table_20160202类似这种分布式表 //用于存在table_20160202类似这种分布式表
final Set<String> tables = new HashSet<>();
//分表 策略
final DistributeTableStrategy<T> tableStrategy; final DistributeTableStrategy<T> tableStrategy;
//根据主键查找单个对象的SQL
final String querySQL; final String querySQL;
private final Attribute<T, Serializable>[] queryAttributes; //数据库中所有字段 //数据库中所有字段
private final Attribute<T, Serializable>[] queryAttributes;
//新增SQL 含 ?,即排除了自增长主键和标记为&#064;Column(insertable=false)的字段
private final String insertSQL; private final String insertSQL;
final Attribute<T, Serializable>[] insertAttributes; //数据库中所有可新增字段 //数据库中所有可新增字段
final Attribute<T, Serializable>[] insertAttributes;
//根据主键更新所有可更新字段的SQL
private final String updateSQL; private final String updateSQL;
final Attribute<T, Serializable>[] updateAttributes; //数据库中所有可更新字段 //数据库中所有可更新字段
final Attribute<T, Serializable>[] updateAttributes;
//根据主键删除记录的SQL
private final String deleteSQL; private final String deleteSQL;
//日志级别从LogLevel获取
private final int logLevel; private final int logLevel;
//Flipper.sort转换成以ORDER BY开头SQL的缓存
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>(); private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
//---------------------计算主键值---------------------------- //是否由数据库生成主键值
final boolean autoGenerated; final boolean autoGenerated;
//是否UUID主键
final boolean autouuid; final boolean autouuid;
//所属的DataSource
final DataSource source; final DataSource source;
//全量数据的加载器
final BiFunction<DataSource, Class, List> fullloader; final BiFunction<DataSource, Class, List> fullloader;
//------------------------------------------------------------ //------------------------------------------------------------
/**
* 加载EntityInfo
*
* @param type Entity类
* @param cacheForbidden 是否禁用EntityCache
* @param conf 配置信息, persistence.xml中的property节点值
* @param source DataSource,可为null
* @param fullloader 全量加载器,可为null
*/
static <T> EntityInfo<T> load(Class<T> clazz, final boolean cacheForbidden, final Properties conf, static <T> EntityInfo<T> load(Class<T> clazz, final boolean cacheForbidden, final Properties conf,
DataSource source, BiFunction<DataSource, Class, List> fullloader) { DataSource source, BiFunction<DataSource, Class, List> fullloader) {
EntityInfo rs = entityInfos.get(clazz); EntityInfo rs = entityInfos.get(clazz);
@@ -115,10 +148,27 @@ public final class EntityInfo<T> {
} }
} }
/**
* 获取Entity类对应的EntityInfo对象
*
* @param <T> 泛型
* @param clazz Entity类
*
* @return EntityInfo
*/
static <T> EntityInfo<T> get(Class<T> clazz) { static <T> EntityInfo<T> get(Class<T> clazz) {
return entityInfos.get(clazz); return entityInfos.get(clazz);
} }
/**
* 构造函数
*
* @param type Entity类
* @param cacheForbidden 是否禁用EntityCache
* @param conf 配置信息, persistence.xml中的property节点值
* @param source DataSource,可为null
* @param fullloader 全量加载器,可为null
*/
private EntityInfo(Class<T> type, final boolean cacheForbidden, private EntityInfo(Class<T> type, final boolean cacheForbidden,
Properties conf, DataSource source, BiFunction<DataSource, Class, List> fullloader) { Properties conf, DataSource source, BiFunction<DataSource, Class, List> fullloader) {
this.type = type; this.type = type;
@@ -254,99 +304,203 @@ public final class EntityInfo<T> {
this.cache = null; this.cache = null;
} }
if (conf == null) conf = new Properties(); if (conf == null) conf = new Properties();
this.containSQL = conf.getProperty(JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0"); this.containSQL = conf.getProperty(JDBCPoolSource.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
this.notcontainSQL = conf.getProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0"); this.notcontainSQL = conf.getProperty(JDBCPoolSource.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
this.tablenotexistSqlstates = ";" + conf.getProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";"; this.tablenotexistSqlstates = ";" + conf.getProperty(JDBCPoolSource.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";";
this.tablecopySQL = conf.getProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}"); this.tablecopySQL = conf.getProperty(JDBCPoolSource.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
} }
/**
* 创建主键值目前只支持UUID赋值
*
* @param src Entity对象
*/
public void createPrimaryValue(T src) { public void createPrimaryValue(T src) {
if (autouuid) getPrimary().set(src, Utility.uuid()); if (autouuid) getPrimary().set(src, Utility.uuid());
} }
/**
* 获取Entity缓存器
*
* @return EntityCache
*/
public EntityCache<T> getCache() { public EntityCache<T> getCache() {
return cache; return cache;
} }
/**
* 判断缓存器是否已经全量加载过
*
* @return boolean
*/
public boolean isCacheFullLoaded() { public boolean isCacheFullLoaded() {
return cache != null && cache.isFullLoaded(); return cache != null && cache.isFullLoaded();
} }
/**
* 获取Entity构建器
*
* @return Creator
*/
public Creator<T> getCreator() { public Creator<T> getCreator() {
return creator; return creator;
} }
/**
* 获取Entity类名
*
* @return Class
*/
public Class<T> getType() { public Class<T> getType() {
return type; return type;
} }
/** /**
* 是否虚拟类 * 判断Entity是否虚拟类
* *
* @return 是否虚拟类 * @return boolean
*/ */
public boolean isVirtualEntity() { public boolean isVirtualEntity() {
return table == null; return table == null;
} }
/**
* 获取Entity的INSERT SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getInsertSQL(T bean) { public String getInsertSQL(T bean) {
if (this.tableStrategy == null) return insertSQL; if (this.tableStrategy == null) return insertSQL;
return insertSQL.replace("${newtable}", getTable(bean)); return insertSQL.replace("${newtable}", getTable(bean));
} }
/**
* 获取Entity的UPDATE SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getUpdateSQL(T bean) { public String getUpdateSQL(T bean) {
if (this.tableStrategy == null) return updateSQL; if (this.tableStrategy == null) return updateSQL;
return updateSQL.replace("${newtable}", getTable(bean)); return updateSQL.replace("${newtable}", getTable(bean));
} }
/**
* 获取Entity的DELETE SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getDeleteSQL(T bean) { public String getDeleteSQL(T bean) {
if (this.tableStrategy == null) return deleteSQL; if (this.tableStrategy == null) return deleteSQL;
return deleteSQL.replace("${newtable}", getTable(bean)); return deleteSQL.replace("${newtable}", getTable(bean));
} }
/**
* 根据主键值获取Entity的表名
*
* @param primary Entity主键值
*
* @return String
*/
public String getTable(Serializable primary) { public String getTable(Serializable primary) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, primary); String t = tableStrategy.getTable(table, primary);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 根据过滤条件获取Entity的表名
*
* @param node 过滤条件
*
* @return String
*/
public String getTable(FilterNode node) { public String getTable(FilterNode node) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, node); String t = tableStrategy.getTable(table, node);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 根据Entity对象获取Entity的表名
*
* @param bean Entity对象
*
* @return String
*/
public String getTable(T bean) { public String getTable(T bean) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, bean); String t = tableStrategy.getTable(table, bean);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 获取主键字段的Attribute
*
* @return Attribute
*/
public Attribute<T, Serializable> getPrimary() { public Attribute<T, Serializable> getPrimary() {
return this.primary; return this.primary;
} }
/**
* 遍历数据库表对应的所有字段, 不包含&#64;Transient字段
*
* @param action BiConsumer
*/
public void forEachAttribute(BiConsumer<String, Attribute<T, Serializable>> action) { public void forEachAttribute(BiConsumer<String, Attribute<T, Serializable>> action) {
this.attributeMap.forEach(action); this.attributeMap.forEach(action);
} }
/**
* 根据Entity字段名获取字段的Attribute
*
* @param fieldname Class字段名
*
* @return Attribute
*/
public Attribute<T, Serializable> getAttribute(String fieldname) { public Attribute<T, Serializable> getAttribute(String fieldname) {
if (fieldname == null) return null; if (fieldname == null) return null;
return this.attributeMap.get(fieldname); return this.attributeMap.get(fieldname);
} }
/**
* 根据Entity字段名获取可更新字段的Attribute
*
* @param fieldname Class字段名
*
* @return Attribute
*/
public Attribute<T, Serializable> getUpdateAttribute(String fieldname) { public Attribute<T, Serializable> getUpdateAttribute(String fieldname) {
return this.updateAttributeMap.get(fieldname); return this.updateAttributeMap.get(fieldname);
} }
/**
* 判断Entity类的字段名与表字段名s是否存在不一致的值
*
* @return boolean
*/
public boolean isNoAlias() { public boolean isNoAlias() {
return this.aliasmap == null; return this.aliasmap == null;
} }
/**
* 根据Flipper获取ORDER BY的SQL语句不存在Flipper或sort字段返回空字符串
*
* @param flipper 翻页对象
*
* @return String
*/
protected String createSQLOrderby(Flipper flipper) { protected String createSQLOrderby(Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty() || flipper.getSort().indexOf(';') >= 0 || flipper.getSort().indexOf('\n') >= 0) return ""; if (flipper == null || flipper.getSort() == null) return "";
final String sort = flipper.getSort(); final String sort = flipper.getSort();
if (sort.isEmpty() || sort.indexOf(';') >= 0 || sort.indexOf('\n') >= 0) return "";
String sql = this.sortOrderbySqls.get(sort); String sql = this.sortOrderbySqls.get(sort);
if (sql != null) return sql; if (sql != null) return sql;
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@@ -372,21 +526,47 @@ public final class EntityInfo<T> {
return sql; return sql;
} }
//根据field字段名获取数据库对应的字段名 /**
* 根据field字段名获取数据库对应的字段名
*
* @param tabalis 表别名
* @param fieldname 字段名
*
* @return String
*/
public String getSQLColumn(String tabalis, String fieldname) { public String getSQLColumn(String tabalis, String fieldname) {
return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname))
: (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); : (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname)));
} }
/**
* 获取主键字段的表字段名
*
* @return String
*/
public String getPrimarySQLColumn() { public String getPrimarySQLColumn() {
return getSQLColumn(null, this.primary.field()); return getSQLColumn(null, this.primary.field());
} }
//数据库字段名 /**
* 获取主键字段的带有表别名的表字段名
*
* @param tabalis 表别名
*
* @return String
*/
public String getPrimarySQLColumn(String tabalis) { public String getPrimarySQLColumn(String tabalis) {
return getSQLColumn(tabalis, this.primary.field()); return getSQLColumn(tabalis, this.primary.field());
} }
/**
* 拼接UPDATE给字段赋值的SQL片段
*
* @param col 表字段名
* @param cv ColumnValue
*
* @return CharSequence
*/
protected CharSequence formatSQLValue(String col, final ColumnValue cv) { protected CharSequence formatSQLValue(String col, final ColumnValue cv) {
if (cv == null) return null; if (cv == null) return null;
switch (cv.getExpress()) { switch (cv.getExpress()) {
@@ -404,14 +584,33 @@ public final class EntityInfo<T> {
return formatToString(cv.getValue()); return formatToString(cv.getValue());
} }
/**
* 获取所有数据表字段的Attribute, 不包含&#64;Transient字段
*
* @return Map
*/
protected Map<String, Attribute<T, Serializable>> getAttributes() { protected Map<String, Attribute<T, Serializable>> getAttributes() {
return attributeMap; return attributeMap;
} }
/**
* 判断日志级别
*
* @param l Level
*
* @return boolean
*/
public boolean isLoggable(Level l) { public boolean isLoggable(Level l) {
return l.intValue() >= this.logLevel; return l.intValue() >= this.logLevel;
} }
/**
* 将字段值序列化为可SQL的字符串
*
* @param value 字段值
*
* @return String
*/
protected String formatToString(Object value) { protected String formatToString(Object value) {
if (value == null) return null; if (value == null) return null;
if (value instanceof CharSequence) { if (value instanceof CharSequence) {
@@ -420,12 +619,30 @@ public final class EntityInfo<T> {
return String.valueOf(value); return String.valueOf(value);
} }
/**
* 将一行的ResultSet组装成一个Entity对象
*
* @param sels 指定字段
* @param set ResultSet
*
* @return Entity对象
* @throws SQLException SQLException
*/
protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException { protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException {
T obj = creator.create(); T obj = creator.create();
for (Attribute<T, Serializable> attr : queryAttributes) { for (Attribute<T, Serializable> attr : queryAttributes) {
if (sels == null || sels.test(attr.field())) { if (sels == null || sels.test(attr.field())) {
Serializable o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
final Class t = attr.type(); final Class t = attr.type();
Serializable o;
if (t == byte[].class) {
Blob blob = set.getBlob(this.getSQLColumn(null, attr.field()));
if (blob == null) {
o = null;
} else { //不支持超过2G的数据
o = blob.getBytes(1, (int) blob.length());
}
} else {
o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
if (t.isPrimitive()) { if (t.isPrimitive()) {
if (o != null) { if (o != null) {
if (t == int.class) { if (t == int.class) {
@@ -461,6 +678,7 @@ public final class EntityInfo<T> {
o = (char) 0; o = (char) 0;
} }
} }
}
attr.set(obj, o); attr.set(obj, o);
} }
} }

View File

@@ -3,14 +3,16 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.source; package org.redkale.source;
/** /**
* FilterBean用于过滤条件 所有的FilterBean都必须可以转换成FilterNode <br>
* *
* 不被标记为&#64;javax.persistence.Transient 的字段均视为过滤条件 * 不被标记为&#64;javax.persistence.Transient 的字段均视为过滤条件 <br>
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public interface FilterBean { public interface FilterBean {

View File

@@ -38,10 +38,10 @@ public @interface FilterColumn {
long least() default 1; long least() default 1;
/** /**
* express的默认值根据字段类型的不同而不同: * express的默认值根据字段类型的不同而不同: <br>
* 数组 --&gt; IN * 数组 --&gt; IN <br>
* Range --&gt; Between * Range --&gt; Between <br>
* 其他 --&gt; = * 其他 --&gt; = <br>
* *
* @return 字段表达式 * @return 字段表达式
*/ */

View File

@@ -5,11 +5,14 @@
*/ */
package org.redkale.source; package org.redkale.source;
import org.redkale.convert.json.JsonConvert; import java.util.Arrays;
/** /**
* FilterFuncColumn用于getNumberMap获取列表似数据, getNumberResult获取单字段值 getNumberMap获取多字段值 * FilterFuncColumn用于getNumberMap获取列表似数据, getNumberResult获取单字段值 getNumberMap获取多字段值
* *
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
public class FilterFuncColumn implements java.io.Serializable { public class FilterFuncColumn implements java.io.Serializable {
@@ -85,6 +88,6 @@ public class FilterFuncColumn implements java.io.Serializable {
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return this.getClass().getSimpleName() + "{func:" + this.func + ", columns:" + Arrays.toString(this.columns) + ", defvalue:" + this.defvalue + "}";
} }
} }

View File

@@ -10,9 +10,9 @@ import static java.lang.annotation.ElementType.FIELD;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 默认情况下FilterBean下的过滤字段之间是AND关系。 * 默认情况下FilterBean下的过滤字段之间是AND关系。 <br>
* 当需要使用OR或AND OR组合过滤查询时需要使用 FilterGroup。 * 当需要使用OR或AND OR组合过滤查询时需要使用 FilterGroup。 <br>
* FilterGroup 的value 必须是[OR]或者[AND]开头, 多级需要用点.分隔。 (注: 暂时不支持多级) * FilterGroup 的value 必须是[OR]或者[AND]开头, 多级需要用点.分隔。 (注: 暂时不支持多级) <br>
* 示例一: * 示例一:
* <blockquote><pre> * <blockquote><pre>
* public class TestFilterBean implements FilterBean { * public class TestFilterBean implements FilterBean {
@@ -49,9 +49,9 @@ import java.lang.annotation.*;
* private int birthday; * private int birthday;
* } * }
* </pre></blockquote> * </pre></blockquote>
* 转换的SQL语句为: WHERE id = ? AND ((desc LIKE ? AND name LIKE ?) OR (age = ? OR birthday = ?)) * 转换的SQL语句为: WHERE id = ? AND ((desc LIKE ? AND name LIKE ?) OR (age = ? OR birthday = ?)) <br>
* 因为默认是AND关系 &#64;FilterGroup("") 等价于 &#64;FilterGroup("[AND]") * 因为默认是AND关系 &#64;FilterGroup("") 等价于 &#64;FilterGroup("[AND]") <br>
* 所以示例二的&#64;FilterGroup("[OR]g1.[AND]subg1") 可以简化为 &#64;FilterGroup("[OR]g1.subg1") * 所以示例二的&#64;FilterGroup("[OR]g1.[AND]subg1") 可以简化为 &#64;FilterGroup("[OR]g1.subg1") <br>
*/ */
/** /**
* <p> * <p>

View File

@@ -10,6 +10,8 @@ import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 关联表过滤条件 <br>
* 关联关系表必须含主表, 不能是主表A关联表B表B再关联表C只能是主表A关联表B主表A关联表C <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -31,13 +33,13 @@ public @interface FilterJoinColumn {
/** /**
* *
* 多个关联字段, 默认使用join表(b)的主键, join表与被join表(a)的字段必须一样 * 多个关联字段, 默认使用join表(b)的主键, join表与被join表(a)的字段必须一样 <br>
* 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.userid AND a.usertype = b.usertype * 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.userid AND a.usertype = b.usertype <br>
* 那么注解为: &#64;FilterJoinColumn(table = Record.class, columns = {"userid", "usertype"}) * 那么注解为: &#64;FilterJoinColumn(table = Record.class, columns = {"userid", "usertype"}) <br>
* <p> * <p>
* columns中的字段名如果不一致可以将两个字段名用=连接成一个字段名 * columns中的字段名如果不一致可以将两个字段名用=连接成一个字段名 <br>
* 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.buyerid AND a.usertype = b.usertype * 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.buyerid AND a.usertype = b.usertype <br>
* 那么注解为: &#64;FilterJoinColumn(table = Record.class, columns = {"userid=buyerid", "usertype"}) * 那么注解为: &#64;FilterJoinColumn(table = Record.class, columns = {"userid=buyerid", "usertype"}) <br>
* *
* @return 关联字段 * @return 关联字段
*/ */

View File

@@ -13,6 +13,7 @@ import static org.redkale.source.FilterExpress.EQUAL;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* &#64;FilterJoinColumn对应的FilterNode对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -9,7 +9,7 @@ import java.util.Objects;
/** /**
* FilterKey主要用于自身字段间的表达式, 如: a.recordid = a.parentid , a.parentid就需要FilterKey来表示 new FilterKey("parentid") * FilterKey主要用于自身字段间的表达式, 如: a.recordid = a.parentid , a.parentid就需要FilterKey来表示 new FilterKey("parentid")
* * <br>
* 注意该类型不支持表达式FV_XXX、BETWEEN、NOTBETWEEN、IN、NOTIN * 注意该类型不支持表达式FV_XXX、BETWEEN、NOTBETWEEN、IN、NOTIN
* *
* <p> * <p>

View File

@@ -16,9 +16,9 @@ import org.redkale.util.*;
* 注意: <br> * 注意: <br>
* column的值以#开头的视为虚拟字段,不在过滤范围内 <br> * column的值以#开头的视为虚拟字段,不在过滤范围内 <br>
* 在调用 createSQLExpress 之前必须先调用 createSQLJoin <br> * 在调用 createSQLExpress 之前必须先调用 createSQLJoin <br>
* 在调用 createPredicate 之前必须先调用 isCacheUseable * 在调用 createPredicate 之前必须先调用 isCacheUseable <br>
*
* *
* <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx

View File

@@ -7,7 +7,7 @@ package org.redkale.source;
/** /**
* FilterValue主要用于复杂的表达式。<br> * FilterValue主要用于复杂的表达式。<br>
* 例如: col / 10 = 3 、MOD(col, 8) &gt; 0 这些都不是单独一个数值能表达的因此需要FilterValue 才构建 8 、 &gt; 、0 组合值. * 例如: col / 10 = 3 、MOD(col, 8) &gt; 0 这些都不是单独一个数值能表达的因此需要FilterValue 才构建 8 、 &gt; 、0 组合值
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.source;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 翻页对象, offset从0开始, limit必须大于0
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -27,6 +27,26 @@ import javax.sql.*;
*/ */
public class JDBCPoolSource { public class JDBCPoolSource {
static final String JDBC_CONNECTIONSMAX = "javax.persistence.connections.limit";
static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate";
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates";
static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
static final String JDBC_URL = "javax.persistence.jdbc.url";
static final String JDBC_USER = "javax.persistence.jdbc.user";
static final String JDBC_PWD = "javax.persistence.jdbc.password";
static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
static final String JDBC_SOURCE = "javax.persistence.jdbc.source";
private static final Map<String, AbstractMap.SimpleEntry<WatchService, List<WeakReference<JDBCPoolSource>>>> maps = new HashMap<>(); private static final Map<String, AbstractMap.SimpleEntry<WatchService, List<WeakReference<JDBCPoolSource>>>> maps = new HashMap<>();
private final AtomicLong usingCounter = new AtomicLong(); private final AtomicLong usingCounter = new AtomicLong();
@@ -97,6 +117,77 @@ public class JDBCPoolSource {
} }
} }
static ConnectionPoolDataSource createDataSource(Properties property) {
try {
return createDataSource(property.getProperty(JDBC_SOURCE, property.getProperty(JDBC_DRIVER)),
property.getProperty(JDBC_URL), property.getProperty(JDBC_USER), property.getProperty(JDBC_PWD));
} catch (Exception ex) {
throw new RuntimeException("(" + property + ") have no jdbc parameters", ex);
}
}
static ConnectionPoolDataSource createDataSource(String source0, String url, String user, String password) throws Exception {
String source = source0;
if (source0 == null || source0.isEmpty()) {
if (url.startsWith("jdbc:mysql:")) {
source0 = "com.mysql.jdbc.Driver";
} else if (url.startsWith("jdbc:mariadb:")) {
source0 = "org.mariadb.jdbc.Driver";
} else if (url.startsWith("jdbc:oracle:")) {
source0 = "oracle.jdbc.driver.OracleDriver";
} else if (url.startsWith("jdbc:postgresql:")) {
source0 = "org.postgresql.Driver";
} else if (url.startsWith("jdbc:microsoft:sqlserver:")) {
source0 = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
}
}
if (source0 != null && source0.contains("Driver")) { //为了兼容JPA的配置文件
switch (source0) {
case "org.mariadb.jdbc.Driver":
source = "org.mariadb.jdbc.MySQLDataSource";
break;
case "com.mysql.cj.jdbc.Driver":
case "com.mysql.jdbc.Driver":
try {
Class.forName("com.mysql.cj.jdbc.MysqlConnectionPoolDataSource");
source = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource";
} catch (Exception e) {
source = "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource";
}
break;
case "oracle.jdbc.driver.OracleDriver":
source = "oracle.jdbc.pool.OracleConnectionPoolDataSource";
break;
case "org.postgresql.Driver":
source = "org.postgresql.ds.PGConnectionPoolDataSource";
break;
case "com.microsoft.sqlserver.jdbc.SQLServerDriver":
source = "com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource";
break;
}
}
final Class clazz = Class.forName(source);
Object pdsource = clazz.newInstance();
if (source.contains(".postgresql.")) {
Class driver = Class.forName("org.postgresql.Driver");
Properties properties = (Properties) driver.getMethod("parseURL", String.class, Properties.class).invoke(null, url, new Properties());
clazz.getMethod("setServerName", String.class).invoke(pdsource, properties.getProperty("PGHOST"));
clazz.getMethod("setDatabaseName", String.class).invoke(pdsource, properties.getProperty("PGDBNAME"));
clazz.getMethod("setPortNumber", int.class).invoke(pdsource, Integer.parseInt(properties.getProperty("PGPORT", "5432")));
} else {
Method seturlm;
try {
seturlm = clazz.getMethod("setUrl", String.class);
} catch (Exception e) {
seturlm = clazz.getMethod("setURL", String.class);
}
seturlm.invoke(pdsource, url);
}
clazz.getMethod("setUser", String.class).invoke(pdsource, user);
clazz.getMethod("setPassword", String.class).invoke(pdsource, password);
return (ConnectionPoolDataSource) pdsource;
}
final boolean isMysql() { final boolean isMysql() {
return source != null && source.getClass().getName().contains(".mysql."); return source != null && source.getClass().getName().contains(".mysql.");
} }

View File

@@ -9,7 +9,8 @@ import java.util.function.*;
/** /**
* *
* 包含两边的值 * 取值范围,包含两边的值
*
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -22,31 +23,31 @@ public interface Range<E extends Comparable> extends java.io.Serializable, Predi
public E getMax(); public E getMax();
public static ByteRange crreate(byte min, byte max) { public static ByteRange create(byte min, byte max) {
return new ByteRange(min, max); return new ByteRange(min, max);
} }
public static ShortRange crreate(short min, short max) { public static ShortRange create(short min, short max) {
return new ShortRange(min, max); return new ShortRange(min, max);
} }
public static IntRange crreate(int min, int max) { public static IntRange create(int min, int max) {
return new IntRange(min, max); return new IntRange(min, max);
} }
public static LongRange crreate(long min, long max) { public static LongRange create(long min, long max) {
return new LongRange(min, max); return new LongRange(min, max);
} }
public static FloatRange crreate(float min, float max) { public static FloatRange create(float min, float max) {
return new FloatRange(min, max); return new FloatRange(min, max);
} }
public static DoubleRange crreate(double min, double max) { public static DoubleRange create(double min, double max) {
return new DoubleRange(min, max); return new DoubleRange(min, max);
} }
public static StringRange crreate(String min, String max) { public static StringRange create(String min, String max) {
return new StringRange(min, max); return new StringRange(min, max);
} }

View File

@@ -12,7 +12,7 @@ import java.util.*;
import java.util.function.*; import java.util.function.*;
/** /**
* VirtualEntity表示虚拟的数据实体类 通常Entity都会映射到数据库中的某个表而标记为VirtualEntity的Entity类只存在DataCache中 * VirtualEntity表示虚拟的数据实体类 通常Entity都会映射到数据库中的某个表而标记为&#64;VirtualEntity的Entity类只存在EntityCache中
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -24,12 +24,24 @@ import java.util.function.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface VirtualEntity { public @interface VirtualEntity {
//DataSource是否直接返回对象的真实引用 而不是copy一份 /**
* DataSource是否直接返回对象的真实引用 而不是copy一份
*
* @return boolean
*/
boolean direct() default false; boolean direct() default false;
//初始化时数据的加载器 /**
* 初始化时数据的加载器
*
* @return Class
*/
Class<? extends BiFunction<DataSource, Class, List>> loader() default DefaultFunctionLoader.class; Class<? extends BiFunction<DataSource, Class, List>> loader() default DefaultFunctionLoader.class;
/**
* 默认全量加载器
*
*/
public static class DefaultFunctionLoader implements BiFunction<DataSource, Class, List> { public static class DefaultFunctionLoader implements BiFunction<DataSource, Class, List> {
@Override @Override

View File

@@ -39,11 +39,13 @@ public abstract class AnyValue {
*/ */
public static final BiPredicate<String, String> EQUALSIGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2); public static final BiPredicate<String, String> EQUALSIGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2);
private final BiPredicate<String, String> predicate; private boolean ignoreCase;
private Entry<String>[] stringValues = new Entry[0]; private BiPredicate<String, String> predicate;
private Entry<AnyValue>[] entityValues = new Entry[0]; private Entry<String>[] stringEntrys = new Entry[0];
private Entry<DefaultAnyValue>[] anyEntrys = new Entry[0];
/** /**
* 创建空的DefaultAnyValue对象 * 创建空的DefaultAnyValue对象
@@ -96,27 +98,19 @@ public abstract class AnyValue {
* @param ignoreCase name是否不区分大小写 * @param ignoreCase name是否不区分大小写
*/ */
public DefaultAnyValue(boolean ignoreCase) { public DefaultAnyValue(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS; this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS;
} }
/**
* 创建DefaultAnyValue对象
*
* @param predicate name比较策略
*/
public DefaultAnyValue(BiPredicate<String, String> predicate) {
this.predicate = predicate;
}
/** /**
* 创建共享此内容的DefaultAnyValue对象 * 创建共享此内容的DefaultAnyValue对象
* *
* @return DefaultAnyValue对象 * @return DefaultAnyValue对象
*/ */
public DefaultAnyValue duplicate() { public DefaultAnyValue duplicate() {
DefaultAnyValue rs = new DefaultAnyValue(this.predicate); DefaultAnyValue rs = new DefaultAnyValue(this.ignoreCase);
rs.stringValues = this.stringValues; rs.stringEntrys = this.stringEntrys;
rs.entityValues = this.entityValues; rs.anyEntrys = this.anyEntrys;
return rs; return rs;
} }
@@ -124,13 +118,13 @@ public abstract class AnyValue {
if (av == null) return this; if (av == null) return this;
if (av instanceof DefaultAnyValue) { if (av instanceof DefaultAnyValue) {
final DefaultAnyValue adv = (DefaultAnyValue) av; final DefaultAnyValue adv = (DefaultAnyValue) av;
if (adv.stringValues != null) { if (adv.stringEntrys != null) {
for (Entry<String> en : adv.stringValues) { for (Entry<String> en : adv.stringEntrys) {
this.addValue(en.name, en.value); this.addValue(en.name, en.value);
} }
} }
if (adv.entityValues != null) { if (adv.anyEntrys != null) {
for (Entry<AnyValue> en : adv.entityValues) { for (Entry<DefaultAnyValue> en : adv.anyEntrys) {
this.addValue(en.name, en.value); this.addValue(en.name, en.value);
} }
} }
@@ -155,13 +149,13 @@ public abstract class AnyValue {
if (av == null) return this; if (av == null) return this;
if (av instanceof DefaultAnyValue) { if (av instanceof DefaultAnyValue) {
final DefaultAnyValue adv = (DefaultAnyValue) av; final DefaultAnyValue adv = (DefaultAnyValue) av;
if (adv.stringValues != null) { if (adv.stringEntrys != null) {
for (Entry<String> en : adv.stringValues) { for (Entry<String> en : adv.stringEntrys) {
this.setValue(en.name, en.value); this.setValue(en.name, en.value);
} }
} }
if (adv.entityValues != null) { if (adv.anyEntrys != null) {
for (Entry<AnyValue> en : adv.entityValues) { for (Entry<DefaultAnyValue> en : adv.anyEntrys) {
this.setValue(en.name, en.value); this.setValue(en.name, en.value);
} }
} }
@@ -184,21 +178,41 @@ public abstract class AnyValue {
@Override @Override
public Entry<String>[] getStringEntrys() { public Entry<String>[] getStringEntrys() {
return stringValues; return stringEntrys;
}
public void setStringEntrys(Entry<String>[] stringEntrys) {
this.stringEntrys = stringEntrys;
} }
@Override @Override
public Entry<AnyValue>[] getAnyEntrys() { public Entry<AnyValue>[] getAnyEntrys() {
return entityValues; return (Entry<AnyValue>[]) (Entry[]) anyEntrys;
}
public void setAnyEntrys(Entry<DefaultAnyValue>[] anyEntrys) {
this.anyEntrys = anyEntrys;
}
public boolean isIgnoreCase() {
return ignoreCase;
}
public void setIgnoreCase(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
if (this.predicate == null) {
this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS;
}
} }
@Override @Override
@java.beans.Transient
public String[] getNames() { public String[] getNames() {
Set<String> set = new LinkedHashSet<>(); Set<String> set = new LinkedHashSet<>();
for (Entry en : this.stringValues) { for (Entry en : this.stringEntrys) {
set.add(en.name); set.add(en.name);
} }
for (Entry en : this.entityValues) { for (Entry en : this.anyEntrys) {
set.add(en.name); set.add(en.name);
} }
return set.toArray(new String[set.size()]); return set.toArray(new String[set.size()]);
@@ -206,12 +220,12 @@ public abstract class AnyValue {
@Override @Override
public String[] getValues(String... names) { public String[] getValues(String... names) {
return Entry.getValues(this.predicate, String.class, this.stringValues, names); return Entry.getValues(this.predicate, String.class, this.stringEntrys, names);
} }
@Override @Override
public AnyValue[] getAnyValues(String... names) { public AnyValue[] getAnyValues(String... names) {
return Entry.getValues(this.predicate, AnyValue.class, this.entityValues, names); return Entry.getValues(this.predicate, DefaultAnyValue.class, this.anyEntrys, names);
} }
@Override @Override
@@ -220,8 +234,8 @@ public abstract class AnyValue {
} }
public DefaultAnyValue clear() { public DefaultAnyValue clear() {
this.stringValues = new Entry[0]; this.stringEntrys = new Entry[0];
this.entityValues = new Entry[0]; this.anyEntrys = new Entry[0];
return this; return this;
} }
@@ -230,7 +244,7 @@ public abstract class AnyValue {
if (getValue(name) == null) { if (getValue(name) == null) {
this.addValue(name, value); this.addValue(name, value);
} else { } else {
for (Entry<String> en : this.stringValues) { for (Entry<String> en : this.stringEntrys) {
if (predicate.test(en.name, name)) { if (predicate.test(en.name, name)) {
en.value = value; en.value = value;
return this; return this;
@@ -245,9 +259,9 @@ public abstract class AnyValue {
if (getValue(name) == null) { if (getValue(name) == null) {
this.addValue(name, value); this.addValue(name, value);
} else { } else {
for (Entry<AnyValue> en : this.entityValues) { for (Entry<DefaultAnyValue> en : this.anyEntrys) {
if (predicate.test(en.name, name)) { if (predicate.test(en.name, name)) {
en.value = value; en.value = (DefaultAnyValue) value;
return this; return this;
} }
} }
@@ -264,19 +278,19 @@ public abstract class AnyValue {
} }
public DefaultAnyValue addValue(String name, String value) { public DefaultAnyValue addValue(String name, String value) {
this.stringValues = Utility.append(this.stringValues, new Entry(name, value)); this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value));
return this; return this;
} }
public DefaultAnyValue addValue(String name, AnyValue value) { public DefaultAnyValue addValue(String name, AnyValue value) {
if (name == null || value == null) return this; if (name == null || value == null) return this;
this.entityValues = Utility.append(this.entityValues, new Entry(name, value)); this.anyEntrys = Utility.append(this.anyEntrys, new Entry(name, value));
return this; return this;
} }
@Override @Override
public AnyValue getAnyValue(String name) { public AnyValue getAnyValue(String name) {
for (Entry<AnyValue> en : this.entityValues) { for (Entry<DefaultAnyValue> en : this.anyEntrys) {
if (predicate.test(en.name, name)) { if (predicate.test(en.name, name)) {
return en.value; return en.value;
} }
@@ -286,7 +300,7 @@ public abstract class AnyValue {
@Override @Override
public String getValue(String name) { public String getValue(String name) {
for (Entry<String> en : this.stringValues) { for (Entry<String> en : this.stringEntrys) {
if (predicate.test(en.name, name)) { if (predicate.test(en.name, name)) {
return en.value; return en.value;
} }
@@ -296,12 +310,12 @@ public abstract class AnyValue {
@Override @Override
public String[] getValues(String name) { public String[] getValues(String name) {
return Entry.getValues(this.predicate, String.class, this.stringValues, name); return Entry.getValues(this.predicate, String.class, this.stringEntrys, name);
} }
@Override @Override
public AnyValue[] getAnyValues(String name) { public AnyValue[] getAnyValues(String name) {
return Entry.getValues(this.predicate, AnyValue.class, this.entityValues, name); return Entry.getValues(this.predicate, DefaultAnyValue.class, this.anyEntrys, name);
} }
} }
@@ -312,11 +326,16 @@ public abstract class AnyValue {
T value; T value;
@java.beans.ConstructorProperties({"name", "value"})
public Entry(String name0, T value0) { public Entry(String name0, T value0) {
this.name = name0; this.name = name0;
this.value = value0; this.value = value0;
} }
public String getName() {
return name;
}
public T getValue() { public T getValue() {
return value; return value;
} }
@@ -368,9 +387,9 @@ public abstract class AnyValue {
return new DefaultAnyValue(); return new DefaultAnyValue();
} }
public String toString(int len) { public String toString(int indent) { //indent: 缩进长度
if (len < 0) len = 0; if (indent < 0) indent = 0;
char[] chars = new char[len]; char[] chars = new char[indent];
Arrays.fill(chars, ' '); Arrays.fill(chars, ' ');
final String space = new String(chars); final String space = new String(chars);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -379,7 +398,7 @@ public abstract class AnyValue {
sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n"); sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n");
} }
for (Entry<AnyValue> en : getAnyEntrys()) { for (Entry<AnyValue> en : getAnyEntrys()) {
sb.append(space).append(" '").append(en.name).append("': '").append(en.value.toString(len + 4)).append("',\r\n"); sb.append(space).append(" '").append(en.name).append("': '").append(en.value.toString(indent + 4)).append("',\r\n");
} }
sb.append(space).append('}'); sb.append(space).append('}');
return sb.toString(); return sb.toString();

View File

@@ -296,7 +296,6 @@ public interface Attribute<T, F> {
for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) { for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue;
if (!method.getName().startsWith("set")) continue; if (!method.getName().startsWith("set")) continue;
if (method.getReturnType() != void.class) continue;
if (method.getParameterCount() != 1) continue; if (method.getParameterCount() != 1) continue;
list.add(create(clazz, null, method)); list.add(create(clazz, null, method));
} }

View File

@@ -337,27 +337,38 @@ public final class ByteArray {
* @return 字符串 * @return 字符串
*/ */
public String toDecodeString(final int offset, int len, final Charset charset) { public String toDecodeString(final int offset, int len, final Charset charset) {
int index = offset; int start = offset;
for (int i = offset; i < (offset + len); i++) { final int end = offset + len;
boolean flag = false; //是否需要转义
byte[] bs = content;
for (int i = offset; i < end; i++) {
if (content[i] == '+' || content[i] == '%') {
flag = true;
break;
}
}
if (flag) {
int index = 0;
bs = new byte[len];
for (int i = offset; i < end; i++) {
switch (content[i]) { switch (content[i]) {
case '+': case '+':
content[index] = ' '; bs[index] = ' ';
break; break;
case '%': case '%':
content[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i])));
break; break;
default: default:
content[index] = content[i]; bs[index] = content[i];
break; break;
} }
index++; index++;
} }
for (int i = index + 1; i < (offset + len); i++) { start = 0;
content[i] = ' '; len = index;
} }
len = index - offset; if (charset == null) return new String(Utility.decodeUTF8(bs, start, len));
if (charset == null) return new String(Utility.decodeUTF8(content, offset, len)); return new String(bs, start, len, charset);
return new String(content, offset, len, charset);
} }
private static int hexBit(byte b) { private static int hexBit(byte b) {

View File

@@ -12,7 +12,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 被标记的日志级别以上的才会被记录 * 被标记的日志级别以上的才会被记录
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited

View File

@@ -11,6 +11,7 @@ import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
/** /**
* 对象池
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -7,6 +7,8 @@ import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
/** /**
* JavaBean类对象的拷贝相同的字段名会被拷贝 <br>
* <b>注意</b>: 拷贝类与被拷贝类的字段可见模式必须一致, 要么都是public field, 要么都是getter、setter模式。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -9,6 +9,7 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.logging.*; import java.util.logging.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -259,14 +260,6 @@ public final class ResourceFactory {
return null; return null;
} }
//Map无法保证ResourceEntry的自动同步 暂时不提供该功能
@Deprecated
private <A> Map<String, A> find(final Pattern reg, Class<? extends A> clazz, A exclude) {
Map<String, A> result = new LinkedHashMap();
load(reg, clazz, exclude, result);
return result;
}
private <A> void load(final Pattern reg, Class<? extends A> clazz, final A exclude, final Map<String, A> result) { private <A> void load(final Pattern reg, Class<? extends A> clazz, final A exclude, final Map<String, A> result) {
ConcurrentHashMap<String, ResourceEntry> map = this.store.get(clazz); ConcurrentHashMap<String, ResourceEntry> map = this.store.get(clazz);
if (map != null) { if (map != null) {
@@ -286,10 +279,18 @@ public final class ResourceFactory {
} }
public <T> boolean inject(final Object src, final T attachment) { public <T> boolean inject(final Object src, final T attachment) {
return inject(src, attachment, new ArrayList()); return inject(src, attachment, null);
} }
private <T> boolean inject(final Object src, final T attachment, final List<Object> list) { public <T> boolean inject(final Object src, final BiConsumer<Object, Field> consumer) {
return inject(src, null, consumer);
}
public <T> boolean inject(final Object src, final T attachment, final BiConsumer<Object, Field> consumer) {
return inject(src, attachment, consumer, new ArrayList());
}
private <T> boolean inject(final Object src, final T attachment, final BiConsumer<Object, Field> consumer, final List<Object> list) {
if (src == null) return false; if (src == null) return false;
try { try {
list.add(src); list.add(src);
@@ -301,8 +302,8 @@ public final class ResourceFactory {
final Class classtype = field.getType(); final Class classtype = field.getType();
final Type genctype = field.getGenericType(); final Type genctype = field.getGenericType();
Resource rc = field.getAnnotation(Resource.class); Resource rc = field.getAnnotation(Resource.class);
if (rc == null) { if (rc == null) { //深度注入
boolean flag = true; boolean flag = true; //是否没有重复
Object ns = field.get(src); Object ns = field.get(src);
for (Object o : list) { for (Object o : list) {
if (o == ns) { if (o == ns) {
@@ -312,10 +313,11 @@ public final class ResourceFactory {
} }
if (ns == null) continue; if (ns == null) continue;
if (ns.getClass().isPrimitive() || ns.getClass().isArray() || ns.getClass().getName().startsWith("java")) continue; if (ns.getClass().isPrimitive() || ns.getClass().isArray() || ns.getClass().getName().startsWith("java")) continue;
if (flag) this.inject(ns, attachment, list); if (flag) this.inject(ns, attachment, consumer, list);
continue; continue;
} }
if (Modifier.isFinal(field.getModifiers())) continue; if (Modifier.isFinal(field.getModifiers())) continue;
if (consumer != null) consumer.accept(src, field);
String tname = rc.name(); String tname = rc.name();
if (tname.contains(RESOURCE_PARENT_NAME)) { if (tname.contains(RESOURCE_PARENT_NAME)) {
try { try {
@@ -333,10 +335,6 @@ public final class ResourceFactory {
final String rcname = tname; final String rcname = tname;
ResourceEntry re = findEntry(rcname, genctype); ResourceEntry re = findEntry(rcname, genctype);
if (re == null) { if (re == null) {
// if (Map.class.isAssignableFrom(classtype)) {
// Map map = find(Pattern.compile(rcname.isEmpty() ? ".*" : rcname), (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[1], src);
// if (map != null) re = new ResourceEntry(map);
// } else
if (rcname.startsWith("property.")) { if (rcname.startsWith("property.")) {
re = findEntry(rcname, String.class); re = findEntry(rcname, String.class);
} else { } else {

View File

@@ -11,6 +11,7 @@ import java.util.stream.*;
/** /**
* 页集合。 结构由一个total总数和一个List列表组合而成。 * 页集合。 结构由一个total总数和一个List列表组合而成。
*
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *

View File

@@ -15,6 +15,8 @@ import java.util.zip.GZIPInputStream;
import javax.net.ssl.*; import javax.net.ssl.*;
/** /**
*
* 常见操作的工具类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -175,6 +177,24 @@ public final class Utility {
return news; return news;
} }
/**
* 判断字符串是否包含指定的字符包含返回true
*
* @param string 字符串
* @param values 字符集合
*
* @return boolean
*/
public static boolean contains(String string, char... values) {
if (string == null) return false;
for (char ch : Utility.charArray(string)) {
for (char ch2 : values) {
if (ch == ch2) return true;
}
}
return false;
}
/** /**
* 删除掉字符串数组中包含指定的字符串 * 删除掉字符串数组中包含指定的字符串
* *
@@ -267,6 +287,7 @@ public final class Utility {
for (byte b : bytes) { for (byte b : bytes) {
if (last) sb.append(','); if (last) sb.append(',');
int v = b & 0xff; int v = b & 0xff;
sb.append("0x");
if (v < 16) sb.append('0'); if (v < 16) sb.append('0');
sb.append(Integer.toHexString(v)); sb.append(Integer.toHexString(v));
last = true; last = true;
@@ -526,7 +547,6 @@ public final class Utility {
public static byte[] hexToBin(CharSequence src, int offset, int len) { public static byte[] hexToBin(CharSequence src, int offset, int len) {
final int size = (len + 1) / 2; final int size = (len + 1) / 2;
final byte[] bytes = new byte[size]; final byte[] bytes = new byte[size];
final int end = offset + len;
String digits = "0123456789abcdef"; String digits = "0123456789abcdef";
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int ch1 = src.charAt(offset + i * 2); int ch1 = src.charAt(offset + i * 2);
@@ -578,7 +598,6 @@ public final class Utility {
public static byte[] hexToBin(char[] src, int offset, int len) { public static byte[] hexToBin(char[] src, int offset, int len) {
final int size = (len + 1) / 2; final int size = (len + 1) / 2;
final byte[] bytes = new byte[size]; final byte[] bytes = new byte[size];
final int end = offset + len;
String digits = "0123456789abcdef"; String digits = "0123456789abcdef";
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int ch1 = src[offset + i * 2]; int ch1 = src[offset + i * 2];
@@ -595,6 +614,13 @@ public final class Utility {
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/**
* 使用UTF-8编码将byte[]转换成char[]
*
* @param array byte[]
*
* @return char[]
*/
public static char[] decodeUTF8(final byte[] array) { public static char[] decodeUTF8(final byte[] array) {
return decodeUTF8(array, 0, array.length); return decodeUTF8(array, 0, array.length);
} }
@@ -760,13 +786,16 @@ public final class Utility {
return DEFAULTSSL_CONTEXT; return DEFAULTSSL_CONTEXT;
} }
public static javax.net.ssl.HostnameVerifier getDefaultHostnameVerifier() {
return defaultVerifier;
}
public static Socket createDefaultSSLSocket(InetSocketAddress address) throws IOException { public static Socket createDefaultSSLSocket(InetSocketAddress address) throws IOException {
return createDefaultSSLSocket(address.getAddress(), address.getPort()); return createDefaultSSLSocket(address.getAddress(), address.getPort());
} }
public static Socket createDefaultSSLSocket(InetAddress host, int port) throws IOException { public static Socket createDefaultSSLSocket(InetAddress host, int port) throws IOException {
Socket socket = DEFAULTSSL_CONTEXT.getSocketFactory().createSocket(host, port); Socket socket = DEFAULTSSL_CONTEXT.getSocketFactory().createSocket(host, port);
return socket; return socket;
} }

View File

@@ -72,7 +72,6 @@ public class HelloService implements Service {
//查询单个 //查询单个
@RestMapping(name = "find") @RestMapping(name = "find")
@RestMapping(name = "jsfind", jsvar = "varhello")
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象
return source.find(HelloEntity.class, id); return source.find(HelloEntity.class, id);
} }

View File

@@ -122,12 +122,4 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
resp.finishJson(bean); resp.finishJson(bean);
} }
@AuthIgnore
@WebAction(url = "/hello/jsfind/")
public void jsfind(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
HelloEntity bean = service.findHello(id);
resp.finishJsResult("varhello", bean);
}
} }

View File

@@ -17,9 +17,8 @@ import org.redkale.source.*;
public class LoginRecord extends BaseEntity { public class LoginRecord extends BaseEntity {
@Id @Id
@GeneratedValue @Column(comment = "主键ID; 值=create36time(9位)+UUID(32位)")
@Column(comment = "UUID") private String loginid = ""; //主键ID; 值=create36time(9位)+UUID(32位)
private String loginid = ""; //UUID
@Column(updatable = false, comment = "C端用户ID") @Column(updatable = false, comment = "C端用户ID")
private long userid; //C端用户ID private long userid; //C端用户ID
@@ -129,9 +128,16 @@ public class LoginRecord extends BaseEntity {
return getTable(table, 0, bean.getCreatetime()); return getTable(table, 0, bean.getCreatetime());
} }
//根据主键ID查询单个记录时调用本方法
@Override
public String getTable(String table, Serializable primary) {
String id = (String) primary;
return getTable(table, 0, Long.parseLong(id.substring(0, 9), 36));
}
private String getTable(String table, int day, long createtime) { private String getTable(String table, int day, long createtime) {
int pos = table.indexOf('.'); int pos = table.indexOf('.');
String year = (day > 0 ? "" + day / 10000 : String.format(yearformat, createtime)); String year = (day > 0 ? "" + day / 10000 : String.format(yearformat, createtime)); //没有day取createtime
return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime)); return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime));
} }
} }

View File

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

View File

@@ -17,9 +17,8 @@ import org.redkale.source.*;
public class LoginUserRecord extends BaseEntity { public class LoginUserRecord extends BaseEntity {
@Id @Id
@GeneratedValue @Column(comment = "记录ID; 值=userid+'-'+UUID")
@Column(comment = "UUID") private String seqid = ""; //记录ID; 值=userid+'-'+UUID
private String seqid = ""; //UUID
@Column(updatable = false, comment = "C端用户ID") @Column(updatable = false, comment = "C端用户ID")
private long userid; //C端用户ID private long userid; //C端用户ID
@@ -79,8 +78,9 @@ public class LoginUserRecord extends BaseEntity {
} }
@Override @Override
public String getTable(String table, Serializable userid) { public String getTable(String table, Serializable primary) {
return getHashTable(table, (int) (((Long) userid) % 100)); String id = (String) primary;
return getHashTable(table, (int) (Long.parseLong(id.substring(0, id.indexOf('-'))) % 100));
} }
private String getHashTable(String table, int hash) { private String getHashTable(String table, int hash) {

Some files were not shown because too many files have changed in this diff Show More