All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.ubibi.jettyboot.framework.rest.RestControllerHandler Maven / Gradle / Ivy

package cn.ubibi.jettyboot.framework.rest;

import cn.ubibi.jettyboot.framework.commons.BeanUtils;
import cn.ubibi.jettyboot.framework.commons.StringUtils;
import cn.ubibi.jettyboot.framework.rest.impl.RestTextRender;
import com.alibaba.fastjson.JSON;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class RestControllerHandler {

    private static Logger logger = Log.getLogger(RestControllerHandler.class);


    private Class restControllerClazz;
    private Object restController;
    private String path;

    public RestControllerHandler(String path, Class clazz) {
        this.restControllerClazz = clazz;
        this.path = path;
    }

    public RestControllerHandler(String path, Object restController) {
        this.restController = restController;
        this.path = path;
    }


    public boolean handle(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String reqPath = request.getPathInfo();

        if (this.path!=null && !this.path.isEmpty() && !reqPath.startsWith(this.path)) {
            return false;
        }


        Class clazz = this.getControllerClass();


        String[] classPathList = this.getClassPaths();
        for (String classPath : classPathList) {

            if (isMatchClassPath(reqPath, classPath)) {

                Method[] methods = clazz.getMethods();
                if (methods != null) {
                    for (Method method : methods) {

                        RestGetMapping methodAnnotation1 = method.getAnnotation(RestGetMapping.class);
                        RestPostMapping methodAnnotation2 = method.getAnnotation(RestPostMapping.class);
                        RestMapping methodAnnotation3 = method.getAnnotation(RestMapping.class);
                        boolean handleResult = false;
                        if (methodAnnotation1 != null) {
                            handleResult = handleMethodPath(classPath, methodAnnotation1.path(), methodAnnotation1.method(), request, response, method);
                        } else if (methodAnnotation2 != null) {
                            handleResult = handleMethodPath(classPath, methodAnnotation2.path(), methodAnnotation2.method(), request, response, method);
                        } else if (methodAnnotation3 != null) {
                            handleResult = handleMethodPath(classPath, methodAnnotation3.path(), methodAnnotation3.method(), request, response, method);
                        }

                        if (handleResult) {
                            return true;
                        }
                    }
                }
            }
        }


        //路径不匹配
        return false;
    }


    private Class getControllerClass() {
        Class clazz = this.restControllerClazz;
        if (clazz == null) {
            clazz = this.restController.getClass();
        }
        return clazz;
    }

    private String[] getClassPaths() {
        if (this.path != null && !this.path.isEmpty()) {
            return new String[]{this.path};
        }
        Class clazz = this.getControllerClass();
        RestMapping classRestMappings = clazz.getAnnotation(RestMapping.class);
        if (classRestMappings != null && classRestMappings.path() != null) {
            return classRestMappings.path();
        }
        return new String[]{"/"};
    }


    private boolean handleMethodPath(String classPath, String[] path2, String method, HttpServletRequest request, HttpServletResponse response, Method methodFunc) throws Exception {
        if (method.equalsIgnoreCase(request.getMethod())) {

            String reqPath = request.getPathInfo();

            for (String path22 : path2) {
                String path = pathJoin(classPath, path22);
                boolean isMethodMatchOK = isHandleMethodPath(path, reqPath);
                if (isMethodMatchOK) {
                    handleMethod(request, response, methodFunc, path);
                    return true;
                }
            }
        }

        return false;
    }


    private void handleMethod(HttpServletRequest request, HttpServletResponse response, Method method, String targetPath) throws Exception {


        Object controller = this.restController;
        if (controller == null) {
            controller = restControllerClazz.newInstance();
        }

        Object invokeResult;
        try {
            Type[] paramsTypes = method.getGenericParameterTypes();
            Object[] paramsObjects = getParamsObjects(paramsTypes, request, response, targetPath);
            invokeResult = method.invoke(controller, paramsObjects);
        } catch (Exception e) {
            throw e;
        }

        if (invokeResult instanceof IRestRender) {
            ((IRestRender) invokeResult).doRender(request, response);
        } else if (invokeResult instanceof String) {
            new RestTextRender(invokeResult.toString()).doRender(request, response);
        } else {
            String jsonString = JSON.toJSONString(invokeResult);
            new RestTextRender(jsonString).doRender(request, response);
        }
    }


    private boolean isHandleMethodPath(String configPath, String reqPath) {
        if (configPath.equals(reqPath)) {
            return true;
        }

        //   /user/:id
        //   /user/23332
        List path1Array = removeEmpty(configPath.split("/"));
        List path2Array = removeEmpty(reqPath.split("/"));
        if (path1Array.size() != path2Array.size()) {
            return false;
        }

        for (int i = 0; i < path1Array.size(); i++) {
            String pp1 = path1Array.get(i);
            String pp2 = path2Array.get(i);
            if (!isPathEquals(pp1, pp2)) {
                return false;
            }
        }

        return true;
    }

    private boolean isPathEquals(String configPath, String pp2) {
        if (configPath.equals(pp2)) {
            return true;
        }

        if (configPath.startsWith(":")) {
            return true;
        }

        return false;
    }


    private String pathJoin(String path1, String path2) {

        List path1Arr = removeEmpty(path1.split("/"));
        List path2Arr = removeEmpty(path2.split("/"));


        List pathList = new ArrayList<>();

        pathList.addAll(path1Arr);
        pathList.addAll(path2Arr);

        String result = "/" + StringUtils.join(pathList, "/");
        return result;
    }


    private boolean isMatchClassPath(String reqPath, String classPath) {
        if (classPath == null || classPath.isEmpty() || "/".equals(classPath)) {
            return true;
        }

        if (reqPath.equals(classPath)) {
            return true;
        }

        if (reqPath.startsWith(classPath)) {
            return true;
        }


        List reqPathArray = removeEmpty(reqPath.split("/"));
        List classPathArray = removeEmpty(classPath.split("/"));

        if (classPathArray.size() > reqPathArray.size()) {
            return false;
        }

        int classPathArraySize = classPathArray.size();
        for (int i = 0; i < classPathArraySize; i++) {
            String classPathArrI = classPathArray.get(i);
            String reqPathArrI = reqPathArray.get(i);
            if (!classPathArrI.equals(reqPathArrI)) {
                return false;
            }
        }

        return true;
    }

    private List removeEmpty(String[] split) {
        List result = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            String s = split[i];
            if (s != null && !s.isEmpty()) {
                result.add(s);
            }
        }
        return result;
    }


    private Object[] getParamsObjects(Type[] paramsTypes, HttpServletRequest request, HttpServletResponse response, String targetPath) throws Exception {

        //同一个请求中只有一个ReqParams实例
        ReqParams jettyBootReqParams = getRestParams(request, targetPath);

        List objects = new ArrayList();

        for (Type type : paramsTypes) {


            if (IReqBodyParser.class.isAssignableFrom((Class) type)) {
                Object obj = ((Class) type).newInstance();

                try {
                    BeanUtils.copyField(obj, jettyBootReqParams.getRequestBodyObject(obj.getClass()));
                } catch (IOException e) {
                    e.printStackTrace();
                }

                objects.add(obj);

            } else if (IReqParamParser.class.isAssignableFrom((Class) type)) {

                Object obj = ((Class) type).newInstance();
                BeanUtils.copyField(obj, jettyBootReqParams.getRequestParamObject(obj.getClass()));
                objects.add(obj);

            } else if (IReqParser.class.isAssignableFrom((Class) type)) {

                Class clazz = (Class) type;
                IReqParser m = (IReqParser) clazz.newInstance();

                m.doParse(jettyBootReqParams, request, targetPath);

                objects.add(m);

            } else if (type.equals(ServletRequest.class) || type.equals(HttpServletRequest.class)) {
                objects.add(request);
            } else if (type.equals(ServletResponse.class) || type.equals(HttpServletResponse.class)) {
                objects.add(response);
            } else if (type.equals(ReqParams.class)) {
                objects.add(jettyBootReqParams);
            } else {
                objects.add(null);
            }
        }

        return objects.toArray();
    }


    private ReqParams getRestParams(HttpServletRequest request, String targetPath) {
        ReqParams jettyBootReqParams = (ReqParams) request.getAttribute("jettyBootReqParams");
        if (jettyBootReqParams == null) {
            jettyBootReqParams = new ReqParams(request, targetPath);
            request.setAttribute("jettyBootReqParams", jettyBootReqParams);
        }
        return jettyBootReqParams;
    }
}