This commit is contained in:
Redkale
2016-08-29 20:27:54 +08:00
parent e8e6459679
commit 81f386dcdb
8 changed files with 142 additions and 48 deletions

View File

@@ -133,7 +133,7 @@
-->
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes="">
<!--
value: Service类名列出的表示必须被加载的Service对象 且对象的Resource资源名称只能是""。
value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false
-->
<service value="com.xxx.XXXXService"/>

View File

@@ -172,7 +172,6 @@ public class NodeHttpServer extends NodeServer {
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
super.interceptorServiceWrappers.forEach((wrapper) -> {
if (!wrapper.getName().isEmpty()) return; //只加载resourceName为空的service
final Class stype = wrapper.getType();
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs != null && rs.ignore()) return;
@@ -183,17 +182,8 @@ public class NodeHttpServer extends NodeServer {
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
RestHttpServlet servlet = Rest.createRestServlet(baseServletClass, wrapper.getName(), stype, sncp);
if (servlet == null) return;
RestHttpServlet servlet = httpServer.addRestServlet(stype, wrapper.getName(), wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
if (finest) logger.finest("Create RestServlet = " + servlet);
try {
Field serviceField = servlet.getClass().getDeclaredField("_service");
serviceField.setAccessible(true);
serviceField.set(servlet, wrapper.getService());
} catch (Exception e) {
throw new RuntimeException(wrapper.getType() + " generate rest servlet error", e);
}
httpServer.addHttpServlet(servlet, prefix, (AnyValue) null);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {

View File

@@ -107,7 +107,7 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
}
synchronized (allMapStrings) {
for (String mapping : mappings) {
if(mapping == null) continue;
if (mapping == null) continue;
if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (this.allMapStrings.containsKey(mapping)) {
Class old = this.allMapStrings.get(mapping);
@@ -158,6 +158,10 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
return this.resourceHttpServlet;
}
Set<HttpServlet> getServlets() {
return this.servlets;
}
@Override
public void destroy(HttpContext context, AnyValue config) {
this.resourceHttpServlet.destroy(context, config);

View File

@@ -5,11 +5,13 @@
*/
package org.redkale.net.http;
import java.lang.reflect.Field;
import java.net.HttpCookie;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import org.redkale.net.*;
import org.redkale.service.Service;
import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
@@ -39,6 +41,48 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
this.prepare.addServlet(servlet, prefix, conf, mappings);
}
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(Class<S> serviceType,
final String name, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
RestHttpServlet servlet = null;
for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) {
if (!(item instanceof RestHttpServlet)) continue;
try {
Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
if (serviceType.equals(field.getType())) {
servlet = (RestHttpServlet) item;
break;
}
} catch (NoSuchFieldException | SecurityException e) {
continue;
}
}
if (servlet == null) servlet = Rest.createRestServlet(baseServletClass, serviceType, false);
try { //若提供动态变更Service服务功能则改Rest服务无法做出相应更新
Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
field.setAccessible(true);
Field mapfield = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME);
mapfield.setAccessible(true);
Service firstService = (Service) field.get(servlet);
if (name.isEmpty()) {
field.set(servlet, service);
firstService = service;
}
Map map = (Map) mapfield.get(servlet);
if (map == null && !name.isEmpty()) map = new HashMap();
if (map != null) {
map.put(name, service);
if (firstService != null) map.put("", firstService);
}
mapfield.set(servlet, map);
} catch (Exception e) {
throw new RuntimeException(serviceType + " generate rest servlet error", e);
}
this.prepare.addServlet(servlet, prefix, conf);
return servlet;
}
@Override
@SuppressWarnings("unchecked")
protected HttpContext createContext() {

View File

@@ -27,6 +27,12 @@ import org.redkale.source.Flipper;
*/
public final class Rest {
public static final String REST_HEADER_RESOURCE_NAME = "rest-resource-name";
static final String REST_SERVICE_FIELD_NAME = "_service";
static final String REST_SERVICEMAP_FIELD_NAME = "_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null
private static final Set<String> EXCLUDERMETHODS = new HashSet<>();
static {
@@ -38,14 +44,14 @@ public final class Rest {
private Rest() {
}
public static String getWebModuleName(Class<? extends Service> serviceType) {
static String getWebModuleName(Class<? extends Service> serviceType) {
final RestService controller = serviceType.getAnnotation(RestService.class);
if (controller == null) return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
if (controller.ignore()) return null;
return (!controller.value().isEmpty()) ? controller.value() : serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
}
public static <T extends RestHttpServlet> T createRestServlet(final Class<T> baseServletClass, final String serviceName, final Class<? extends Service> serviceType, final boolean sncp) {
static <T extends RestHttpServlet> T createRestServlet(final Class<T> baseServletClass, final Class<? extends Service> serviceType, final boolean sncp) {
if (baseServletClass == null || serviceType == null) return null;
if (!RestHttpServlet.class.isAssignableFrom(baseServletClass)) return null;
int mod = baseServletClass.getModifiers();
@@ -66,13 +72,6 @@ public final class Rest {
if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = serviceTypeString.substring(0, serviceTypeString.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";
if (!serviceName.isEmpty()) {
boolean normal = true;
for (char ch : serviceName.toCharArray()) {//含特殊字符的使用hash值
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false;
}
newDynName += "_" + (normal ? serviceName : Sncp.hash(serviceName));
}
try {
return ((Class<T>) Class.forName(newDynName.replace('/', '.'))).newInstance();
} catch (Exception ex) {
@@ -113,18 +112,21 @@ public final class Rest {
av0.visitEnd();
classMap.put("type", serviceType.getName());
classMap.put("url", urlpath);
if (!serviceName.isEmpty()) classMap.put("resource", serviceName);
classMap.put("moduleid", moduleid);
classMap.put("repair", repair);
}
{ //注入 @Resource private XXXService _service;
fv = cw.visitField(ACC_PRIVATE, "_service", serviceDesc, null, null);
fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null);
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
av0.visit("name", serviceName);
av0.visit("name", "");
av0.visitEnd();
fv.visitEnd();
}
{ //_servicemap字段 Map<String, XXXService>
fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null);
fv.visitEnd();
}
{ //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
@@ -182,9 +184,34 @@ public final class Rest {
av0 = mv.visitAnnotation(authDesc, true);
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
Label lmapif = new Label();
mv.visitJumpInsn(IFNONNULL, lmapif);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
Label lserif = new Label();
mv.visitJumpInsn(GOTO, lserif);
mv.visitLabel(lmapif);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn(REST_HEADER_RESOURCE_NAME);
mv.visitLdcInsn("");
mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getHeader", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
mv.visitTypeInsn(CHECKCAST, serviceTypeString);
mv.visitLabel(lserif);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{serviceTypeString});
mv.visitVarInsn(ASTORE, 3);
final int maxStack = 3 + params.length;
List<int[]> varInsns = new ArrayList<>();
int maxLocals = 3;
int maxLocals = 4;
boolean hasVisitWebAction = false;
final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar;
int argIndex = 0;
@@ -495,8 +522,9 @@ public final class Rest {
actionMap.put("methods", entry.methods);
}
mv.visitVarInsn(ALOAD, 0); //调用this
mv.visitFieldInsn(GETFIELD, newDynName, "_service", serviceDesc);
//mv.visitVarInsn(ALOAD, 0); //调用this
//mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
mv.visitVarInsn(ALOAD, 3);
for (int[] ins : varInsns) {
mv.visitVarInsn(ins[0], ins[1]);
}

View File

@@ -19,9 +19,18 @@ import org.redkale.util.Sheet;
*/
public class HelloService implements Service {
private int nodeid;
@Resource
private DataSource source;
public HelloService() {
}
public HelloService(int nodeid) {
this.nodeid = nodeid;
}
//增加记录
public RetResult<HelloEntity> createHello(UserInfo info, HelloEntity entity) {
entity.setCreator(info == null ? 0 : info.getUserid()); //设置当前用户ID
@@ -37,7 +46,7 @@ public class HelloService implements Service {
//修改记录
public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
System.out.println("修改记录: clientAddr = " + clientAddr + ", entity =" + entity);
System.out.println("修改记录-" + nodeid + ": clientAddr = " + clientAddr + ", entity =" + entity);
if (entity != null) entity.setUpdatetime(System.currentTimeMillis());
if (source != null) source.update(entity);
}
@@ -66,4 +75,5 @@ public class HelloService implements Service {
public HelloEntity findHello(@RestParam("#") int id) { //通过 /hello/find/1234 查询对象
return source.find(HelloEntity.class, id);
}
}

View File

@@ -1,7 +1,6 @@
package org.redkale.test.rest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.net.http.*;
@@ -16,15 +15,16 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
@Resource
private HelloService _service;
@Resource
private Map<String, HelloService> _servicemap;
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/*");
server.addRestServlet(HelloService.class, "", service, SimpleRestServlet.class, "/pipes", null);
server.addRestServlet(HelloService.class, "my-res", new HelloService(3), SimpleRestServlet.class, "/pipes", null);
DefaultAnyValue conf = DefaultAnyValue.create("port", "" + port);
server.init(conf);
@@ -35,6 +35,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
entity.setHelloname("my name");
Map<String, String> headers = new HashMap<>();
headers.put("hello-res", "my res");
//headers.put(Rest.REST_HEADER_RESOURCE_NAME, "my-res");
String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}";
System.out.println(Utility.postHttpContent(url, headers, null));
@@ -43,68 +44,76 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
@AuthIgnore
@WebAction(url = "/hello/create")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
UserInfo user = currentUser(req);
RetResult<HelloEntity> result = _service.createHello(user, bean);
RetResult<HelloEntity> result = service.createHello(user, bean);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/delete/")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
_service.deleteHello(id);
service.deleteHello(id);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/update")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
String clientaddr = req.getRemoteAddr();
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
_service.updateHello(clientaddr, bean);
service.updateHello(clientaddr, bean);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/partupdate")
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
String[] cols = req.getJsonParameter(String[].class, "cols");
_service.updateHello(bean, cols);
service.updateHello(bean, cols);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/query")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
Flipper flipper = req.getFlipper();
Sheet<HelloEntity> result = _service.queryHello(bean, flipper);
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/list")
public void list(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
List<HelloEntity> result = _service.queryHello(bean);
List<HelloEntity> result = service.queryHello(bean);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/find/")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
HelloEntity bean = _service.findHello(id);
HelloEntity bean = service.findHello(id);
resp.finishJson(bean);
}
@AuthIgnore
@WebAction(url = "/hello/jsfind/")
public void jsfind(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
HelloEntity bean = _service.findHello(id);
HelloEntity bean = service.findHello(id);
resp.finishJsResult("varhello", bean);
}
}

View File

@@ -6,6 +6,7 @@
package org.redkale.test.rest;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
@@ -22,45 +23,53 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
@Resource
private HelloService2 _service;
@Resource
private Map<String, HelloService2> _servicemap;
@AuthIgnore
@WebAction(url = "/hello/create")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
UserInfo user = currentUser(req);
RetResult<HelloEntity> result = _service.createHello(user, bean);
RetResult<HelloEntity> result = service.createHello(user, bean);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/delete/")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
_service.deleteHello(id);
service.deleteHello(id);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/update")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
_service.updateHello(bean);
service.updateHello(bean);
resp.finishJson(RetResult.success());
}
@AuthIgnore
@WebAction(url = "/hello/query")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
Flipper flipper = req.getFlipper();
Sheet<HelloEntity> result = _service.queryHello(bean, flipper);
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
resp.finishJson(result);
}
@AuthIgnore
@WebAction(url = "/hello/find/")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
HelloEntity bean = _service.findHello(id);
HelloEntity bean = service.findHello(id);
resp.finishJson(bean);
}
}