重构HttpServlet
This commit is contained in:
@@ -11,7 +11,7 @@ import java.util.*;
|
|||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.*;
|
||||||
import org.redkale.source.*;
|
import org.redkale.source.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
@@ -24,7 +24,9 @@ import org.redkale.util.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class ApiDocsService extends DefaultRestServlet implements Service {
|
@AutoLoad(false)
|
||||||
|
@LocalService
|
||||||
|
public final class ApiDocsService extends AbstractService {
|
||||||
|
|
||||||
private final Application app; //Application全局对象
|
private final Application app; //Application全局对象
|
||||||
|
|
||||||
@@ -34,7 +36,8 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
|
|||||||
|
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
List<Map> serverList = new ArrayList<>();
|
List<Map> serverList = new ArrayList<>();
|
||||||
|
Field __prefix = HttpServlet.class.getDeclaredField("__prefix");
|
||||||
|
__prefix.setAccessible(true);
|
||||||
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
|
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
|
||||||
for (NodeServer node : app.servers) {
|
for (NodeServer node : app.servers) {
|
||||||
if (!(node instanceof NodeHttpServer)) continue;
|
if (!(node instanceof NodeHttpServer)) continue;
|
||||||
@@ -52,7 +55,7 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final Map<String, Object> servletmap = new LinkedHashMap<>();
|
final Map<String, Object> servletmap = new LinkedHashMap<>();
|
||||||
String prefix = _prefix(servlet);
|
String prefix = (String) __prefix.get(servlet);
|
||||||
String[] urlregs = ws.value();
|
String[] urlregs = ws.value();
|
||||||
if (prefix != null && !prefix.isEmpty()) {
|
if (prefix != null && !prefix.isEmpty()) {
|
||||||
for (int i = 0; i < urlregs.length; i++) {
|
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;
|
if (Modifier.isAbstract(clz.getModifiers())) break;
|
||||||
for (Method method : clz.getMethods()) {
|
for (Method method : clz.getMethods()) {
|
||||||
if (method.getParameterCount() != 2) continue;
|
if (method.getParameterCount() != 2) continue;
|
||||||
WebMapping action = method.getAnnotation(WebMapping.class);
|
HttpMapping action = method.getAnnotation(HttpMapping.class);
|
||||||
if (action == null) continue;
|
if (action == null) continue;
|
||||||
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
||||||
final Map<String, Object> mappingmap = new LinkedHashMap<>();
|
final Map<String, Object> mappingmap = new LinkedHashMap<>();
|
||||||
@@ -123,7 +126,7 @@ public class ApiDocsService extends DefaultRestServlet implements Service {
|
|||||||
typesmap.put(rtype.getName(), typemap);
|
typesmap.put(rtype.getName(), typemap);
|
||||||
}
|
}
|
||||||
mappingmap.put("results", results);
|
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 Map<String, Object> parammap = new LinkedHashMap<>();
|
||||||
final boolean isarray = param.type().isArray();
|
final boolean isarray = param.type().isArray();
|
||||||
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
||||||
|
|||||||
@@ -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) {
|
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
|
||||||
this.recycleListener = recycleListener;
|
this.recycleListener = recycleListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void recycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
|
||||||
|
this.recycleListener = recycleListener;
|
||||||
|
}
|
||||||
|
|
||||||
public Object getOutput() {
|
public Object getOutput() {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,4 @@ public class DefaultRestServlet extends RestHttpServlet<Object> {
|
|||||||
return new Object();
|
return new Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
|
|
||||||
next.execute(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,31 +22,31 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
import org.redkale.service.RetResult;
|
import org.redkale.service.RetResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 直接只用HttpServlet代替, 将在1.9版本移除
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract class HttpBaseServlet extends HttpServlet {
|
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 使用。
|
* 使用 org.redkale.util.AuthIgnore 代替
|
||||||
* 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Inherited
|
@Inherited
|
||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD, TYPE})
|
@Target({METHOD, TYPE})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Deprecated
|
||||||
protected @interface AuthIgnore {
|
protected @interface AuthIgnore {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -66,18 +66,20 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配合 @WebMapping 使用。
|
*
|
||||||
* 用于对@WebMapping方法中参数描述
|
* 使用 org.redkale.net.http.HttpParam 代替
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD})
|
@Target({METHOD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Repeatable(WebParams.class)
|
@Repeatable(WebParams.class)
|
||||||
|
@Deprecated
|
||||||
protected @interface WebParam {
|
protected @interface WebParam {
|
||||||
|
|
||||||
String name(); //参数名
|
String name(); //参数名
|
||||||
@@ -102,16 +104,17 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用 WebMapping 替代。
|
* 使用 org.redkale.net.http.HttpMapping 替代。
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD})
|
@Target({METHOD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Deprecated
|
||||||
protected @interface WebAction {
|
protected @interface WebAction {
|
||||||
|
|
||||||
int actionid() default 0;
|
int actionid() default 0;
|
||||||
@@ -130,17 +133,18 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配合 HttpBaseServlet 使用。
|
* 使用 org.redkale.net.http.HttpMapping 替代。
|
||||||
* 用于对@WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀, 且不能是正则表达式
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD})
|
@Target({METHOD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Deprecated
|
||||||
protected @interface WebMapping {
|
protected @interface WebMapping {
|
||||||
|
|
||||||
int actionid() default 0;
|
int actionid() default 0;
|
||||||
@@ -159,18 +163,15 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配合 HttpBaseServlet 使用。
|
* 使用 org.redkale.net.http.HttpCacheable 替代。
|
||||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
|
|
||||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD})
|
@Target({METHOD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Deprecated
|
||||||
protected @interface HttpCacheable {
|
protected @interface HttpCacheable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,8 +216,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
if (entry.ignore) {
|
if (entry.ignore) {
|
||||||
authSuccessServlet.execute(request, response);
|
authSuccessServlet.execute(request, response);
|
||||||
} else {
|
} else {
|
||||||
response.nextEvent(authSuccessServlet);
|
HttpBaseServlet.this.authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
|
||||||
authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
|
|
||||||
}
|
}
|
||||||
return;
|
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>
|
* <p>
|
||||||
* 预执行方法,在execute方法之前运行,通常用于常规统计或基础检测,例如 : <br>
|
* 预执行方法,在execute方法之前运行,通常用于常规统计或基础检测,例如 : <br>
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* @Override
|
* @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) -> { //记录处理时间比较长的请求
|
* if (finer) response.setRecycleListener((req, resp) -> { //记录处理时间比较长的请求
|
||||||
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
|
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
|
||||||
* if (e > 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
|
* if (e > 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
|
||||||
* });
|
* });
|
||||||
* response.nextEvent();
|
* next.execute(request, response);
|
||||||
* }
|
* }
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @param request HttpRequest
|
* @param request HttpRequest
|
||||||
* @param response HttpResponse
|
* @param response HttpResponse
|
||||||
|
* @param next HttpServlet
|
||||||
*
|
*
|
||||||
* @throws IOException IOException
|
* @throws IOException IOException
|
||||||
*/
|
*/
|
||||||
public void preExecute(HttpRequest request, HttpResponse response) throws IOException {
|
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
|
||||||
response.nextEvent();
|
next.execute(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -313,10 +299,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
|
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
|
||||||
response.nextEvent(preSuccessServlet);
|
preExecute(request, response, preSuccessServlet);
|
||||||
preExecute(request, response);
|
|
||||||
//兼容以前
|
|
||||||
//preExecute(request, response, preSuccessServlet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void preInit(HttpContext context, AnyValue config) {
|
public final void preInit(HttpContext context, AnyValue config) {
|
||||||
|
|||||||
33
src/org/redkale/net/http/HttpCacheable.java
Normal file
33
src/org/redkale/net/http/HttpCacheable.java
Normal 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 使用。
|
||||||
|
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
|
||||||
|
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface HttpCacheable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超时的秒数
|
||||||
|
*
|
||||||
|
* @return 超时秒数
|
||||||
|
*/
|
||||||
|
int seconds() default 15;
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ import java.nio.charset.*;
|
|||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.logging.*;
|
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.net.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
import org.redkale.watch.*;
|
import org.redkale.watch.*;
|
||||||
@@ -27,6 +29,8 @@ public class HttpContext extends Context {
|
|||||||
|
|
||||||
protected final SecureRandom random = new SecureRandom();
|
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,
|
public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
|
||||||
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
|
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
|
||||||
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
|
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
|
||||||
@@ -54,4 +58,113 @@ public class HttpContext extends Context {
|
|||||||
return responsePool;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/org/redkale/net/http/HttpMapping.java
Normal file
39
src/org/redkale/net/http/HttpMapping.java
Normal 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 使用。
|
||||||
|
* 用于对@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 {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
|
||||||
|
}
|
||||||
61
src/org/redkale/net/http/HttpParam.java
Normal file
61
src/org/redkale/net/http/HttpParam.java
Normal 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配合 @HttpMapping 使用。
|
||||||
|
* 用于对@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; //参数是否必传
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配合 @WebParam 使用。
|
||||||
|
* 用于对@WebParam中参数的来源类型
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public static enum HttpParamSourceType {
|
||||||
|
|
||||||
|
PARAMETER, HEADER, COOKIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface HttpParams {
|
||||||
|
|
||||||
|
HttpParam[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -43,11 +43,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
public void init(HttpContext context, AnyValue config) {
|
public void init(HttpContext context, AnyValue config) {
|
||||||
Collection<HttpServlet> servlets = getServlets();
|
Collection<HttpServlet> servlets = getServlets();
|
||||||
servlets.forEach(s -> {
|
servlets.forEach(s -> {
|
||||||
if (s instanceof WebSocketServlet) {
|
s.preInit(context, getServletConf(s));
|
||||||
((WebSocketServlet) s).preInit(context, getServletConf(s));
|
|
||||||
} else if (s instanceof HttpBaseServlet) {
|
|
||||||
((HttpBaseServlet) s).preInit(context, getServletConf(s));
|
|
||||||
}
|
|
||||||
s.init(context, getServletConf(s));
|
s.init(context, getServletConf(s));
|
||||||
});
|
});
|
||||||
final WatchFactory watch = context.getWatchFactory();
|
final WatchFactory watch = context.getWatchFactory();
|
||||||
@@ -213,11 +209,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
this.resourceHttpServlet.destroy(context, config);
|
this.resourceHttpServlet.destroy(context, config);
|
||||||
getServlets().forEach(s -> {
|
getServlets().forEach(s -> {
|
||||||
s.destroy(context, getServletConf(s));
|
s.destroy(context, getServletConf(s));
|
||||||
if (s instanceof WebSocketServlet) {
|
s.postDestroy(context, getServletConf(s));
|
||||||
((WebSocketServlet) s).postDestroy(context, getServletConf(s));
|
|
||||||
} else if (s instanceof HttpBaseServlet) {
|
|
||||||
((HttpBaseServlet) s).postDestroy(context, getServletConf(s));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.allMapStrings.clear();
|
this.allMapStrings.clear();
|
||||||
this.wsmappings.clear();
|
this.wsmappings.clear();
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
|
|
||||||
protected boolean boundary = false;
|
protected boolean boundary = false;
|
||||||
|
|
||||||
|
protected int moduleid;
|
||||||
|
|
||||||
|
protected int actionid;
|
||||||
|
|
||||||
private final String remoteAddrHeader;
|
private final String remoteAddrHeader;
|
||||||
|
|
||||||
Object attachment; //供 HttpBaseServlet传递Entry使用
|
Object attachment; //供 HttpBaseServlet传递Entry使用
|
||||||
@@ -236,6 +240,24 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
return super.removeProperty(name);
|
return super.removeProperty(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模块ID,来自@HttpServlet.moduleid()
|
||||||
|
*
|
||||||
|
* @return 模块ID
|
||||||
|
*/
|
||||||
|
public int getModuleid() {
|
||||||
|
return this.moduleid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取操作ID,来自@HttpMapping.actionid()
|
||||||
|
*
|
||||||
|
* @return 模块ID
|
||||||
|
*/
|
||||||
|
public int getActionid() {
|
||||||
|
return this.actionid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客户端地址IP
|
* 获取客户端地址IP
|
||||||
*
|
*
|
||||||
@@ -350,6 +372,8 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
this.contentLength = -1;
|
this.contentLength = -1;
|
||||||
this.boundary = false;
|
this.boundary = false;
|
||||||
this.bodyparsed = false;
|
this.bodyparsed = false;
|
||||||
|
this.moduleid = 0;
|
||||||
|
this.actionid = 0;
|
||||||
|
|
||||||
this.attachment = null;
|
this.attachment = null;
|
||||||
|
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建AsyncHandler实例,将非字符串对象以JSON格式输出,字符串以文本输出
|
* 创建AsyncHandler实例
|
||||||
*
|
*
|
||||||
* @return 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格式输出
|
* 将对象以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格式输出
|
* 将CompletableFuture的结果对象以JSON格式输出
|
||||||
*
|
*
|
||||||
|
|||||||
103
src/org/redkale/net/http/HttpResult.java
Normal file
103
src/org/redkale/net/http/HttpResult.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,9 +5,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net.http;
|
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>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -16,6 +27,337 @@ import org.redkale.net.Servlet;
|
|||||||
*/
|
*/
|
||||||
public abstract class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse> {
|
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前缀
|
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>
|
||||||
|
* @Override
|
||||||
|
* public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
|
||||||
|
* if (finer) response.recycleListener((req, resp) -> { //记录处理时间比较长的请求
|
||||||
|
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
|
||||||
|
* if (e > 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>
|
||||||
|
* 用户登录或权限验证, 没有注解为@AuthIgnore 的方法会执行authenticate方法, 若验证成功则必须调用response.nextEvent();进行下一步操作, 例如: <br>
|
||||||
|
* <blockquote><pre>
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,12 +122,12 @@ public final class Rest {
|
|||||||
final String flipperDesc = Type.getDescriptor(Flipper.class);
|
final String flipperDesc = Type.getDescriptor(Flipper.class);
|
||||||
final String restoutputDesc = Type.getDescriptor(RestOutput.class);
|
final String restoutputDesc = Type.getDescriptor(RestOutput.class);
|
||||||
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
|
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
|
||||||
final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
|
final String authDesc = Type.getDescriptor(AuthIgnore.class);
|
||||||
final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class);
|
final String cacheDesc = Type.getDescriptor(HttpCacheable.class);
|
||||||
final String mappingDesc = Type.getDescriptor(HttpBaseServlet.WebMapping.class);
|
final String mappingDesc = Type.getDescriptor(HttpMapping.class);
|
||||||
final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class);
|
final String webparamDesc = Type.getDescriptor(HttpParam.class);
|
||||||
final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class);
|
final String webparamsDesc = Type.getDescriptor(HttpParam.HttpParams.class);
|
||||||
final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class);
|
final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParamSourceType.class);
|
||||||
|
|
||||||
final String reqInternalName = Type.getInternalName(HttpRequest.class);
|
final String reqInternalName = Type.getInternalName(HttpRequest.class);
|
||||||
final String respInternalName = Type.getInternalName(HttpResponse.class);
|
final String respInternalName = Type.getInternalName(HttpResponse.class);
|
||||||
@@ -218,7 +218,7 @@ public final class Rest {
|
|||||||
|
|
||||||
final List<MappingEntry> entrys = new ArrayList<>();
|
final List<MappingEntry> entrys = new ArrayList<>();
|
||||||
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
|
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
|
||||||
//获取所有可以转换成WebMapping的方法
|
//获取所有可以转换成HttpMapping的方法
|
||||||
int methodidex = 0;
|
int methodidex = 0;
|
||||||
final List<java.lang.reflect.Type[]> paramtypes = new ArrayList<>();
|
final List<java.lang.reflect.Type[]> paramtypes = new ArrayList<>();
|
||||||
for (final Method method : serviceType.getMethods()) {
|
for (final Method method : serviceType.getMethods()) {
|
||||||
@@ -254,9 +254,9 @@ public final class Rest {
|
|||||||
}
|
}
|
||||||
methodidex++;
|
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);
|
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(serviceType);
|
||||||
for (final MappingEntry entry : entrys) {
|
for (final MappingEntry entry : entrys) {
|
||||||
final Method method = entry.mappingMethod;
|
final Method method = entry.mappingMethod;
|
||||||
@@ -380,7 +380,7 @@ public final class Rest {
|
|||||||
|
|
||||||
Map<String, Object> mappingMap = new LinkedHashMap<>();
|
Map<String, Object> mappingMap = new LinkedHashMap<>();
|
||||||
{ // 设置 Annotation
|
{ // 设置 Annotation
|
||||||
//设置 WebMapping
|
//设置 HttpMapping
|
||||||
boolean reqpath = false;
|
boolean reqpath = false;
|
||||||
for (Object[] ps : paramlist) {
|
for (Object[] ps : paramlist) {
|
||||||
if ("#".equals((String) ps[1])) {
|
if ("#".equals((String) ps[1])) {
|
||||||
@@ -425,8 +425,8 @@ public final class Rest {
|
|||||||
av2.visit("name", (String) ps[1]);
|
av2.visit("name", (String) ps[1]);
|
||||||
av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2])));
|
av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2])));
|
||||||
av2.visit("radix", (Integer) ps[3]);
|
av2.visit("radix", (Integer) ps[3]);
|
||||||
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name()
|
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpParam.HttpParamSourceType.HEADER.name()
|
||||||
: (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name()));
|
: (iscookie ? HttpParam.HttpParamSourceType.COOKIE.name() : HttpParam.HttpParamSourceType.PARAMETER.name()));
|
||||||
av2.visit("comment", (String) ps[4]);
|
av2.visit("comment", (String) ps[4]);
|
||||||
av2.visit("required", (Boolean) ps[5]);
|
av2.visit("required", (Boolean) ps[5]);
|
||||||
av2.visitEnd();
|
av2.visitEnd();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
* @param <T> 当前用户对象类型
|
* @param <T> 当前用户对象类型
|
||||||
*/
|
*/
|
||||||
public abstract class RestHttpServlet<T> extends HttpBaseServlet {
|
public abstract class RestHttpServlet<T> extends HttpServlet {
|
||||||
|
|
||||||
protected abstract T currentUser(HttpRequest req) throws IOException;
|
protected abstract T currentUser(HttpRequest req) throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public @interface RestMapping {
|
|||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 备注描述, 对应@WebMapping.comment
|
* 备注描述, 对应@HttpMapping.comment
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
@@ -54,7 +54,7 @@ public @interface RestMapping {
|
|||||||
boolean auth() default false;
|
boolean auth() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作ID值,鉴权时用到, 对应@WebMapping.actionid
|
* 操作ID值,鉴权时用到, 对应@HttpMapping.actionid
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@@ -68,7 +68,7 @@ public @interface RestMapping {
|
|||||||
int cacheseconds() default 0;
|
int cacheseconds() default 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebMapping.methods
|
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@HttpMapping.methods
|
||||||
*
|
*
|
||||||
* @return String[]
|
* @return String[]
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,13 +10,16 @@ import java.net.HttpCookie;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 使用 HttpResult 代替
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
* @param <T> 结果对象的类型
|
* @param <T> 结果对象的类型
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class RestOutput<T> {
|
public class RestOutput<T> {
|
||||||
|
|
||||||
private Map<String, String> headers;
|
private Map<String, String> headers;
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
|
|
||||||
protected WebSocketEngine engine;
|
protected WebSocketEngine engine;
|
||||||
|
|
||||||
public final void preInit(HttpContext context, AnyValue conf) {
|
@Override
|
||||||
|
final void preInit(HttpContext context, AnyValue conf) {
|
||||||
InetSocketAddress addr = context.getServerAddress();
|
InetSocketAddress addr = context.getServerAddress();
|
||||||
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", this.node, logger);
|
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", this.node, logger);
|
||||||
if (this.node == null) this.node = createWebSocketNode();
|
if (this.node == null) this.node = createWebSocketNode();
|
||||||
@@ -84,7 +85,8 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
this.engine.init(conf);
|
this.engine.init(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void postDestroy(HttpContext context, AnyValue conf) {
|
@Override
|
||||||
|
final void postDestroy(HttpContext context, AnyValue conf) {
|
||||||
this.node.postDestroy(conf);
|
this.node.postDestroy(conf);
|
||||||
super.destroy(context, conf);
|
super.destroy(context, conf);
|
||||||
engine.close();
|
engine.close();
|
||||||
|
|||||||
27
src/org/redkale/util/AuthIgnore.java
Normal file
27
src/org/redkale/util/AuthIgnore.java
Normal 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 使用。
|
||||||
|
* 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD, TYPE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface AuthIgnore {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,16 +25,16 @@ public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
|
|||||||
|
|
||||||
//普通鉴权
|
//普通鉴权
|
||||||
@Override
|
@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);
|
UserInfo info = currentUser(request);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
response.finishJson(RET_UNLOGIN);
|
response.finishJson(RET_UNLOGIN);
|
||||||
return;
|
return;
|
||||||
} else if (!info.checkAuth(module, actionid)) {
|
} else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
|
||||||
response.finishJson(RET_AUTHILLEGAL);
|
response.finishJson(RET_AUTHILLEGAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
next.execute(request, response);
|
response.nextEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/create")
|
@HttpMapping(url = "/hello/create")
|
||||||
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||||
@@ -60,7 +60,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/delete/")
|
@HttpMapping(url = "/hello/delete/")
|
||||||
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||||
@@ -69,7 +69,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/update")
|
@HttpMapping(url = "/hello/update")
|
||||||
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
String clientaddr = req.getRemoteAddr();
|
String clientaddr = req.getRemoteAddr();
|
||||||
@@ -81,7 +81,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/partupdate")
|
@HttpMapping(url = "/hello/partupdate")
|
||||||
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
|
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||||
@@ -93,7 +93,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/query")
|
@HttpMapping(url = "/hello/query")
|
||||||
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||||
@@ -107,7 +107,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/list")
|
@HttpMapping(url = "/hello/list")
|
||||||
public void list(HttpRequest req, HttpResponse resp) throws IOException {
|
public void list(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||||
@@ -120,7 +120,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/find/")
|
@HttpMapping(url = "/hello/find/")
|
||||||
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||||
@@ -129,7 +129,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/asyncfind/")
|
@HttpMapping(url = "/hello/asyncfind/")
|
||||||
public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException {
|
public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import javax.annotation.Resource;
|
|||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
import org.redkale.service.RetResult;
|
import org.redkale.service.RetResult;
|
||||||
import org.redkale.source.Flipper;
|
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;
|
private Map<String, HelloService2> _servicemap;
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/create", comment = "创建Hello对象")
|
@HttpMapping(url = "/hello/create", comment = "创建Hello对象")
|
||||||
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
|
@HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
|
||||||
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||||
@@ -42,8 +42,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/delete/", comment = "根据id删除Hello对象")
|
@HttpMapping(url = "/hello/delete/", comment = "根据id删除Hello对象")
|
||||||
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
|
@HttpParam(name = "#", type = int.class, comment = "Hello对象id")
|
||||||
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||||
@@ -52,8 +52,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/update", comment = "修改Hello对象")
|
@HttpMapping(url = "/hello/update", comment = "修改Hello对象")
|
||||||
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
|
@HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
|
||||||
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||||
@@ -66,8 +66,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/query", comment = "查询Hello对象列表")
|
@HttpMapping(url = "/hello/query", comment = "查询Hello对象列表")
|
||||||
@WebParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
|
@HttpParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
|
||||||
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||||
@@ -81,8 +81,8 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthIgnore
|
@AuthIgnore
|
||||||
@WebMapping(url = "/hello/find/", comment = "根据id删除Hello对象")
|
@HttpMapping(url = "/hello/find/", comment = "根据id删除Hello对象")
|
||||||
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
|
@HttpParam(name = "#", type = int.class, comment = "Hello对象id")
|
||||||
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
||||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||||
|
|||||||
Reference in New Issue
Block a user