android基于注解实现类似spring服务端框架

用过spring或Retrofit的人都知道实现函数和http请求的绑定和解耦非常方便,这里分享一下基于NanoHttpd实现的简单注解框架。
第一步定义注解类:

//http控制类,被该注解的类用来处理http请求
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {
    //路径前缀,有此前缀的请求会使用此类处理
    String name() default "/"; 
    boolean needPermissonControl() default true;
}
//被该注解的方法用来一个处理http请求
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestMapping {
    //匹配的路径
    String path() default "";
    Method method() default Method.GET;
}
//该注解用于函数的参数,用于绑定请求的参
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
    //参数名
    String name() default "";
    //参数默认值
    String value() default "";
}

第二步,实现serverlet时注册Controll类

@Override
public void addController(Class<?> controller) {
    // has controller annotation
    if (controller.isAnnotationPresent(Controller.class)) {
        Controller controllerAnnotation = controller.getAnnotation(Controller.class);
        String name = controllerAnnotation.name();
        boolean needPermissionControl = controllerAnnotation.needPermissonControl();
        Method[] methods = controller.getDeclaredMethods();
        // get all request mapping annotation
        for (Method method : methods) {
            if (method.isAnnotationPresent(RequestMapping.class)) {
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                String path = requestMapping.path();
                org.nanohttpd.protocols.http.request.Method m = requestMapping.method();
                // build full path
                String fullPath = name + File.separatorChar + path;
                // getparams
                ArrayList<Param> params = new ArrayList<>();
                Annotation[][] paramAnnotation = method.getParameterAnnotations();
                for (Annotation[] an : paramAnnotation) {
                    if (an.length > 0) {
                        Param p = (Param)an[0];
                        params.add(p);
                    }
                }
                RequestMappingParams requestMappingParams = new RequestMappingParams();
                requestMappingParams.path = fullPath;
                requestMappingParams.handler = controller;
                requestMappingParams.method = m;
                requestMappingParams.methodReflect = method;
                requestMappingParams.params = params;
                requestMappingParams.needPermissionControl = needPermissionControl;
                addRoute(requestMappingParams);
            }
        }
    }
}

大概思路是在注册时,找到Controller注解的uri路径前缀,还有有RequestMapping注解的函数,将路径对应上函数方法,然后在请求来时匹配到该路径就调用对应用的方法,下面是匹配到路径时的处理:

private Response processController(Object object, Map<String, String> urlParams, IHTTPSession session) throws InvocationTargetException, IllegalAccessException {
    if (requestMappingParams.needPermissionControl) {
        if (!AppNanolets.PermissionEntries.isRemoteAllow(session.getRemoteIpAddress())) {
            return Response.newFixedLengthResponse("not allow");
        }
    }
    //匹配请求方法
    if (requestMappingParams.method != session.getMethod()) {
        return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, "text/plain", "method not supply");
    }
    ArrayList<Object> params = new ArrayList<>();
    Map<String, List<String>> requestParams = session.getParameters();
    if (requestParams != null) {
        //获取对应http请求参数
        Type[] types = requestMappingParams.methodReflect.getGenericParameterTypes();
        for (int i = 0; i < requestMappingParams.params.size(); i++) {
            Param p = requestMappingParams.params.get(i);
            if (!TextUtils.isEmpty(p.name())) {
                List<String> values = requestParams.get(p.name());
                if (values != null && values.size() > 0) {
                    String v = values.get(0);
                    Type t = types[i];
                    params.add(valueToObject(t, v));
                } else {
                    params.add(p.value());
                }
            }
        }
    }
    //调用方法
    return (Response)requestMappingParams.methodReflect.invoke(object, params.toArray());
}

下面是Controller的一个实例:

@Controller(name = "filemanager")
public class FileManagerHandler {
    @RequestMapping(path= "list")
    public Response list(@Param(name = "dir", value = "/sdcard") String path) {
        if (TextUtils.isEmpty(path)) {
            path = Environment.getExternalStorageDirectory().getAbsolutePath();
        }
        Dir d = new Dir(new java.io.File(path));
        String json = JSON.toJSONString(d);
        Response response = Response.newFixedLengthResponse(Status.OK, "application/json", json);
        response.addHeader("Access-Control-Allow-Origin", "*");
        return response;
    }

上面的Controller匹配路径前缀是filemanager就是http://host/filemanager/xxx?xxx这样的的请求都会使用此类来处理,然后有个list方法处理http://host/filemanager/list?xxx请求,请求参数只有一个dir又参数,默认值是/sdcard,就是没传参时会使用此值传入函数。
全部代码在github:Enlarge-Android

这里使用注解的方法是调用反射,性能上会有所降低,可以使用另外一种基于注解自动生成代码的方法提高性能。使用注解来绑定http请求好处相当明显,如果不使用注解,那么要处理http请求时需要类实现或继承http请求处理类,并重写请求处理的方法,以达到得到处理的时机再做相关的逻辑处理,这样的代码显然多了很多也不灵活。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值