This commit is contained in:
Redkale
2016-08-29 17:21:02 +08:00
parent 9f5ab4b068
commit e8e6459679
10 changed files with 188 additions and 24 deletions

View File

@@ -56,6 +56,7 @@ public final class Rest {
final String webServletDesc = Type.getDescriptor(WebServlet.class); final String webServletDesc = Type.getDescriptor(WebServlet.class);
final String httpRequestDesc = Type.getDescriptor(HttpRequest.class); final String httpRequestDesc = Type.getDescriptor(HttpRequest.class);
final String httpResponseDesc = Type.getDescriptor(HttpResponse.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 authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class); final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class);
final String serviceTypeString = serviceType.getName().replace('.', '/'); final String serviceTypeString = serviceType.getName().replace('.', '/');
@@ -135,6 +136,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<>();
for (final Method method : serviceType.getMethods()) { for (final Method method : serviceType.getMethods()) {
Class[] extypes = method.getExceptionTypes(); Class[] extypes = method.getExceptionTypes();
@@ -407,6 +409,68 @@ public final class Rest {
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals}); varInsns.add(new int[]{ALOAD, maxLocals});
//构建 RestHeader、RestCookie、RestAddress 等赋值操作
Class loop = ptype;
Set<String> fields = new HashSet<>();
Map<String, String> 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<String, String> 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++; maxLocals++;
paramMaps.add(paramMap); paramMaps.add(paramMap);
@@ -671,7 +735,13 @@ public final class Rest {
mv.visitMaxs(maxStack, maxLocals); mv.visitMaxs(maxStack, maxLocals);
actionMap.put("params", paramMaps); actionMap.put("params", paramMaps);
actionMaps.add(actionMap); 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); classMap.put("actions", actionMaps);
{ //toString函数 { //toString函数
@@ -691,7 +761,13 @@ public final class Rest {
} }
}.loadClass(newDynName.replace('/', '.'), bytes); }.loadClass(newDynName.replace('/', '.'), bytes);
try { try {
return ((Class<T>) newClazz).newInstance(); T obj = ((Class<T>) newClazz).newInstance();
for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) {
Field attrField = newClazz.getDeclaredField(en.getKey());
attrField.setAccessible(true);
attrField.set(obj, en.getValue());
}
return obj;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 只能注解于Service类的方法的参数或参数内的字段 * 只能注解于Service类的方法的参数或参数内的String字段
* <p> * <p>
* 详情见: http://redkale.org * 详情见: http://redkale.org
* *

View File

@@ -17,16 +17,16 @@ import org.redkale.util.Attribute;
*/ */
public abstract class RestHttpServlet<T> extends HttpBaseServlet { public abstract class RestHttpServlet<T> extends HttpBaseServlet {
Attribute[] _paramAttrs; // 为null表示无DynCall处理index=0固定为null, 其他为参数标记的DynCall回调方法
protected abstract T currentUser(HttpRequest req) throws IOException; 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) { protected void _callParameter(final HttpResponse response, final Object... params) {
if (_paramAttrs == null) return; if (_paramAttrs == null) return;
for (int i = 1; i < _paramAttrs.length; i++) { for (int i = 1; i < _paramAttrs.length; i++) {
org.redkale.util.Attribute attr = _paramAttrs[i]; org.redkale.util.Attribute attr = _paramAttrs[i];
if (attr == null) continue; if (attr == null) continue;
//convert.convertTo(out, attr.type(), attr.get(params[i - 1])); //convert.convertTo(out, attr.type(), attr.get(params[i - 1]));
} }
} }

View File

@@ -82,6 +82,25 @@ public class AsmMethodVisitor {
if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); 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 构建 public void visitJumpInsn(int opcode, Label var) { //调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
visitor.visitJumpInsn(opcode, var); visitor.visitJumpInsn(opcode, var);
if (debug) { if (debug) {

View File

@@ -44,17 +44,17 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* public String get(Record obj) { * public String get(Record obj) {
* return obj.getName(); * return obj.getName();
* } * }
* *
* &#64;Override * &#64;Override
* public void set(Record obj, String value) { * public void set(Record obj, String value) {
* obj.setName(value); * obj.setName(value);
* } * }
* *
* &#64;Override * &#64;Override
* public Class type() { * public Class type() {
* return String.class; * return String.class;
* } * }
* *
* &#64;Override * &#64;Override
* public Class declaringClass() { * public Class declaringClass() {
* return Record.class; * return Record.class;
@@ -421,6 +421,8 @@ public interface Attribute<T, F> {
column = tgetter.getReturnType(); column = tgetter.getReturnType();
} else if (tsetter != null) { } else if (tsetter != null) {
column = tsetter.getParameterTypes()[0]; column = tsetter.getParameterTypes()[0];
} else if (fieldtype == null) {
throw new RuntimeException("[" + clazz + "]have no public field or setter or getter");
} }
final Class pcolumn = column; final Class pcolumn = column;
if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass(); if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass();

View File

@@ -1,12 +1,16 @@
package org.redkale.test.rest; package org.redkale.test.rest;
import org.redkale.convert.json.JsonFactory; import org.redkale.convert.json.JsonFactory;
import org.redkale.net.http.*;
import org.redkale.source.FilterBean; import org.redkale.source.FilterBean;
public class HelloBean implements FilterBean { public class HelloBean implements FilterBean {
private int helloid; private int helloid;
@RestHeader("hello-res")
private String res;
public int getHelloid() { public int getHelloid() {
return helloid; return helloid;
} }
@@ -15,8 +19,17 @@ public class HelloBean implements FilterBean {
this.helloid = helloid; this.helloid = helloid;
} }
public String getRes() {
return res;
}
public void setRes(String res) {
this.res = res;
}
@Override @Override
public String toString() { public String toString() {
return JsonFactory.root().getConvert().convertTo(this); return JsonFactory.root().getConvert().convertTo(this);
} }
} }

View File

@@ -2,7 +2,10 @@ package org.redkale.test.rest;
import javax.persistence.Id; import javax.persistence.Id;
import org.redkale.convert.json.JsonFactory; import org.redkale.convert.json.JsonFactory;
import org.redkale.net.http.*;
import org.redkale.source.VirtualEntity;
@VirtualEntity
public class HelloEntity { public class HelloEntity {
@Id @Id
@@ -16,6 +19,12 @@ public class HelloEntity {
private long createtime; private long createtime;
@RestHeader("hello-res")
private String resname;
@RestAddress
private String clientaddr;
public int getHelloid() { public int getHelloid() {
return helloid; return helloid;
} }
@@ -56,6 +65,22 @@ public class HelloEntity {
this.creator = creator; 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 @Override
public String toString() { public String toString() {
return JsonFactory.root().getConvert().convertTo(this); return JsonFactory.root().getConvert().convertTo(this);

View File

@@ -9,7 +9,6 @@ import org.redkale.source.DataSource;
import org.redkale.source.Flipper; import org.redkale.source.Flipper;
import org.redkale.util.Sheet; import org.redkale.util.Sheet;
/** /**
* 类说明: * 类说明:
* Flipper : Source组件中的翻页对象 * Flipper : Source组件中的翻页对象
@@ -37,18 +36,19 @@ public class HelloService implements Service {
} }
//修改记录 //修改记录
public void updateHello(HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象 public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
entity.setUpdatetime(System.currentTimeMillis()); System.out.println("修改记录: clientAddr = " + clientAddr + ", entity =" + entity);
source.update(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={...} 修改对象 public void updateHello(HelloEntity entity, @RestParam("cols") String[] columns) { //通过 /hello/partupdate?bean={...} 修改对象
entity.setUpdatetime(System.currentTimeMillis()); entity.setUpdatetime(System.currentTimeMillis());
source.updateColumns(entity, columns); source.updateColumns(entity, columns);
} }
//查询Sheet列表 //查询Sheet列表
public Sheet<HelloEntity> queryHello(HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询Sheet列表 public Sheet<HelloEntity> queryHello(HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询Sheet列表
return source.querySheet(HelloEntity.class, flipper, bean); 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 查询对象 public HelloEntity findHello(@RestParam("#") int id) { //通过 /hello/find/1234 查询对象
return source.find(HelloEntity.class, id); return source.find(HelloEntity.class, id);
} }
} }

View File

@@ -15,16 +15,13 @@ import org.redkale.service.*;
*/ */
public abstract class RetCodes { public abstract class RetCodes {
static { protected static final Map<Integer, String> rets = new HashMap<>();
load(RetCodes.class);
}
protected RetCodes() { protected RetCodes() {
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
protected static final Map<Integer, String> rets = new HashMap<>();
protected static void load(Class clazz) { protected static void load(Class clazz) {
for (Field field : clazz.getFields()) { for (Field field : clazz.getFields()) {
if (!Modifier.isStatic(field.getModifiers())) continue; if (!Modifier.isStatic(field.getModifiers())) continue;
@@ -158,4 +155,9 @@ public abstract class RetCodes {
@RetLabel("用户设备ID无效") @RetLabel("用户设备ID无效")
public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030; public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030;
static {
load(RetCodes.class);
}
} }

View File

@@ -1,19 +1,45 @@
package org.redkale.test.rest; package org.redkale.test.rest;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.lang.reflect.Field;
import java.util.*;
import javax.annotation.Resource; 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.*; import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
@WebServlet(value = {"/hello/*"}, repair = true) @WebServlet(value = {"/hello/*"}, repair = true)
public class _DynHelloRestServlet extends SimpleRestServlet { public class _DynHelloRestServlet1 extends SimpleRestServlet {
@Resource @Resource
private HelloService _service; 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<String, String> 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 @AuthIgnore
@WebAction(url = "/hello/create") @WebAction(url = "/hello/create")
public void create(HttpRequest req, HttpResponse resp) throws IOException { public void create(HttpRequest req, HttpResponse resp) throws IOException {
@@ -34,8 +60,9 @@ public class _DynHelloRestServlet extends SimpleRestServlet {
@AuthIgnore @AuthIgnore
@WebAction(url = "/hello/update") @WebAction(url = "/hello/update")
public void update(HttpRequest req, HttpResponse resp) throws IOException { public void update(HttpRequest req, HttpResponse resp) throws IOException {
String clientaddr = req.getRemoteAddr();
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
_service.updateHello(bean); _service.updateHello(clientaddr, bean);
resp.finishJson(RetResult.success()); resp.finishJson(RetResult.success());
} }