前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud ApiController

Spring Cloud ApiController

作者头像
赵哥窟
发布2022-08-11 14:41:33
1880
发布2022-08-11 14:41:33
举报
文章被收录于专栏:日常技术分享日常技术分享

在Spring Cloud项目开发中,一般的目录结构

截屏2022-08-09 13.50.44.png

各个模块是做什么的就不用多说了,主要是web模块,比如我们实现一个登陆功能,首先要在Web模块下面新建一个LoginController,然后再后写接口层和实现层,然后我们需要查询用户又要新建一个UserController,新增加一个功能就要新建一个Controller,那么我不想建这么多的Controller,我想用一个Controller来统一调用接口可不可以,答案是可以。这就是我们接下来要讲的ApiController

ApiController

作用,不用每个功能都写一个Controller,只要写在一个公共的模块里面,其他模块引入就可以了

优点:因为是统一的Controller入口,所以可以做一些拦截,鉴权操作

下面只提供一些核心代码和思路供大家参考

代码语言:javascript
复制
@RestController
@RequestMapping({"/api"})
public class ApiController implements ApplicationContextAware {
    private static final Logger log = LoggerFactory.getLogger(ApiController.class);
    private ApplicationContext applicationContext;
    private static Map<String, Object> serviceCache = new HashMap();

    public ApiController() {
    }

    @CrossOrigin
    @RequestMapping(
            value = {"/{serviceName}/{method}"},
            method = {RequestMethod.POST}
    )

    /**
     * Api入口
     */
    public Object post(@PathVariable("serviceName") String serviceName, @PathVariable("method") String method, @RequestBody String params, HttpServletRequest request, HttpServletResponse response) {
        long startTime = System.currentTimeMillis();
        ServletThreadLocal.put(request, response);
        Object object = this.doService(serviceName, method, params);
        long executeTime = System.currentTimeMillis() - startTime;
        log.info("调用服务[{}.{}]执行时间:{}ms", new Object[]{serviceName, method, executeTime});
        return object;
    }

    /**
     * doService
     *
     * @param serviceName
     * @param method
     * @param params
     * @return
     */
    private Object doService(String serviceName, String method, String params) {
        Object serviceBean = this.getServiceBean(serviceName);
        Result commonResult = null;
        if (serviceBean == null) {
            commonResult = Result.fail(ResultCodeEnum.SERVICE_NOT_FOUND.getDesc());
            log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult.toString())});
            return commonResult;
        } else {
            Method currentMethod = this.getInvokeMethod(serviceBean, method);
            //方法不存在
            if (currentMethod == null) {
                commonResult = Result.fail(ResultCodeEnum.METHOD_NOT_FOUND.getDesc());
                log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult.toString())});
                return commonResult;
            } else {
                Type[] paramTypes = currentMethod.getGenericParameterTypes();
                if (paramTypes.length != 0 && paramTypes.length <= 1) {
                    CallTypeEnum callType = CallTypeEnum.REAL;
                    BaseParam baseParam = null;

                    try {
                        //获取入参
                        Object inputParam = JSONObject.parseObject(params, paramTypes[0]);
                        baseParam = (BaseParam) inputParam;
                        log.info("调用服务[{}.{}]请求参数:{}", new Object[]{serviceName, method, JSONObject.toJSONString(inputParam)});

                        callType = baseParam.getCallType();
                        //判断是真实调用还是mock调用,mock调用自己实现
                        if (callType == CallTypeEnum.REAL) {
                            //获取返回结果
                            Object callResult = currentMethod.invoke(serviceBean, inputParam);
                            //判断返回结果类型
                            if (!(callResult instanceof Result)) {
                                throw new RuntimeException("接口返回类型必须为[com.xxx.base.bean.Result]类型");
                            }
                            commonResult = (Result) callResult;
                            log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult)});
                            return commonResult;
                        }
                    } catch (Exception var17) {
                        commonResult = Result.buildFail(ResultCodeEnum.FAIL.getDesc());
                        log.error("服务[{}.{}]处理失败", new Object[]{serviceName, method, var17});
                    }
                } else {
                    log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, "服务定义形参个数只能为一个"});
                    return Result.buildFail("服务定义形参个数只能为一个");
                }
            }
        }
        return commonResult;
    }

    /**
     * 获取ServiceBean
     *
     * @param serviceName
     * @return
     */
    private Object getServiceBean(String serviceName) {
        Object serviceBean = serviceCache.get(serviceName);
        try {
            if (serviceBean == null) {
                if (serviceName.contains(".")) {
                    Class apiClass = null;

                    try {
                        apiClass = Class.forName(serviceName);
                        serviceBean = this.applicationContext.getBean(apiClass);
                    } catch (ClassNotFoundException var5) {
                        log.error("获取服务[" + serviceName + "]出错", var5);
                    } catch (Exception var6) {
                        log.error("获取服务[" + serviceName + "]出错", var6);
                    }
                } else {
                    serviceBean = this.applicationContext.getBean(serviceName);
                }
            }
        } catch (Exception var7) {
            log.error("获取服务[" + serviceName + "]出错", var7);
        }

        if (serviceBean != null) {
            serviceCache.put(serviceName, serviceBean);
        }
        return serviceBean;
    }

    /**
     * 获取方法
     *
     * @param serviceBean
     * @param method
     * @return
     */
    private Method getInvokeMethod(Object serviceBean, String method) {
        Method currentMethod = null;
        Method[] methods = serviceBean.getClass().getDeclaredMethods();
        Method[] var5 = methods;
        int var6 = methods.length;

        for (int var7 = 0; var7 < var6; ++var7) {
            Method method1 = var5[var7];
            if (method1.getName().equals(method)) {
                currentMethod = method1;
            }
        }

        return currentMethod;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
代码语言:javascript
复制
public class ServletThreadLocal {
    private static ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal();
    private static ThreadLocal<HttpServletResponse> responseThreadLocal = new ThreadLocal();

    public ServletThreadLocal() {
    }

    public static HttpServletRequest getRequest() {
        return (HttpServletRequest)requestThreadLocal.get();
    }

    public static HttpServletResponse getResponse() {
        return (HttpServletResponse)responseThreadLocal.get();
    }

    public static void putRequest(HttpServletRequest request) {
        requestThreadLocal.set(request);
    }

    public static void putResponse(HttpServletResponse response) {
        responseThreadLocal.set(response);
    }

    public static void put(HttpServletRequest request, HttpServletResponse response) {
        putRequest(request);
        putResponse(response);
    }
}

Api模块

代码语言:javascript
复制
public interface OrderServiceFacade {
    Result<OrderResult> getOrderById(OrderParam param);
}

Service模块

代码语言:javascript
复制
@Service("orderServiceFacade")
public class OrderServiceFacadeImpl implements OrderServiceFacade {

   @Resource
   OrderMainMapper orderMainMapper;

   @Override
   public Result<OrderResult> getOrderById(OrderParam param){
}

这样就不需要我们在写Controller了

接口调用

代码语言:javascript
复制
http://localhost:9091/api/orderServiceFacade/getOrderById
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ApiController
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档