This commit is contained in:
16
README.md
16
README.md
@@ -1,27 +1,27 @@
|
||||
<h1>项目介绍</h1>
|
||||
<b>项目介绍</b>
|
||||
<p>
|
||||
Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 11全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
|
||||
</p>
|
||||
<strong>RedKale 有如下主要特点:</strong>
|
||||
<ol>
|
||||
<li>大量使用Java 8新特性(接口默认值、Stream、Lambda、JDk8内置的ASM等)</li>
|
||||
<li>大量使用Java 8+新特性(接口默认值、Stream、Lambda、内置的ASM、HttpClient等)</li>
|
||||
<li>提供HTTP服务,同时内置JSON功能与限时缓存功能</li>
|
||||
<li>TCP层完全使用NIO,并统一TCP与UDP的接口换</li>
|
||||
<li>提供分布式与集中式部署的无缝切换</li>
|
||||
<li>提供类似JPA功能,包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
|
||||
<li>可以动态修改已依赖注入的资源</li>
|
||||
</ol>
|
||||
</ol>
|
||||
|
||||
<strong>Redkale 设计理念</strong>
|
||||
<p>
|
||||
作为一个全新的微服务框架,Redkale在接口定义上使用了Java 8大量的新语法,接口有默认实现、接口带静态方法、重复注解等特性,同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的,而非以容器为主,几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的,所有web资源/配置由Tomcat控制,开发者很能难控制到Tomcat内部,而Redkale的HTTP服务只是个组件,开发者既可以自己启动和配置HttpServer,也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此,Redkale提供的依赖注入仅通过ResouceFactory一个类来控制,非常轻量,并且可动态更改已注入的资源。Spring提倡控制反转思想,而自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看,Redkale的架构分两层:接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务;若想使用Hibernate作为数据库操作,可以写一个自己的DataSource实现类;JSON的序列化和反序列化也可以使用第三方的实现;Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想,让框架里的各个组件均可让开发者控制。<br/>
|
||||
与主流框架比,功能上Redkale显得很简单,这体现了Redkale的简易性,而并非是不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持HTTPS和JSP,HTTPS比HTTP多了一层加密解密,这种密集型的计算不是Java的专长,通常提供HTTP服务的架构不会将Java动态服务器放在最前端,而是在前方会放nginx或apache,除了负载均衡还能静动分离,因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术,现在是一个多样化终端的时代,终端不只局限于桌面程序和PC浏览器,还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端,这些都不是JSP能方便兼顾的,而HTTP+JSON作为通用性接口可以避免重复开发,模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选,不会为了迎合主流而提供,而是以良好的设计思想为指导。这是Redkale的主导思维。
|
||||
作为一个全新的微服务框架,Redkale在接口定义上使用了Java 8以上版本的大量新特性,接口有默认实现、接口带静态方法、重复注解等特性,同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的,而非以容器为主,几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的,所有web资源/配置由Tomcat控制,开发者很能难控制到Tomcat内部,而Redkale的HTTP服务只是个组件,开发者既可以自己启动和配置HttpServer,也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此,Redkale提供的依赖注入仅通过ResouceFactory一个类来控制,非常轻量,并且可动态更改已注入的资源。Spring提倡控制反转思想,而自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看,Redkale的架构分两层:接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务;若想使用Hibernate作为数据库操作,可以写一个自己的DataSource实现类;JSON的序列化和反序列化也可以使用第三方的实现;Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想,让框架里的各个组件均可让开发者控制。<br/>
|
||||
与主流框架比,功能上Redkale显得很简单,这体现了Redkale的简易性,而并非是不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持JSP, JSP其实算是一个落后的技术,现在是一个多样化终端的时代,终端不只局限于桌面程序和PC浏览器,还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端,这些都不是JSP能方便兼顾的,而HTTP+JSON作为通用性接口可以避免重复开发,模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选,不会为了迎合主流而提供,而是以良好的设计思想为指导。这是Redkale的主导思维。
|
||||
</p>
|
||||
|
||||
|
||||
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
||||
<b>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></b>
|
||||
|
||||
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
||||
<b>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></b>
|
||||
|
||||
<h5>欢迎加入Redkale QQ群: 527523235</h5>
|
||||
<b>欢迎加入Redkale QQ群: 527523235</b>
|
||||
|
||||
|
||||
8
pom.xml
8
pom.xml
@@ -15,10 +15,10 @@
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
|
||||
<junit.version>5.7.0</junit.version>
|
||||
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
|
||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
|
||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||
<maven-compiler-plugin.version>3.9.0</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>3.0.0-M6</maven-surefire-plugin.version>
|
||||
<maven-failsafe-plugin.version>3.0.0-M6</maven-failsafe-plugin.version>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
|
||||
@@ -732,7 +732,10 @@ public final class Application {
|
||||
if (key.startsWith("redkale.datasource[") || key.startsWith("redkale.cachesource[")) {
|
||||
sourceProperties.put(key, value);
|
||||
} else if (key.startsWith("system.property.")) {
|
||||
System.setProperty(key.substring("system.property.".length()), value);
|
||||
String propName = key.substring("system.property.".length());
|
||||
if (System.getProperty(propName) == null) { //命令行传参数优先级高
|
||||
System.setProperty(propName, value);
|
||||
}
|
||||
} else if (key.startsWith("mimetype.property.")) {
|
||||
MimeType.add(key.substring("mimetype.property.".length()), value);
|
||||
} else if (key.startsWith("property.")) {
|
||||
|
||||
@@ -50,6 +50,7 @@ public class LoggingFileHandler extends LoggingBaseHandler {
|
||||
|
||||
public LoggingConsoleHandler() {
|
||||
super();
|
||||
setFormatter(new LoggingFormater());
|
||||
configure();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
||||
return writer;
|
||||
}
|
||||
|
||||
protected <S extends W> S fieldFunc(S writer, BiFunction<Object, Object, Object> mapFieldFunc, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
writer.mapFieldFunc = mapFieldFunc;
|
||||
writer.objFieldFunc = objFieldFunc;
|
||||
writer.objExtFunc = objExtFunc;
|
||||
return writer;
|
||||
}
|
||||
|
||||
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
|
||||
|
||||
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
|
||||
|
||||
@@ -61,6 +61,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
private final Set<Class> skipIgnores = new HashSet();
|
||||
|
||||
final Set<String> ignoreMapColumns = new HashSet();
|
||||
|
||||
//key:需要屏蔽的字段;value:排除的字段名
|
||||
private final ConcurrentHashMap<Class, Set<String>> ignoreAlls = new ConcurrentHashMap();
|
||||
|
||||
@@ -707,7 +709,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
if (set == null) {
|
||||
ignoreAlls.put(type, new HashSet<>(Arrays.asList(excludeColumns)));
|
||||
} else {
|
||||
set.addAll(Arrays.asList(excludeColumns));
|
||||
synchronized (set) {
|
||||
set.addAll(Arrays.asList(excludeColumns));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,17 +720,47 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
if (set == null) {
|
||||
ignoreAlls.put(type, new HashSet<>(excludeColumns));
|
||||
} else {
|
||||
set.addAll(new ArrayList(excludeColumns));
|
||||
synchronized (set) {
|
||||
set.addAll(new ArrayList(excludeColumns));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void register(final Class type, boolean ignore, String... columns) {
|
||||
if (type == Map.class) {
|
||||
synchronized (ignoreMapColumns) {
|
||||
if (ignore) {
|
||||
for (String column : columns) {
|
||||
ignoreMapColumns.add(column);
|
||||
}
|
||||
} else {
|
||||
for (String column : columns) {
|
||||
ignoreMapColumns.remove(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (String column : columns) {
|
||||
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||
}
|
||||
}
|
||||
|
||||
public final void register(final Class type, boolean ignore, Collection<String> columns) {
|
||||
if (type == Map.class) {
|
||||
synchronized (ignoreMapColumns) {
|
||||
if (ignore) {
|
||||
for (String column : columns) {
|
||||
ignoreMapColumns.add(column);
|
||||
}
|
||||
} else {
|
||||
for (String column : columns) {
|
||||
ignoreMapColumns.remove(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (String column : columns) {
|
||||
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ package org.redkale.convert;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Map的序列化操作类
|
||||
@@ -32,6 +33,8 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
||||
|
||||
protected final Object lock = new Object();
|
||||
|
||||
protected final Set<String> ignoreMapColumns;
|
||||
|
||||
public MapEncoder(final ConvertFactory factory, final Type type) {
|
||||
this.type = type;
|
||||
try {
|
||||
@@ -43,6 +46,9 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
||||
this.keyEncoder = factory.getAnyEncoder();
|
||||
this.valueEncoder = factory.getAnyEncoder();
|
||||
}
|
||||
synchronized (factory.ignoreMapColumns) {
|
||||
this.ignoreMapColumns = factory.ignoreMapColumns.isEmpty() ? null : new HashSet<>(factory.ignoreMapColumns);
|
||||
}
|
||||
} finally {
|
||||
inited = true;
|
||||
synchronized (lock) {
|
||||
@@ -74,11 +80,15 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> ignoreColumns = this.ignoreMapColumns;
|
||||
BiFunction<K, V, V> mapFieldFunc = (BiFunction) out.mapFieldFunc;
|
||||
if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) {
|
||||
boolean first = true;
|
||||
for (Map.Entry<K, V> en : values.entrySet()) {
|
||||
if (ignoreColumns != null && ignoreColumns.contains(en.getKey())) continue;
|
||||
V v = mapFieldFunc == null ? en.getValue() : mapFieldFunc.apply(en.getKey(), en.getValue());
|
||||
if (!first) out.writeArrayMark();
|
||||
writeMemberValue(out, member, en.getKey(), en.getValue(), first);
|
||||
writeMemberValue(out, member, en.getKey(), v, first);
|
||||
if (first) first = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ public abstract class Writer {
|
||||
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
||||
protected Type specify;
|
||||
|
||||
//对某个key值进行动态处理,仅供MapEncoder使用
|
||||
protected BiFunction<Object, Object, Object> mapFieldFunc;
|
||||
|
||||
//对某个字段值进行动态处理
|
||||
protected BiFunction<Attribute, Object, Object> objFieldFunc;
|
||||
|
||||
|
||||
@@ -58,16 +58,25 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||
return newConvert(fieldFunc, null);
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc) {
|
||||
return newConvert(objFieldFunc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new JsonConvert(getFactory(), tiny) {
|
||||
@Override
|
||||
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||
return fieldFunc(writer, objFieldFunc, objExtFunc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public JsonConvert newConvert(BiFunction<Object, Object, Object> mapFieldFunc, final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new JsonConvert(getFactory(), tiny) {
|
||||
@Override
|
||||
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, mapFieldFunc, objFieldFunc, objExtFunc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,8 +34,10 @@ public class HttpMessageRequest extends HttpRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setRequestURI(String uri) {
|
||||
@Override
|
||||
public HttpMessageRequest setRequestURI(String uri) {
|
||||
this.requestURI = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -62,6 +62,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
||||
Set<S> newservlets = new HashSet<>(servlets);
|
||||
newservlets.remove(servlet);
|
||||
this.servlets = newservlets;
|
||||
doAfterRemove(servlet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,8 +96,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
||||
synchronized (lock2) {
|
||||
if (mappings.containsKey(key)) {
|
||||
Map<K, S> newmappings = new HashMap<>(mappings);
|
||||
newmappings.remove(key);
|
||||
S s = newmappings.remove(key);
|
||||
this.mappings = newmappings;
|
||||
doAfterRemove(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,9 +114,13 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
||||
}
|
||||
for (K key : keys) newmappings.remove(key);
|
||||
this.mappings = newmappings;
|
||||
doAfterRemove(servlet);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doAfterRemove(S servlet) {
|
||||
}
|
||||
|
||||
protected S mappingServlet(K key) {
|
||||
return mappings.get(key);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,19 @@ public abstract class Request<C extends Context> {
|
||||
this.jsonConvert = context.getJsonConvert();
|
||||
}
|
||||
|
||||
protected Request(Request<C> request) {
|
||||
this.context = request.context;
|
||||
this.bsonConvert = request.bsonConvert;
|
||||
this.jsonConvert = request.jsonConvert;
|
||||
this.createTime = request.createTime;
|
||||
this.keepAlive = request.keepAlive;
|
||||
this.pipelineIndex = request.pipelineIndex;
|
||||
this.pipelineCount = request.pipelineCount;
|
||||
this.pipelineOver = request.pipelineOver;
|
||||
this.hashid = request.hashid;
|
||||
this.channel = request.channel;
|
||||
}
|
||||
|
||||
protected Request copyHeader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -21,4 +21,24 @@ public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpRe
|
||||
//Server执行start后运行此方法
|
||||
public void postStart(HttpContext context, AnyValue config) {
|
||||
}
|
||||
|
||||
protected void setMethod(HttpRequest request, String method) {
|
||||
request.setMethod(method);
|
||||
}
|
||||
|
||||
protected void setRequestURI(HttpRequest request, String requestURI) {
|
||||
request.setRequestURI(requestURI);
|
||||
}
|
||||
|
||||
protected void setRemoteAddr(HttpRequest request, String remoteAddr) {
|
||||
request.setRemoteAddr(remoteAddr);
|
||||
}
|
||||
|
||||
protected void setParameter(HttpRequest request, String name, String value) {
|
||||
request.setParameter(name, value);
|
||||
}
|
||||
|
||||
protected void setHeader(HttpRequest request, String name, String value) {
|
||||
request.setHeader(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
||||
|
||||
private BiPredicate<String, String>[] forbidURIPredicates; //禁用的URL的Predicate, 必须与 forbidURIMaps 保持一致
|
||||
|
||||
private HttpServlet lastRunServlet;
|
||||
|
||||
private List<HttpServlet> removeHttpServlet(final Predicate<MappingEntry> predicateEntry, final Predicate<Map.Entry<String, WebSocketServlet>> predicateFilter) {
|
||||
List<HttpServlet> servlets = new ArrayList<>();
|
||||
synchronized (allMapStrings) {
|
||||
@@ -91,6 +93,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
||||
allMapStrings.remove(key);
|
||||
}
|
||||
}
|
||||
this.lastRunServlet = null;
|
||||
}
|
||||
return servlets;
|
||||
}
|
||||
@@ -365,7 +368,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
||||
} else if (mappingpath != null && !mappingpath.isEmpty()) {
|
||||
if (servlet._actionmap != null && servlet._actionmap.containsKey(mappingpath)) {
|
||||
//context.addRequestURINode(mappingpath);
|
||||
putMapping(mappingpath, new HttpServlet.HttpActionServlet(servlet._actionmap.get(mappingpath), servlet));
|
||||
putMapping(mappingpath, new HttpServlet.HttpActionServlet(servlet._actionmap.get(mappingpath), servlet, mappingpath));
|
||||
} else {
|
||||
putMapping(mappingpath, servlet);
|
||||
}
|
||||
@@ -434,6 +437,22 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
||||
return predicate == null ? servletStream() : servletStream().filter(predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpServlet mappingServlet(String key) {
|
||||
HttpServlet last = this.lastRunServlet;
|
||||
if (last != null && last._actionSimpleMappingUrl != null && last._actionSimpleMappingUrl.equalsIgnoreCase(key)) {
|
||||
return last;
|
||||
}
|
||||
HttpServlet s = super.mappingServlet(key);
|
||||
this.lastRunServlet = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAfterRemove(HttpServlet servlet) {
|
||||
this.lastRunServlet = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(HttpContext context, AnyValue config) {
|
||||
super.destroy(context, config); //必须要执行
|
||||
|
||||
@@ -840,6 +840,32 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
}
|
||||
}
|
||||
|
||||
protected HttpRequest setMethod(String method) {
|
||||
this.method = method;
|
||||
this.getmethod = "GET".equalsIgnoreCase(method);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected HttpRequest setRequestURI(String requestURI) {
|
||||
this.requestURI = requestURI;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected HttpRequest setRemoteAddr(String remoteAddr) {
|
||||
this.remoteAddr = remoteAddr;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected HttpRequest setParameter(String name, String value) {
|
||||
this.params.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected HttpRequest setHeader(String name, String value) {
|
||||
this.headers.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected static String toDecodeString(ByteArray array, int offset, int len, final Charset charset) {
|
||||
byte[] content = array.content();
|
||||
int start = offset;
|
||||
@@ -2471,14 +2497,14 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取翻页对象 同 getFlipper("flipper", needcreate, 0);
|
||||
* 获取翻页对象 同 getFlipper("flipper", autoCreate, 0);
|
||||
*
|
||||
* @param needcreate 无参数时是否创建新Flipper对象
|
||||
* @param autoCreate 无参数时是否创建新Flipper对象
|
||||
*
|
||||
* @return Flipper翻页对象
|
||||
*/
|
||||
public org.redkale.source.Flipper getFlipper(boolean needcreate) {
|
||||
return getFlipper(needcreate, 0);
|
||||
public org.redkale.source.Flipper getFlipper(boolean autoCreate) {
|
||||
return getFlipper(autoCreate, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2493,44 +2519,46 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit)
|
||||
* 获取翻页对象 同 getFlipper("flipper", autoCreate, maxLimit)
|
||||
*
|
||||
* @param needcreate 无参数时是否创建新Flipper对象
|
||||
* @param autoCreate 无参数时是否创建新Flipper对象
|
||||
* @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT
|
||||
*
|
||||
* @return Flipper翻页对象
|
||||
*/
|
||||
public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit) {
|
||||
return getFlipper("flipper", needcreate, maxLimit);
|
||||
public org.redkale.source.Flipper getFlipper(boolean autoCreate, int maxLimit) {
|
||||
return getFlipper("flipper", autoCreate, maxLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取翻页对象 https://redkale.org/pipes/users/list/offset:0/limit:20/sort:createtime%20ASC <br>
|
||||
* https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'} <br>
|
||||
* 以上两种接口都可以获取到翻页对象
|
||||
* 获取翻页对象 https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'} <br>
|
||||
*
|
||||
*
|
||||
* @param name Flipper对象的参数名,默认为 "flipper"
|
||||
* @param needcreate 无参数时是否创建新Flipper对象
|
||||
* @param autoCreate 无参数时是否创建新Flipper对象
|
||||
* @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT
|
||||
*
|
||||
* @return Flipper翻页对象
|
||||
*/
|
||||
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) {
|
||||
public org.redkale.source.Flipper getFlipper(String name, boolean autoCreate, int maxLimit) {
|
||||
org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name);
|
||||
if (flipper == null) {
|
||||
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
|
||||
int limit = getRequstURIPath("limit:", 0);
|
||||
int offset = getRequstURIPath("offset:", 0);
|
||||
String sort = getRequstURIPath("sort:", "");
|
||||
if (limit > 0) {
|
||||
if (limit > maxLimit) limit = maxLimit;
|
||||
flipper = new org.redkale.source.Flipper(limit, offset, sort);
|
||||
}
|
||||
// if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
|
||||
// String limitstr = getParameter("limit");
|
||||
// if (limitstr != null && !limitstr.isEmpty()) {
|
||||
// String offsetstr = getParameter("offset");
|
||||
// if (offsetstr != null && !offsetstr.isEmpty()) {
|
||||
// int limit = Integer.parseInt(limitstr);
|
||||
// int offset = Integer.parseInt(offsetstr);
|
||||
// String sort = getParameter("sort");
|
||||
// if (limit > maxLimit) limit = maxLimit;
|
||||
// flipper = new org.redkale.source.Flipper(limit, offset, sort);
|
||||
// }
|
||||
// }
|
||||
} else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) {
|
||||
flipper.setLimit(maxLimit);
|
||||
}
|
||||
if (flipper != null || !needcreate) return flipper;
|
||||
if (flipper != null || !autoCreate) return flipper;
|
||||
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
|
||||
return new org.redkale.source.Flipper(maxLimit);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
|
||||
|
||||
public static final int RET_METHOD_ERROR = 1200_0002;
|
||||
|
||||
String _actionSimpleMappingUrl; //只给HttpActionServlet使用,_actionSimpleMappingUrl不能包含正则表达式,比如 /json /createRecord, 不能是 /user/**
|
||||
|
||||
String _prefix = ""; //当前HttpServlet的path前缀
|
||||
|
||||
String _reqtopic; //根据RestService+MQ生成的值 @since 2.5.0
|
||||
@@ -454,9 +456,12 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
|
||||
|
||||
final HttpServlet servlet;
|
||||
|
||||
public HttpActionServlet(ActionEntry actionEntry, HttpServlet servlet) {
|
||||
public HttpActionServlet(ActionEntry actionEntry, HttpServlet servlet, String actionSimpleMappingUrl) {
|
||||
this.action = actionEntry;
|
||||
this.servlet = servlet;
|
||||
if (actionSimpleMappingUrl != null && !Utility.contains(actionSimpleMappingUrl, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) {
|
||||
this._actionSimpleMappingUrl = actionSimpleMappingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
*/
|
||||
package org.redkale.test.convert;
|
||||
|
||||
import java.util.*;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.convert.json.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class MapIgnoreColumnTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
MapIgnoreColumnTest test = new MapIgnoreColumnTest();
|
||||
test.main = true;
|
||||
test.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("aaa", "123");
|
||||
map.put("bbb", List.of(1, 2));
|
||||
System.out.println(JsonConvert.root().convertTo(map));
|
||||
JsonFactory factory = JsonFactory.create();
|
||||
factory.register(Map.class, true, "aaa");
|
||||
JsonConvert convert = factory.getConvert();
|
||||
String rs = "{\"bbb\":[1,2]}";
|
||||
if (!main) Assertions.assertEquals(rs, convert.convertTo(map));
|
||||
System.out.println(convert.convertTo(map));
|
||||
JsonConvert convert2 = JsonConvert.root().newConvert((k, v) -> {
|
||||
if ("bbb".equals(k)) return null;
|
||||
return v;
|
||||
}, null, null);
|
||||
if (!main) Assertions.assertEquals("{\"aaa\":\"123\",\"bbb\":null}", convert2.convertTo(map));
|
||||
System.out.println(convert2.convertTo(map));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user