java110
2023-06-07 e050a2ab2fa176ebd0d2461681a41df34838c028
add comment
9个文件已修改
1个文件已添加
143 ■■■■ 已修改文件
java110-core/src/main/java/com/java110/core/event/cmd/ServiceCmdEventPublishing.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-service/src/main/java/com/java110/service/api/CmdApi.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-service/src/main/java/com/java110/service/smo/ICmdServiceSMO.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-service/src/main/java/com/java110/service/smo/impl/CmdServiceSMOImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/controller/app/AppController.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/controller/package-info.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/smo/IApiServiceSMO.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/smo/api/IApiSMO.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/smo/api/impl/ApiSMOImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/java/com/java110/boot/smo/impl/ApiServiceSMOImpl.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-core/src/main/java/com/java110/core/event/cmd/ServiceCmdEventPublishing.java
@@ -110,6 +110,7 @@
     */
    public static void multicastEvent(ICmdDataFlowContext cmdDataFlowContext) throws Exception {
        Assert.notNull(cmdDataFlowContext.getServiceCode(), "当前没有可处理的业务信息!");
        //todo 根据cmd serviceCode 发布事件
        multicastEvent(cmdDataFlowContext.getServiceCode(), cmdDataFlowContext, null);
    }
@@ -132,8 +133,10 @@
     */
    public static void multicastEvent(String serviceCode, ICmdDataFlowContext dataFlowContext, String asyn) throws Exception {
        try {
            //todo 组装事件
            CmdEvent targetDataFlowEvent = new CmdEvent(serviceCode, dataFlowContext);
            //todo 发布事件
            multicastEvent(serviceCode, targetDataFlowEvent, asyn);
        } catch (Exception e) {
            logger.error("发布侦听失败,失败原因为:", e);
@@ -151,6 +154,7 @@
     * @param asyn  A 表示异步处理
     */
    public static void multicastEvent(String serviceCode, final CmdEvent event, String asyn) throws Exception {
        //todo 根据serviceCode 去寻找 处理的Cmd处理类 如果java类中 @Java110Cmd(serviceCode = "xx.xx") 写了该注解就会被寻找到
        List<ServiceCmdListener> listeners = getListeners(serviceCode);
        //这里判断 serviceCode + httpMethod 的侦听,如果没有注册直接报错。
        if (listeners == null || listeners.size() == 0) {
@@ -159,7 +163,7 @@
        }
        for (final ServiceCmdListener listener : listeners) {
            if (CommonConstant.PROCESS_ORDER_ASYNCHRONOUS.equals(asyn)) { //异步处理
            if (CommonConstant.PROCESS_ORDER_ASYNCHRONOUS.equals(asyn)) { //todo 异步处理,一般很少用
                Executor executor = getTaskExecutor();
                executor.execute(new Runnable() {
@@ -174,6 +178,7 @@
                });
                break;
            } else {
                // todo 通过同步的方式调用CMDjava类
                invokeListener(listener, event);
                break;
            }
@@ -192,7 +197,7 @@
    }
    /**
     * Invoke the given listener with the given event.
     * 执行 根据serviceCode 找到的cmd 类
     *
     * @param listener the ApplicationListener to invoke
     * @param event    the current event to propagate
@@ -201,15 +206,17 @@
    @SuppressWarnings({"unchecked", "rawtypes"})
    protected static void invokeListener(ServiceCmdListener listener, CmdEvent event) throws Exception {
        try {
            //        //这里处理业务逻辑数据
            //todo 获取 cmd 上下文对象
            ICmdDataFlowContext dataFlowContext = event.getCmdDataFlowContext();
            //获取请求数据
            //todo 获取请求数据
            JSONObject reqJson = dataFlowContext.getReqJson();
            logger.debug("API服务 --- 请求参数为:{}", reqJson.toJSONString());
            //todo 调用 cmd的校验方法
            listener.validate(event, dataFlowContext, reqJson);
            //todo 调用 cmd的业务处理方法
            listener.doCmd(event, dataFlowContext, reqJson);
            //logger.debug("API服务 --- 返回报文信息:{}", dataFlowContext.getResponseEntity());
java110-service/src/main/java/com/java110/service/api/CmdApi.java
@@ -41,6 +41,13 @@
    ISaveSystemErrorSMO saveSystemErrorSMOImpl;
    /**
     * 微服务 /cmd/xx.xx 接受类
     * @param service
     * @param postInfo
     * @param request
     * @return
     */
    @RequestMapping(path = "/{service:.+}", method = RequestMethod.POST)
    public ResponseEntity<String> service(@PathVariable String service,
                                          @RequestBody String postInfo,
@@ -48,17 +55,22 @@
        ResponseEntity<String> responseEntity = null;
        Map<String, String> headers = new HashMap<String, String>();
        try {
            //todo 头信息封装
            this.getRequestInfo(request, headers);
            //todo 将serviceCode 写入到头信息
            headers.put(CommonConstant.HTTP_SERVICE, service);
            //todo 将请求方式 写入到头信息
            headers.put(CommonConstant.HTTP_METHOD, CommonConstant.HTTP_METHOD_POST);
            logger.debug("api:{} 请求报文为:{},header信息为:{}", service, postInfo, headers);
            //todo 开始调用 cmd 类
            responseEntity = cmdServiceSMOImpl.cmd(postInfo, headers);
        } catch (Throwable e) {
            //todo 异常信息进行记录
            LogSystemErrorPo logSystemErrorPo = new LogSystemErrorPo();
            logSystemErrorPo.setErrId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_errId));
            logSystemErrorPo.setErrType(LogSystemErrorDto.ERR_TYPE_CMD);
            logSystemErrorPo.setMsg(ExceptionUtil.getStackTrace(e));
            //todo 日志
            saveSystemErrorSMOImpl.saveLog(logSystemErrorPo);
            logger.error("请求post 方法[" + service + "]失败:" + postInfo, e);
            responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
java110-service/src/main/java/com/java110/service/smo/ICmdServiceSMO.java
@@ -15,7 +15,7 @@
public interface ICmdServiceSMO {
    /**
     * 业务统一处理服务方法
     * cmd 调用 处理类
     * @param reqJson 请求报文json
     * @return
     */
java110-service/src/main/java/com/java110/service/smo/impl/CmdServiceSMOImpl.java
@@ -53,7 +53,7 @@
    /**
     * 服务调度
     * cmd 服务调度
     *
     * @param reqJson 请求报文json
     * @param headers
@@ -70,11 +70,11 @@
        ResponseEntity<String> responseEntity = null;
        //1.0 创建数据流 appId serviceCode
        //todo 1.0 创建数据流 appId serviceCode
        cmdDataFlowContext = DataFlowFactory.newInstance(CmdDataFlow.class).builder(reqJson, headers);
        //6.0 调用下游系统
        //todo 2.0 调用下游系统
        invokeBusinessSystem(cmdDataFlowContext);
        responseEntity = cmdDataFlowContext.getResponseEntity();
@@ -89,12 +89,13 @@
    /**
     * 6.0 调用下游系统
     * 2.0 调用下游系统
     *
     * @param cmdDataFlowContext
     * @throws BusinessException
     */
    private void invokeBusinessSystem(ICmdDataFlowContext cmdDataFlowContext) throws Exception {
        //todo 发布 cmd 事件
        ServiceCmdEventPublishing.multicastEvent(cmdDataFlowContext);
    }
springboot/src/main/java/com/java110/boot/controller/app/AppController.java
@@ -63,7 +63,7 @@
    private IPrivilegeSMO privilegeSMOImpl;
    /**
     * 资源请求 post方式
     * 资源请求 post方式 统一入口类
     * <p>
     * /app/user.listUser
     * <p>
@@ -86,12 +86,18 @@
        ResponseEntity<String> responseEntity = null;
        try {
            Map<String, String> headers = new HashMap<String, String>();
            //todo 封装请求中的 头信息
            this.getRequestInfo(request, headers);
            //todo 将接口编码(服务编码) 放入头信息 通过头信息的方式 传递到后端
            headers.put(CommonConstant.HTTP_SERVICE, service);
            // todo 请求方式 放入到头信息
            headers.put(CommonConstant.HTTP_METHOD, CommonConstant.HTTP_METHOD_POST);
            logger.debug("api:{} 请求报文为:{},header信息为:{}", service, postInfo, headers);
            //todo 获取由 PageProcessAspect aop 拦截封装的 pd 页面数据对象
            IPageData pd = (IPageData) request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA);
            //todo 根据登录用户 的权限 校验 用户是否有权限访问该接口,此时的"/app/" + service 为 开发这账户 菜单权限下的资源地址
            privilegeSMOImpl.hasPrivilege(restTemplate, pd, "/app/" + service);
            //todo 进入 接口相关 业务处理
            responseEntity = apiSMOImpl.doApi(postInfo, headers,request);
            //todo 写入 token
            wirteToken(request,pd,service,responseEntity);
@@ -105,7 +111,7 @@
    }
    /**
     * 资源请求 get方式
     * 资源请求 get方式 统一入口类
     *
     * @param service 请求接口方式
     * @param request 请求对象 查询头信息 url等信息
@@ -121,12 +127,18 @@
        ResponseEntity<String> responseEntity = null;
        try {
            Map<String, String> headers = new HashMap<String, String>();
            //todo 封装请求中的 头信息
            this.getRequestInfo(request, headers);
            //todo 将接口编码(服务编码) 放入头信息 通过头信息的方式 传递到后端
            headers.put(CommonConstant.HTTP_SERVICE, service);
            // todo 请求方式 放入到头信息
            headers.put(CommonConstant.HTTP_METHOD, CommonConstant.HTTP_METHOD_GET);
            logger.debug("api:{} 请求报文为:{},header信息为:{}", "", headers);
            //todo 获取由 PageProcessAspect aop 拦截封装的 pd 页面数据对象
            IPageData pd = (IPageData) request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA);
            //todo 根据登录用户 的权限 校验 用户是否有权限访问该接口,此时的"/app/" + service 为 开发这账户 菜单权限下的资源地址
            privilegeSMOImpl.hasPrivilege(restTemplate, pd, "/app/" + service);
            //todo 进入 接口相关 业务处理
            responseEntity = apiSMOImpl.doApi(JSONObject.toJSONString(getParameterStringMap(request)), headers, request);
        } catch (Throwable e) {
springboot/src/main/java/com/java110/boot/controller/package-info.java
New file
@@ -0,0 +1,16 @@
/**
 * 入口控制类
 *
 * // 1.0 系统基本入口类为 ./app/AppController 通过 servicePost  或者 serviceGet 拦截 请求
 * 请求地址为 /app/xxx.xxx  其中xxx.xxx 统称为 serviceCode  服务编码或者接口编码
 *
 * 数据流转流程: AppController.java下的servicePost 接受请求--->ApiSMOImpl.java下的doApi---> ApiServiceSMOImpl下的service方法 --> ApiServiceSMOImpl下的dealCmd方法
 * --->java110-service 模块下的 CmdApi 类 --->CmdServiceSMOImpl.java 的 cmd方法 ---> ServiceCmdListener.java 下的cmd 类 ---> 到具体的serviceCode 对应的cmd文件
 *
 * //2.0 支付 三方支付系统通知 统一有 ./app/payment 下的类来处理
 *
 * // 3.0 智能电表通知 通过 ./app/smartWeter 下的类来处理
 *
 * // 4.0 智能充电桩 通过./app/charge 下的类来处理
 */
package com.java110.boot.controller;
springboot/src/main/java/com/java110/boot/smo/IApiServiceSMO.java
@@ -12,7 +12,7 @@
public interface IApiServiceSMO {
    /**
     * 业务统一处理服务方法
     * 业务统一处理服务方法 应用是否有接口权限校验
     * @param reqJson 请求报文json
     * @return
     */
springboot/src/main/java/com/java110/boot/smo/api/IApiSMO.java
@@ -8,5 +8,13 @@
public interface IApiSMO {
    public ResponseEntity<String> doApi(String body, Map<String, String> headers, HttpServletRequest request) throws UnsupportedEncodingException;
    /**
     *  主要完成员工是否有访问小区的权限校验
     * @param body
     * @param headers
     * @param request
     * @return
     * @throws UnsupportedEncodingException
     */
     ResponseEntity<String> doApi(String body, Map<String, String> headers, HttpServletRequest request) throws UnsupportedEncodingException;
}
springboot/src/main/java/com/java110/boot/smo/api/impl/ApiSMOImpl.java
@@ -88,19 +88,17 @@
        IPageData pd = (IPageData) request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA);
        //todo 校验员工时 是否有访问小区的权限
        ComponentValidateResult result = this.validateStoreStaffCommunityRelationship(pd, restTemplate);
        //todo 如果 登录用户不为空 则将 前段传递的user-id 重写
        if (!StringUtil.isEmpty(result.getLoginUserId())) {
            headers.remove("user-id");
            headers.remove("user_id");
            headers.put("user-id", result.getUserId());
            headers.put("user_id", result.getUserId());
            headers.put("login-user-id",result.getLoginUserId());
//            if (!StringUtil.isEmpty(result.getUserName())) {
//                headers.put("user-name", URLEncoder.encode(result.getUserName(), "UTF-8"));
//            }
        }
        // todo 如果 商户不为空则 商户ID写入只头信息中 这里的商户ID 可以是物业ID 或者商家ID
        if (!StringUtil.isEmpty(result.getStoreId())) {
            headers.remove("store-id");
            headers.put("store-id", result.getStoreId());
@@ -113,6 +111,7 @@
            headers.put("user-id", "-1");
        }
        headers.put("store-id", result.getStoreId());
        // todo 应用是否有接口权限校验
        ResponseEntity<String> responseEntity = apiServiceSMOImpl.service(body, headers);
        return responseEntity;
    }
springboot/src/main/java/com/java110/boot/smo/impl/ApiServiceSMOImpl.java
@@ -85,21 +85,21 @@
        String resJson = "";
        try {
            //在post和 put 时才存在报文加密的情况
            //todo 在post和 put 时才存在报文加密的情况
            if ("POST,PUT".contains(headers.get(CommonConstant.HTTP_METHOD))) {
                reqJson = decrypt(reqJson, headers);
            }
            //1.0 创建数据流 appId serviceCode
            //todo 1.0 创建数据流 appId serviceCode
            dataFlow = DataFlowFactory.newInstance(ApiDataFlow.class).builder(reqJson, headers);
            //2.0 加载配置信息
            //todo 2.0 加载配置信息
            initConfigData(dataFlow);
            //3.0 校验 APPID是否有权限操作serviceCode
            //todo 3.0 校验 APPID是否有权限操作serviceCode
            judgeAuthority(dataFlow);
            //6.0 调用下游系统
            //todo 6.0 调用下游系统
            invokeBusinessSystem(dataFlow);
            responseEntity = dataFlow.getResponseEntity();
@@ -328,13 +328,13 @@
            DataFlowFactory.addCostTime(dataFlow, "judgeAuthority", "鉴权耗时", startDate);
            throw new NoAuthorityException(ResponseConstant.RESULT_CODE_NO_AUTHORITY_ERROR, "requestTime 格式不对,遵循yyyyMMddHHmmss格式");
        }
        //用户ID校验
        //todo 用户ID校验
        if (StringUtil.isNullOrNone(dataFlow.getUserId())) {
            throw new NoAuthorityException(ResponseConstant.RESULT_CODE_NO_AUTHORITY_ERROR, "USER_ID 不能为空");
        }
        //判断 AppId 是否有权限操作相应的服务
        //todo 判断 AppId 是否有权限操作相应的服务
        AppService appService = DataFlowFactory.getService(dataFlow, dataFlow.getRequestHeaders().get(CommonConstant.HTTP_SERVICE));
        //这里调用缓存 查询缓存信息
@@ -373,9 +373,9 @@
     */
    private void invokeBusinessSystem(ApiDataFlow dataFlow) throws BusinessException {
        Date startDate = DateUtil.getCurrentDate();
        //拿到当前服务
        //todo 拿到当前服务
        AppService appService = DataFlowFactory.getService(dataFlow, dataFlow.getRequestHeaders().get(CommonConstant.HTTP_SERVICE));
        //这里对透传类处理
        //todo 这里对透传类处理,目前很少用到,可以不用关注
        if ("NT".equals(appService.getIsInstance())) {
            //如果是透传类 请求方式必须与接口提供方调用方式一致
            String httpMethod = dataFlow.getRequestCurrentHeaders().get(CommonConstant.HTTP_METHOD);
@@ -386,8 +386,8 @@
            //dataFlow.setApiCurrentService(ServiceCodeConstant.SERVICE_CODE_DO_SERVICE_TRANSFER);
            doNT(appService, dataFlow, dataFlow.getReqJson());
            return;
        } else if ("T".equals(appService.getIsInstance())) {
            //如果是透传类 请求方式必须与接口提供方调用方式一致
        } else if ("T".equals(appService.getIsInstance())) { // todo 通过透传方式 调用 目前很少用到,可以不用关注
            //todo 如果是透传类 请求方式必须与接口提供方调用方式一致
            String httpMethod = dataFlow.getRequestCurrentHeaders().get(CommonConstant.HTTP_METHOD);
            if (!appService.getMethod().equals(httpMethod)) {
                throw new ListenerExecuteException(ResponseConstant.RESULT_CODE_ERROR,
@@ -395,13 +395,14 @@
            }
            doTransfer(appService, dataFlow, dataFlow.getReqJson());
            return;
        } else if ("CMD".equals(appService.getIsInstance())) {
        } else if ("CMD".equals(appService.getIsInstance())) { // todo 微服务调用方式,目前主要用这种方式调度分发 到不同的微服务,这里是通过c_service 中配置 调用到不同的微服务
            //如果是透传类 请求方式必须与接口提供方调用方式一致
            String httpMethod = dataFlow.getRequestCurrentHeaders().get(CommonConstant.HTTP_METHOD);
            if (!appService.getMethod().equals(httpMethod)) {
                throw new ListenerExecuteException(ResponseConstant.RESULT_CODE_ERROR,
                        "服务【" + appService.getServiceCode() + "】调用方式不对请检查,当前请求方式为:" + httpMethod);
            }
            // todo 根据接口编码找到 appService 也就是c_service 表中的内容
            dealCmd(appService, dataFlow, dataFlow.getReqJson());
            return;
        } else {
@@ -503,11 +504,11 @@
                oId = headers.get(OrderDto.O_ID).get(0);
            }
            //进入databus
            if (!CommonConstant.HTTP_METHOD_GET.equals(appService.getMethod())) {
                // dealDatabus(serviceCode, reqJson, oId);
            }
//            //进入databus
//            if (!CommonConstant.HTTP_METHOD_GET.equals(appService.getMethod())) {
//
//                // dealDatabus(serviceCode, reqJson, oId);
//            }
        } catch (HttpStatusCodeException e) { //这里spring 框架 在4XX 或 5XX 时抛出 HttpServerErrorException 异常,需要重新封装一下
@@ -545,12 +546,20 @@
        dataFlow.setResponseEntity(responseEntity);
    }
    /**
     * 开始调度微服务
     * @param appService
     * @param dataFlow
     * @param reqJson
     */
    private void dealCmd(AppService appService, ApiDataFlow dataFlow, JSONObject reqJson) {
        Map<String, String> reqHeader = dataFlow.getRequestCurrentHeaders();
        HttpHeaders header = new HttpHeaders();
        //todo 对头信息重新包装
        for (String key : dataFlow.getRequestCurrentHeaders().keySet()) {
            header.add(key, reqHeader.get(key));
        }
        //todo 用户信息再次包装
        if (reqHeader.containsKey(CommonConstant.USER_ID)
                && (!reqJson.containsKey("userId") || StringUtil.isEmpty(reqJson.getString("userId")))) {
            reqJson.put("userId", reqHeader.get(CommonConstant.USER_ID));
@@ -570,14 +579,18 @@
        serviceCode = serviceCode.startsWith("/") ? serviceCode : ("/" + serviceCode);
        //todo 组装调用微服务的地址
        String requestUrl = "http://127.0.0.1:8008/cmd" + serviceCode;
        //
        ResponseEntity responseEntity = null;
        //todo url 带了地址这里 拼接
        if (!StringUtil.isNullOrNone(orgRequestUrl)) {
            String param = orgRequestUrl.contains("?") ? orgRequestUrl.substring(orgRequestUrl.indexOf("?") + 1, orgRequestUrl.length()) : "";
            requestUrl += ("?" + param);
        }
        try {
            //todo http的方式调用微服务,相应的java类可以到相应微服务下的cmd下根据serviceCode 的寻找
            //todo 这里会调用到 java110-service 模块下的 CmdApi 类,这个类各个微服务都会集成
            responseEntity = outRestTemplate.exchange(requestUrl, HttpMethod.POST, httpEntity, String.class);
            HttpHeaders headers = responseEntity.getHeaders();
            String oId = "-1";
@@ -585,7 +598,7 @@
                oId = headers.get(OrderDto.O_ID).get(0);
            }
        } catch (HttpStatusCodeException e) { //这里spring 框架 在4XX 或 5XX 时抛出 HttpServerErrorException 异常,需要重新封装一下
        } catch (HttpStatusCodeException e) { //todo 这里spring 框架 在4XX 或 5XX 时抛出 HttpServerErrorException 异常,需要重新封装一下
            logger.error("请求下游服务【" + requestUrl + "】异常,参数为" + httpEntity + e.getResponseBodyAsString(), e);
            String body = e.getResponseBodyAsString();
@@ -603,7 +616,6 @@
        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            responseEntity = ResultVo.createResponseEntity(ResultVo.CODE_ERROR, String.valueOf(responseEntity.getBody()));
            dataFlow.setResponseEntity(responseEntity);
            return;
        }
        if (StringUtils.isEmpty(responseEntity.getBody() + "")) {