diff --git a/src/org/redkale/net/http/Rest.java b/src/org/redkale/net/http/Rest.java index f24f9562c..2d3e5e9fd 100644 --- a/src/org/redkale/net/http/Rest.java +++ b/src/org/redkale/net/http/Rest.java @@ -56,6 +56,7 @@ public final class Rest { final String webServletDesc = Type.getDescriptor(WebServlet.class); final String httpRequestDesc = Type.getDescriptor(HttpRequest.class); final String httpResponseDesc = Type.getDescriptor(HttpResponse.class); + final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class); final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class); final String serviceTypeString = serviceType.getName().replace('.', '/'); @@ -135,6 +136,7 @@ public final class Rest { } final List entrys = new ArrayList<>(); + final Map restAttributes = new LinkedHashMap<>(); for (final Method method : serviceType.getMethods()) { Class[] extypes = method.getExceptionTypes(); @@ -407,6 +409,68 @@ public final class Rest { mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); mv.visitVarInsn(ASTORE, maxLocals); varInsns.add(new int[]{ALOAD, maxLocals}); + + //构建 RestHeader、RestCookie、RestAddress 等赋值操作 + Class loop = ptype; + Set fields = new HashSet<>(); + Map attrParaNames = new LinkedHashMap<>(); + do { + for (Field field : loop.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (Modifier.isFinal(field.getModifiers())) continue; + if (fields.contains(field.getName())) continue; + RestHeader rh = field.getAnnotation(RestHeader.class); + RestCookie rc = field.getAnnotation(RestCookie.class); + RestAddress ra = field.getAnnotation(RestAddress.class); + if (rh == null && rc == null && ra == null) continue; + if (rh != null && field.getType() != String.class) throw new RuntimeException("@RestHeader must on String Field in " + field); + if (rc != null && field.getType() != String.class) throw new RuntimeException("@RestCookie must on String Field in " + field); + if (ra != null && field.getType() != String.class) throw new RuntimeException("@RestAddress must on String Field in " + field); + org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field); + String attrFieldName; + String restname = ""; + if (rh != null) { + attrFieldName = "_redkale_attr_header_" + restAttributes.size(); + restname = rh.value(); + } else if (rc != null) { + attrFieldName = "_redkale_attr_cookie_" + restAttributes.size(); + restname = rc.value(); + } else if (ra != null) { + attrFieldName = "_redkale_attr_address_" + restAttributes.size(); + } else { + continue; + } + restAttributes.put(attrFieldName, attr); + attrParaNames.put(attrFieldName, restname); + fields.add(field.getName()); + } + } while ((loop = loop.getSuperclass()) != Object.class); + + if (!attrParaNames.isEmpty()) { //参数存在 RestHeader、RestCookie、RestAddress字段 + mv.visitVarInsn(ALOAD, maxLocals); + Label lif = new Label(); + mv.visitJumpInsn(IFNULL, lif); //if(bean != null) { + for (Map.Entry en : attrParaNames.entrySet()) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, en.getKey(), attrDesc); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitVarInsn(ALOAD, 1); + if (en.getKey().contains("_header_")) { + mv.visitLdcInsn(en.getValue()); + mv.visitLdcInsn(""); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getHeader", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false); + } else if (en.getKey().contains("_cookie_")) { + mv.visitLdcInsn(en.getValue()); + mv.visitLdcInsn(""); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getCookie", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false); + } else if (en.getKey().contains("_address_")) { + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRemoteAddr", "()Ljava/lang/String;", false); + } + mv.visitMethodInsn(INVOKEINTERFACE, "org/redkale/util/Attribute", "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + } + mv.visitLabel(lif); // end if } + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{ptype.getName().replace('.', '/')}, 0, null); + } } maxLocals++; paramMaps.add(paramMap); @@ -671,7 +735,13 @@ public final class Rest { mv.visitMaxs(maxStack, maxLocals); actionMap.put("params", paramMaps); actionMaps.add(actionMap); - } // end for each + } // end for each + + for (String attrname : restAttributes.keySet()) { + fv = cw.visitField(ACC_PRIVATE, attrname, attrDesc, null, null); + fv.visitEnd(); + } + classMap.put("actions", actionMaps); { //toString函数 @@ -691,7 +761,13 @@ public final class Rest { } }.loadClass(newDynName.replace('/', '.'), bytes); try { - return ((Class) newClazz).newInstance(); + T obj = ((Class) newClazz).newInstance(); + for (Map.Entry en : restAttributes.entrySet()) { + Field attrField = newClazz.getDeclaredField(en.getKey()); + attrField.setAccessible(true); + attrField.set(obj, en.getValue()); + } + return obj; } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/org/redkale/net/http/RestHeader.java b/src/org/redkale/net/http/RestHeader.java index 641241050..2428f6b1d 100644 --- a/src/org/redkale/net/http/RestHeader.java +++ b/src/org/redkale/net/http/RestHeader.java @@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * 只能注解于Service类的方法的参数或参数内的字段 + * 只能注解于Service类的方法的参数或参数内的String字段 *

* 详情见: http://redkale.org * diff --git a/src/org/redkale/net/http/RestHttpServlet.java b/src/org/redkale/net/http/RestHttpServlet.java index 2c9489940..1b3184786 100644 --- a/src/org/redkale/net/http/RestHttpServlet.java +++ b/src/org/redkale/net/http/RestHttpServlet.java @@ -17,16 +17,16 @@ import org.redkale.util.Attribute; */ public abstract class RestHttpServlet extends HttpBaseServlet { - Attribute[] _paramAttrs; // 为null表示无DynCall处理,index=0固定为null, 其他为参数标记的DynCall回调方法 - protected abstract T currentUser(HttpRequest req) throws IOException; + Attribute[] _paramAttrs; // 为null表示无DynCall处理,index=0固定为null, 其他为参数标记的DynCall回调方法 + protected void _callParameter(final HttpResponse response, final Object... params) { if (_paramAttrs == null) return; for (int i = 1; i < _paramAttrs.length; i++) { org.redkale.util.Attribute attr = _paramAttrs[i]; if (attr == null) continue; - + //convert.convertTo(out, attr.type(), attr.get(params[i - 1])); } } diff --git a/src/org/redkale/util/AsmMethodVisitor.java b/src/org/redkale/util/AsmMethodVisitor.java index 2284b593f..577112237 100644 --- a/src/org/redkale/util/AsmMethodVisitor.java +++ b/src/org/redkale/util/AsmMethodVisitor.java @@ -82,6 +82,25 @@ public class AsmMethodVisitor { if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); } + public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { + visitor.visitFrame(type, nLocal, local, nStack, stack); + if (debug) { + String typestr = "" + type; + if (type == -1) { + typestr = "Opcodes.F_NEW"; + } else if (type == 1) { + typestr = "Opcodes.F_APPEND"; + } else if (type == 2) { + typestr = "Opcodes.F_CHOP"; + } else if (type == 3) { + typestr = "Opcodes.F_SAME"; + } else if (type == 4) { + typestr = "Opcodes.F_SAME1"; + } + System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");"); + } + } + public void visitJumpInsn(int opcode, Label var) { //调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建 visitor.visitJumpInsn(opcode, var); if (debug) { diff --git a/src/org/redkale/util/Attribute.java b/src/org/redkale/util/Attribute.java index ad7e22bc0..401d0a05e 100644 --- a/src/org/redkale/util/Attribute.java +++ b/src/org/redkale/util/Attribute.java @@ -44,17 +44,17 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; * public String get(Record obj) { * return obj.getName(); * } - * + * * @Override * public void set(Record obj, String value) { * obj.setName(value); * } - * + * * @Override * public Class type() { * return String.class; * } - * + * * @Override * public Class declaringClass() { * return Record.class; @@ -421,6 +421,8 @@ public interface Attribute { column = tgetter.getReturnType(); } else if (tsetter != null) { column = tsetter.getParameterTypes()[0]; + } else if (fieldtype == null) { + throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); } final Class pcolumn = column; if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass(); diff --git a/test/org/redkale/test/rest/HelloBean.java b/test/org/redkale/test/rest/HelloBean.java index f43a180c0..8a01cfa84 100644 --- a/test/org/redkale/test/rest/HelloBean.java +++ b/test/org/redkale/test/rest/HelloBean.java @@ -1,12 +1,16 @@ package org.redkale.test.rest; import org.redkale.convert.json.JsonFactory; +import org.redkale.net.http.*; import org.redkale.source.FilterBean; public class HelloBean implements FilterBean { private int helloid; + @RestHeader("hello-res") + private String res; + public int getHelloid() { return helloid; } @@ -15,8 +19,17 @@ public class HelloBean implements FilterBean { this.helloid = helloid; } + public String getRes() { + return res; + } + + public void setRes(String res) { + this.res = res; + } + @Override public String toString() { return JsonFactory.root().getConvert().convertTo(this); } + } diff --git a/test/org/redkale/test/rest/HelloEntity.java b/test/org/redkale/test/rest/HelloEntity.java index 1297f1bfe..6fff93c15 100644 --- a/test/org/redkale/test/rest/HelloEntity.java +++ b/test/org/redkale/test/rest/HelloEntity.java @@ -2,7 +2,10 @@ package org.redkale.test.rest; import javax.persistence.Id; import org.redkale.convert.json.JsonFactory; +import org.redkale.net.http.*; +import org.redkale.source.VirtualEntity; +@VirtualEntity public class HelloEntity { @Id @@ -16,6 +19,12 @@ public class HelloEntity { private long createtime; + @RestHeader("hello-res") + private String resname; + + @RestAddress + private String clientaddr; + public int getHelloid() { return helloid; } @@ -56,6 +65,22 @@ public class HelloEntity { this.creator = creator; } + public String getClientaddr() { + return clientaddr; + } + + public void setClientaddr(String clientaddr) { + this.clientaddr = clientaddr; + } + + public String getResname() { + return resname; + } + + public void setResname(String resname) { + this.resname = resname; + } + @Override public String toString() { return JsonFactory.root().getConvert().convertTo(this); diff --git a/test/org/redkale/test/rest/HelloService.java b/test/org/redkale/test/rest/HelloService.java index 3a1b504f1..ac3500e3a 100644 --- a/test/org/redkale/test/rest/HelloService.java +++ b/test/org/redkale/test/rest/HelloService.java @@ -9,7 +9,6 @@ import org.redkale.source.DataSource; import org.redkale.source.Flipper; import org.redkale.util.Sheet; - /** * 类说明: * Flipper : Source组件中的翻页对象 @@ -37,18 +36,19 @@ public class HelloService implements Service { } //修改记录 - public void updateHello(HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象 - entity.setUpdatetime(System.currentTimeMillis()); - source.update(entity); + public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象 + System.out.println("修改记录: clientAddr = " + clientAddr + ", entity =" + entity); + if (entity != null) entity.setUpdatetime(System.currentTimeMillis()); + if (source != null) source.update(entity); } //修改记录 - @RestMapping(name = "partupdate") + @RestMapping(name = "partupdate") public void updateHello(HelloEntity entity, @RestParam("cols") String[] columns) { //通过 /hello/partupdate?bean={...} 修改对象 entity.setUpdatetime(System.currentTimeMillis()); source.updateColumns(entity, columns); } - + //查询Sheet列表 public Sheet queryHello(HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询Sheet列表 return source.querySheet(HelloEntity.class, flipper, bean); @@ -66,4 +66,4 @@ public class HelloService implements Service { public HelloEntity findHello(@RestParam("#") int id) { //通过 /hello/find/1234 查询对象 return source.find(HelloEntity.class, id); } -} \ No newline at end of file +} diff --git a/test/org/redkale/test/rest/RetCodes.java b/test/org/redkale/test/rest/RetCodes.java index 1501597c4..1b9b7b496 100644 --- a/test/org/redkale/test/rest/RetCodes.java +++ b/test/org/redkale/test/rest/RetCodes.java @@ -15,16 +15,13 @@ import org.redkale.service.*; */ public abstract class RetCodes { - static { - load(RetCodes.class); - } + protected static final Map rets = new HashMap<>(); + protected RetCodes() { } //----------------------------------------------------------------------------------------------------------- - protected static final Map rets = new HashMap<>(); - protected static void load(Class clazz) { for (Field field : clazz.getFields()) { if (!Modifier.isStatic(field.getModifiers())) continue; @@ -158,4 +155,9 @@ public abstract class RetCodes { @RetLabel("用户设备ID无效") public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030; + + + static { + load(RetCodes.class); + } } diff --git a/test/org/redkale/test/rest/_DynHelloRestServlet.java b/test/org/redkale/test/rest/_DynHelloRestServlet1.java similarity index 67% rename from test/org/redkale/test/rest/_DynHelloRestServlet.java rename to test/org/redkale/test/rest/_DynHelloRestServlet1.java index 5649eb235..2961e1f28 100644 --- a/test/org/redkale/test/rest/_DynHelloRestServlet.java +++ b/test/org/redkale/test/rest/_DynHelloRestServlet1.java @@ -1,19 +1,45 @@ package org.redkale.test.rest; import java.io.IOException; -import java.util.List; +import java.lang.reflect.Field; +import java.util.*; import javax.annotation.Resource; import org.redkale.net.http.*; import org.redkale.service.RetResult; import org.redkale.source.Flipper; import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; @WebServlet(value = {"/hello/*"}, repair = true) -public class _DynHelloRestServlet extends SimpleRestServlet { +public class _DynHelloRestServlet1 extends SimpleRestServlet { @Resource private HelloService _service; + public static void main(String[] args) throws Throwable { + final int port = 8888; + HelloService service = new HelloService(); + HttpServer server = new HttpServer(); + RestHttpServlet servlet = Rest.createRestServlet(SimpleRestServlet.class, "", HelloService.class, false); + Field field = servlet.getClass().getDeclaredField("_service"); + field.setAccessible(true); + field.set(servlet, service); + server.addHttpServlet(servlet, "/pipes", null, "/hello/*"); + + DefaultAnyValue conf = DefaultAnyValue.create("port", "" + port); + server.init(conf); + server.start(); + Thread.sleep(100); + + HelloEntity entity = new HelloEntity(); + entity.setHelloname("my name"); + Map headers = new HashMap<>(); + headers.put("hello-res", "my res"); + String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}"; + System.out.println(Utility.postHttpContent(url, headers, null)); + + } + @AuthIgnore @WebAction(url = "/hello/create") public void create(HttpRequest req, HttpResponse resp) throws IOException { @@ -34,8 +60,9 @@ public class _DynHelloRestServlet extends SimpleRestServlet { @AuthIgnore @WebAction(url = "/hello/update") public void update(HttpRequest req, HttpResponse resp) throws IOException { + String clientaddr = req.getRemoteAddr(); HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - _service.updateHello(bean); + _service.updateHello(clientaddr, bean); resp.finishJson(RetResult.success()); }