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 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<MappingEntry> entrys = new ArrayList<>();
final Map<String, org.redkale.util.Attribute> 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<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++;
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<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) {
throw new RuntimeException(e);
}

View File

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

View File

@@ -17,16 +17,16 @@ import org.redkale.util.Attribute;
*/
public abstract class RestHttpServlet<T> 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]));
}
}

View File

@@ -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) {

View File

@@ -44,17 +44,17 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* public String get(Record obj) {
* return obj.getName();
* }
*
*
* &#64;Override
* public void set(Record obj, String value) {
* obj.setName(value);
* }
*
*
* &#64;Override
* public Class type() {
* return String.class;
* }
*
*
* &#64;Override
* public Class declaringClass() {
* return Record.class;
@@ -421,6 +421,8 @@ public interface Attribute<T, F> {
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();

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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<HelloEntity> 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);
}
}
}

View File

@@ -15,16 +15,13 @@ import org.redkale.service.*;
*/
public abstract class RetCodes {
static {
load(RetCodes.class);
}
protected static final Map<Integer, String> rets = new HashMap<>();
protected RetCodes() {
}
//-----------------------------------------------------------------------------------------------------------
protected static final Map<Integer, String> 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);
}
}

View File

@@ -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<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
@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());
}