重构HttpServlet

This commit is contained in:
Redkale
2017-05-12 13:42:10 +08:00
parent 681faa415f
commit 4feea0e784
22 changed files with 891 additions and 106 deletions

View File

@@ -11,7 +11,7 @@ import java.util.*;
import javax.persistence.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.Service;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
@@ -24,7 +24,9 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
public class ApiDocsService extends DefaultRestServlet implements Service {
@AutoLoad(false)
@LocalService
public final class ApiDocsService extends AbstractService {
private final Application app; //Application全局对象
@@ -34,7 +36,8 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
public void run() throws Exception {
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("__prefix");
__prefix.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue;
@@ -52,7 +55,7 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
continue;
}
final Map<String, Object> servletmap = new LinkedHashMap<>();
String prefix = _prefix(servlet);
String prefix = (String) __prefix.get(servlet);
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < urlregs.length; i++) {
@@ -73,7 +76,7 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
WebMapping action = method.getAnnotation(WebMapping.class);
HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final Map<String, Object> mappingmap = new LinkedHashMap<>();
@@ -123,7 +126,7 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
typesmap.put(rtype.getName(), typemap);
}
mappingmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();

View File

@@ -158,10 +158,22 @@ public abstract class Response<C extends Context, R extends Request<C>> {
}
}
/**
* 使用 public void recycleListener(BiConsumer recycleListener) 代替
*
* @param recycleListener BiConsumer
*
* @deprecated
*/
@Deprecated
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
this.recycleListener = recycleListener;
}
public void recycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
this.recycleListener = recycleListener;
}
public Object getOutput() {
return output;
}

View File

@@ -21,9 +21,4 @@ public class DefaultRestServlet extends RestHttpServlet<Object> {
return new Object();
}
@Override
public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
next.execute(request, response);
}
}

View File

@@ -22,31 +22,31 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.service.RetResult;
/**
* 直接只用HttpServlet代替, 将在1.9版本移除
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Deprecated
public abstract class HttpBaseServlet extends HttpServlet {
public static final int RET_SERVER_ERROR = 1800_0001;
public static final int RET_METHOD_ERROR = 1800_0002;
/**
* 配合 HttpBaseServlet 使用。
* 当标记为 &#64;AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
* 使用 org.redkale.util.AuthIgnore 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, TYPE})
@Retention(RUNTIME)
@Deprecated
protected @interface AuthIgnore {
}
@@ -66,18 +66,20 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 &#64;WebMapping 使用。
* 用于对&#64;WebMapping方法中参数描述
*
* 使用 org.redkale.net.http.HttpParam 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(WebParams.class)
@Deprecated
protected @interface WebParam {
String name(); //参数名
@@ -102,16 +104,17 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 使用 WebMapping 替代。
* 使用 org.redkale.net.http.HttpMapping 替代。
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Deprecated
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface WebAction {
int actionid() default 0;
@@ -130,17 +133,18 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 HttpBaseServlet 使用
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
* 使用 org.redkale.net.http.HttpMapping 替代
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface WebMapping {
int actionid() default 0;
@@ -159,18 +163,15 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 HttpBaseServlet 使用
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
*
* <p>
* 详情见: https://redkale.org
* 使用 org.redkale.net.http.HttpCacheable 替代
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface HttpCacheable {
/**
@@ -215,8 +216,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
response.nextEvent(authSuccessServlet);
authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
HttpBaseServlet.this.authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
}
return;
}
@@ -225,43 +225,29 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
};
/**
* 使用 public void preExecute(HttpRequest request, HttpResponse response) throws IOException 代替
*
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @deprecated
*
* @throws IOException IOException
*/
@Deprecated
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
}
/**
* <p>
* 预执行方法在execute方法之前运行通常用于常规统计或基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
* public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
* if (finer) response.setRecycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* response.nextEvent();
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public void preExecute(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent();
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
next.execute(request, response);
}
/**
@@ -313,10 +299,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
@Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent(preSuccessServlet);
preExecute(request, response);
//兼容以前
//preExecute(request, response, preSuccessServlet);
preExecute(request, response, preSuccessServlet);
}
public final void preInit(HttpContext context, AnyValue config) {

View File

@@ -0,0 +1,33 @@
/*
* 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.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 HttpServlet 使用。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface HttpCacheable {
/**
* 超时的秒数
*
* @return 超时秒数
*/
int seconds() default 15;
}

View File

@@ -11,6 +11,8 @@ import java.nio.charset.*;
import java.security.*;
import java.util.concurrent.*;
import java.util.logging.*;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.net.*;
import org.redkale.util.*;
import org.redkale.watch.*;
@@ -27,6 +29,8 @@ public class HttpContext extends Context {
protected final SecureRandom random = new SecureRandom();
protected final ConcurrentHashMap<Class, Creator> asyncHandlerCreators = new ConcurrentHashMap<>();
public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
@@ -54,4 +58,113 @@ public class HttpContext extends Context {
return responsePool;
}
protected <H extends AsyncHandler> Creator<H> loadAsyncHandlerCreator(Class<H> handlerClass) {
Creator<H> creator = asyncHandlerCreators.get(handlerClass);
if (creator == null) {
creator = createAsyncHandlerCreator(handlerClass);
asyncHandlerCreators.put(handlerClass, creator);
}
return creator;
}
private <H extends AsyncHandler> Creator<H> createAsyncHandlerCreator(Class<H> handlerClass) {
//生成规则与SncpAsyncHandler.Factory 很类似
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String handlerName = AsyncHandler.class.getName().replace('.', '/');
final String handlerDesc = Type.getDescriptor(AsyncHandler.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + handlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "handler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<AsyncHandler> newHandlerClazz = (Class<AsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return (Creator<H>) Creator.create(newHandlerClazz);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 HttpServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface HttpMapping {
int actionid() default 0;
String url();
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}

View File

@@ -0,0 +1,61 @@
/*
* 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.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 &#64;HttpMapping 使用。
* 用于对&#64;HttpMapping方法中参数描述
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(HttpParam.HttpParams.class)
public @interface HttpParam {
String name(); //参数名
Class type(); //参数的数据类型
String comment() default ""; //备注描述
HttpParamSourceType src() default HttpParamSourceType.PARAMETER; //参数来源类型
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
/**
* 配合 &#64;WebParam 使用。
* 用于对&#64;WebParam中参数的来源类型
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public static enum HttpParamSourceType {
PARAMETER, HEADER, COOKIE;
}
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@interface HttpParams {
HttpParam[] value();
}
}

View File

@@ -43,11 +43,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
public void init(HttpContext context, AnyValue config) {
Collection<HttpServlet> servlets = getServlets();
servlets.forEach(s -> {
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).preInit(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) {
((HttpBaseServlet) s).preInit(context, getServletConf(s));
}
s.preInit(context, getServletConf(s));
s.init(context, getServletConf(s));
});
final WatchFactory watch = context.getWatchFactory();
@@ -213,11 +209,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
this.resourceHttpServlet.destroy(context, config);
getServlets().forEach(s -> {
s.destroy(context, getServletConf(s));
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).postDestroy(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) {
((HttpBaseServlet) s).postDestroy(context, getServletConf(s));
}
s.postDestroy(context, getServletConf(s));
});
this.allMapStrings.clear();
this.wsmappings.clear();

View File

@@ -64,6 +64,10 @@ public class HttpRequest extends Request<HttpContext> {
protected boolean boundary = false;
protected int moduleid;
protected int actionid;
private final String remoteAddrHeader;
Object attachment; //供 HttpBaseServlet传递Entry使用
@@ -236,6 +240,24 @@ public class HttpRequest extends Request<HttpContext> {
return super.removeProperty(name);
}
/**
* 获取模块ID来自&#64;HttpServlet.moduleid()
*
* @return 模块ID
*/
public int getModuleid() {
return this.moduleid;
}
/**
* 获取操作ID来自&#64;HttpMapping.actionid()
*
* @return 模块ID
*/
public int getActionid() {
return this.actionid;
}
/**
* 获取客户端地址IP
*
@@ -350,6 +372,8 @@ public class HttpRequest extends Request<HttpContext> {
this.contentLength = -1;
this.boundary = false;
this.bodyparsed = false;
this.moduleid = 0;
this.actionid = 0;
this.attachment = null;

View File

@@ -213,7 +213,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
}
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出
* 创建AsyncHandler实例
*
* @return AsyncHandler
*/
@@ -232,6 +232,21 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
});
}
/**
* 创建AsyncHandler子类的实例 <br>
*
* 传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
*
* @param <H> 泛型
* @param handlerClass AsyncHandler子类
*
* @return AsyncHandler AsyncHandler
*/
public <H extends AsyncHandler> H createAsyncHandler(Class<H> handlerClass) {
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) createAsyncHandler();
return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler());
}
/**
* 将对象以JSON格式输出
*
@@ -354,6 +369,44 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
});
}
/**
* 将HttpResult的结果对象以JSON格式输出
*
* @param result HttpResult对象
*/
public void finishJson(final HttpResult result) {
finishJson(request.getJsonConvert(), result);
}
/**
* 将HttpResult的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param result HttpResult对象
*/
public void finishJson(final JsonConvert convert, final HttpResult result) {
if (output == null) {
finish("");
return;
}
if (result.getContentType() != null) setContentType(result.getContentType());
addHeader(result.getHeaders()).addCookie(result.getCookies()).setStatus(result.getStatus() < 1 ? 200 : result.getStatus());
if (result.getResult() instanceof File) {
try {
finish((File) result.getResult());
} catch (IOException e) {
getContext().getLogger().log(Level.WARNING, "HttpServlet finishJson HttpResult File occur, forece to close channel. request = " + getRequest(), e);
finish(500, null);
}
} else if (result.getResult() instanceof String) {
finish((String) result.getResult());
} else if (result.getResult() == null) {
finish(result.getMessage());
} else {
finishJson(result.getResult());
}
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*

View File

@@ -0,0 +1,103 @@
/*
* 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.net.http;
import java.io.Serializable;
import java.net.HttpCookie;
import java.util.*;
/**
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 结果对象的类型
*/
public class HttpResult<T> {
public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME;
private Map<String, String> headers;
private List<HttpCookie> cookies;
private String contentType;
private T result;
private int status = 0; //不设置则为 200
private String message;
public HttpResult() {
}
public HttpResult(T result) {
this.result = result;
}
public HttpResult<T> addHeader(String name, Serializable value) {
if (this.headers == null) this.headers = new HashMap<>();
this.headers.put(name, String.valueOf(value));
return this;
}
public HttpResult<T> addCookie(HttpCookie cookie) {
if (this.cookies == null) this.cookies = new ArrayList<>();
this.cookies.add(cookie);
return this;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public List<HttpCookie> getCookies() {
return cookies;
}
public void setCookies(List<HttpCookie> cookies) {
this.cookies = cookies;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -5,9 +5,20 @@
*/
package org.redkale.net.http;
import org.redkale.net.Servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.net.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
/**
* HTTP版的Servlet 执行顺序 execute --> preExecute --> authenticate --> HttpMapping对应的方法
*
* <p>
* 详情见: https://redkale.org
@@ -16,6 +27,337 @@ import org.redkale.net.Servlet;
*/
public abstract class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse> {
public static final int RET_SERVER_ERROR = 1800_0001;
public static final int RET_METHOD_ERROR = 1800_0002;
String _prefix = ""; //当前HttpServlet的path前缀
private Map.Entry<String, Entry>[] mappings;
//这里不能直接使用HttpServlet会造成死循环初始化HttpServlet
private final Servlet<HttpContext, HttpRequest, HttpResponse> authSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.attachment;
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
};
//preExecute运行完后执行的Servlet
private final Servlet<HttpContext, HttpRequest, HttpResponse> preSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
request.attachment = entry;
request.moduleid = entry.moduleid;
request.actionid = entry.actionid;
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
response.nextEvent(authSuccessServlet);
authenticate(request, response);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
};
void preInit(HttpContext context, AnyValue config) {
String path = _prefix == null ? "" : _prefix;
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load();
this.mappings = new Map.Entry[map.size()];
int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) {
mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
}
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
}
void postDestroy(HttpContext context, AnyValue config) {
}
/**
* <p>
* 预执行方法在execute方法之前运行通常用于常规统计或基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
* if (finer) response.recycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* response.nextEvent();
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
*
* @throws IOException IOException
*/
protected void preExecute(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent();
}
/**
* <p>
* 用户登录或权限验证, 没有注解为&#64;AuthIgnore 的方法会执行authenticate方法, 若验证成功则必须调用response.nextEvent();进行下一步操作, 例如: <br>
* <blockquote><pre>
* &#64;Override
* public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
* UserInfo info = currentUser(request);
* if (info == null) {
* response.finishJson(RET_UNLOGIN);
* return;
* } else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
* response.finishJson(RET_AUTHILLEGAL);
* return;
* }
* response.nextEvent();
* }
* </pre></blockquote>
* <p>
*
*
* @param request HttpRequest
* @param response HttpResponse
*
* @throws IOException IOException
*/
protected void authenticate(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent();
}
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent(preSuccessServlet);
preExecute(request, response);
}
private HashMap<String, Entry> load() {
final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null;
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>();
HashMap<String, Class> nameset = new HashMap<>();
final Class selfClz = this.getClass();
Class clz = this.getClass();
do {
if (java.lang.reflect.Modifier.isAbstract(clz.getModifiers())) break;
for (final Method method : clz.getMethods()) {
//-----------------------------------------------
String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//-----------------------------------------------
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|| paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final HttpMapping mapping = method.getAnnotation(HttpMapping.class);
if (mapping == null) continue;
final boolean inherited = mapping.inherited();
if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = mapping.actionid();
final String name = mapping.url().trim();
final String[] methods = mapping.methods();
if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
return map;
}
private HttpServlet createHttpServlet(final Method method) {
//------------------------------------------------------------------------------
final String supDynName = HttpServlet.class.getName().replace('.', '/');
final String interName = this.getClass().getName().replace('.', '/');
final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass());
final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class);
final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class);
final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class);
final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class);
String newDynName = interName + "_Dyn_" + method.getName();
int i = 0;
for (;;) {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i);
} catch (Throwable ex) {
break;
}
}
//------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
final String factfield = "_factServlet";
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{
fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null);
fv.visitEnd();
}
{ //构造函数
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"}));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"});
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/'));
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/'));
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
cw.visitEnd();
//------------------------------------------------------------------------------
byte[] bytes = cw.toByteArray();
Class<?> newClazz = new ClassLoader(this.getClass().getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
try {
HttpServlet instance = (HttpServlet) newClazz.newInstance();
instance.getClass().getField(factfield).set(instance, this);
return instance;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static final class Entry {
public Entry(boolean typeIgnore, int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
this.moduleid = moduleid;
this.actionid = actionid;
this.name = name;
this.methods = methods;
this.method = method;
this.servlet = servlet;
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
this.cacheseconds = hc == null ? 0 : hc.seconds() * 1000;
this.cache = cacheseconds > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
cache.put(response.getRequest().getRequestURI(), ce);
return ce.getBuffers();
} : null;
}
public boolean isNeedCheck() {
return this.moduleid != 0 || this.actionid != 0;
}
public boolean checkMethod(final String reqMethod) {
if (methods.length == 0) return true;
for (String m : methods) {
if (reqMethod.equalsIgnoreCase(m)) return true;
}
return false;
}
public final HttpResponse.BufferHandler cacheHandler;
public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cacheseconds;
public final boolean ignore;
public final int moduleid;
public final int actionid;
public final String name;
public final String[] methods;
public final Method method;
public final HttpServlet servlet;
}
private static final class CacheEntry {
public final long time = System.currentTimeMillis();
private final ByteBuffer[] buffers;
private final int status;
private final String contentType;
public CacheEntry(int status, String contentType, ByteBuffer[] bufs) {
this.status = status;
this.contentType = contentType;
final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer();
}
this.buffers = newBuffers;
}
public ByteBuffer[] getBuffers() {
final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = buffers[i].duplicate();
}
return newBuffers;
}
}
}

View File

@@ -122,12 +122,12 @@ public final class Rest {
final String flipperDesc = Type.getDescriptor(Flipper.class);
final String restoutputDesc = Type.getDescriptor(RestOutput.class);
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class);
final String mappingDesc = Type.getDescriptor(HttpBaseServlet.WebMapping.class);
final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class);
final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class);
final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class);
final String authDesc = Type.getDescriptor(AuthIgnore.class);
final String cacheDesc = Type.getDescriptor(HttpCacheable.class);
final String mappingDesc = Type.getDescriptor(HttpMapping.class);
final String webparamDesc = Type.getDescriptor(HttpParam.class);
final String webparamsDesc = Type.getDescriptor(HttpParam.HttpParams.class);
final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParamSourceType.class);
final String reqInternalName = Type.getInternalName(HttpRequest.class);
final String respInternalName = Type.getInternalName(HttpResponse.class);
@@ -218,7 +218,7 @@ public final class Rest {
final List<MappingEntry> entrys = new ArrayList<>();
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
//获取所有可以转换成WebMapping的方法
//获取所有可以转换成HttpMapping的方法
int methodidex = 0;
final List<java.lang.reflect.Type[]> paramtypes = new ArrayList<>();
for (final Method method : serviceType.getMethods()) {
@@ -254,9 +254,9 @@ public final class Rest {
}
methodidex++;
}
if (entrys.isEmpty()) return null; //没有可WebMapping的方法
if (entrys.isEmpty()) return null; //没有可HttpMapping的方法
//将每个Service可转换的方法生成HttpServlet对应的WebMapping方法
//将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(serviceType);
for (final MappingEntry entry : entrys) {
final Method method = entry.mappingMethod;
@@ -380,7 +380,7 @@ public final class Rest {
Map<String, Object> mappingMap = new LinkedHashMap<>();
{ // 设置 Annotation
//设置 WebMapping
//设置 HttpMapping
boolean reqpath = false;
for (Object[] ps : paramlist) {
if ("#".equals((String) ps[1])) {
@@ -425,8 +425,8 @@ public final class Rest {
av2.visit("name", (String) ps[1]);
av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2])));
av2.visit("radix", (Integer) ps[3]);
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name()
: (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name()));
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpParam.HttpParamSourceType.HEADER.name()
: (iscookie ? HttpParam.HttpParamSourceType.COOKIE.name() : HttpParam.HttpParamSourceType.PARAMETER.name()));
av2.visit("comment", (String) ps[4]);
av2.visit("required", (Boolean) ps[5]);
av2.visitEnd();

View File

@@ -19,7 +19,7 @@ import org.redkale.util.*;
* @author zhangjx
* @param <T> 当前用户对象类型
*/
public abstract class RestHttpServlet<T> extends HttpBaseServlet {
public abstract class RestHttpServlet<T> extends HttpServlet {
protected abstract T currentUser(HttpRequest req) throws IOException;

View File

@@ -40,7 +40,7 @@ public @interface RestMapping {
String name() default "";
/**
* 备注描述, 对应&#64;WebMapping.comment
* 备注描述, 对应&#64;HttpMapping.comment
*
* @return String
*/
@@ -54,7 +54,7 @@ public @interface RestMapping {
boolean auth() default false;
/**
* 操作ID值鉴权时用到, 对应&#64;WebMapping.actionid
* 操作ID值鉴权时用到, 对应&#64;HttpMapping.actionid
*
* @return int
*/
@@ -68,7 +68,7 @@ public @interface RestMapping {
int cacheseconds() default 0;
/**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebMapping.methods
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;HttpMapping.methods
*
* @return String[]
*/

View File

@@ -10,13 +10,16 @@ import java.net.HttpCookie;
import java.util.*;
/**
* 使用 HttpResult 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
* @param <T> 结果对象的类型
*/
@Deprecated
public class RestOutput<T> {
private Map<String, String> headers;

View File

@@ -71,7 +71,8 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
protected WebSocketEngine engine;
public final void preInit(HttpContext context, AnyValue conf) {
@Override
final void preInit(HttpContext context, AnyValue conf) {
InetSocketAddress addr = context.getServerAddress();
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", this.node, logger);
if (this.node == null) this.node = createWebSocketNode();
@@ -84,7 +85,8 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
this.engine.init(conf);
}
public final void postDestroy(HttpContext context, AnyValue conf) {
@Override
final void postDestroy(HttpContext context, AnyValue conf) {
this.node.postDestroy(conf);
super.destroy(context, conf);
engine.close();

View File

@@ -0,0 +1,27 @@
/*
* 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.util;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 HttpServlet 使用。
* 当标记为 &#64;AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface AuthIgnore {
}

View File

@@ -25,16 +25,16 @@ public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
//普通鉴权
@Override
public void authenticate(int module, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
UserInfo info = currentUser(request);
if (info == null) {
response.finishJson(RET_UNLOGIN);
return;
} else if (!info.checkAuth(module, actionid)) {
} else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
response.finishJson(RET_AUTHILLEGAL);
return;
}
next.execute(request, response);
response.nextEvent();
}
}

View File

@@ -48,7 +48,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/create")
@HttpMapping(url = "/hello/create")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -60,7 +60,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/delete/")
@HttpMapping(url = "/hello/delete/")
public void delete(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());
@@ -69,7 +69,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/update")
@HttpMapping(url = "/hello/update")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
String clientaddr = req.getRemoteAddr();
@@ -81,7 +81,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/partupdate")
@HttpMapping(url = "/hello/partupdate")
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -93,7 +93,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/query")
@HttpMapping(url = "/hello/query")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
@@ -107,7 +107,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/list")
@HttpMapping(url = "/hello/list")
public void list(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
@@ -120,7 +120,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/find/")
@HttpMapping(url = "/hello/find/")
public void find(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());
@@ -129,7 +129,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/asyncfind/")
@HttpMapping(url = "/hello/asyncfind/")
public void asyncfind(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());

View File

@@ -11,7 +11,7 @@ import javax.annotation.Resource;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.source.Flipper;
import org.redkale.util.Sheet;
import org.redkale.util.*;
/**
*
@@ -27,8 +27,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
private Map<String, HelloService2> _servicemap;
@AuthIgnore
@WebMapping(url = "/hello/create", comment = "创建Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
@HttpMapping(url = "/hello/create", comment = "创建Hello对象")
@HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -42,8 +42,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/delete/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
@HttpMapping(url = "/hello/delete/", comment = "根据id删除Hello对象")
@HttpParam(name = "#", type = int.class, comment = "Hello对象id")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
@@ -52,8 +52,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/update", comment = "修改Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
@HttpMapping(url = "/hello/update", comment = "修改Hello对象")
@HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -66,8 +66,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/query", comment = "查询Hello对象列表")
@WebParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
@HttpMapping(url = "/hello/query", comment = "查询Hello对象列表")
@HttpParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
@@ -81,8 +81,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebMapping(url = "/hello/find/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
@HttpMapping(url = "/hello/find/", comment = "根据id删除Hello对象")
@HttpParam(name = "#", type = int.class, comment = "Hello对象id")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());