【仅供内部供应商使用,不提供对外解答和培训】
【仅供内部供应商使用,不提供对外解答和培训】
该文档为《跟我一起学代码》系列视频课程第三课的配套专题文档。视频课程主要向开发者介绍内网环境下的短信功能集成方法。该方法可扩展到内网下的私有化插件商城的实现。
内网短信集成:由SMSServiceProvider接口缺陷衍生的短信集成场景。SMSServiceProvider短信集成接口,仅仅提供了短信最终发送时的第三方短信服务集成。但要触发短信功能的前提是,要在决策平台开启短信功能,同时定时调度等功能和插件在调用短信列表时必须能够访问帆软的短信服务器,完成基于ID映射的短信调用。这就导致了如果决策系统服务器如果不通外网的情况下,就无法获取到相关的列表和开启短信功能。
插件商城私有化:集团化企业定制了一批符合自身业务规范的插件功能,但是这些功能本身并不符合帆软的商城插件标准,所以无法上架到公网商城。所以衍生了,企业希望能够自己建立自己的一个私有化的商城,相关的子公司服务器或设计器,直接连接这个私有化的商城实现插件的下载和安装。
(一)、相关链接
视频课程链接:待录制
(二)、方案介绍
抛开决策平台来思考这样的场景:“应用服务器原本要访问一个A服务器,现在要转而访问B服务器,A服务器本身我们无法控制”。
一般最常见的方案就是在网关上做代理转发,然后通过代理服务器来接收相应的请求,并作出业务响应。
本文中通过类比的方式把网关代理转发和代理服务器接收处理响应的思路借鉴过来,从而实现内网下的短信功能集成。
1、请求的转发设计
这里需要引入一个插件接口SiteTransformer【旧文档】,通过该接口把短信平台和帆软通行证相关的请求进行转发。
2、代理服务器接收并响应
本文讲述的是纯插件方案,所以这里选择了ControllerRegisterProvider接口来提供服务响应。
通过这两步转换,从而实现了原本要访问公网服务器的相关请求,全部转变为访问到内网决策平台服务器了。
注:本文使用的方案有一定的缺陷,如果某代理请求发起的时机在服务器启动较早阶段,此时插件引擎本身还未启动或spring的服务资源尚未初始化完成。则代理转换将会失效。所以更稳妥的方式是单独开发一个代理服务器来专门接收和处理转发过来的请求。
3、找到哪些请求要被代理
通过在SiteTransformer的match方法中打断点,然后在相关功能触发(一般都是在决策平台上操作,比如短信功能就是开启短信功能登录账号等操作)时,让后台断点生效,看一下具体要拦截的相关地址即可
通过这样的方法发现4个基本的请求要代理
https://market.fanruan.com/api/v1/ping
http://shop.finereport.com/api/v1/sms
http://api.shequ.fanruan.com/v1/user/login/
http://shop.finereport.com/api/v1/sms/user_info
通过服务接口把这四个请求都转发到决策平台服务器处理即可【注,这四个仅仅是基本的请求,其他请求用同样的方法即可定位到】
package com.tptj.demo.hg.third.sms; import com.fr.stable.StringUtils; import com.fr.stable.fun.impl.AbstractSiteTransformer; import java.util.HashMap; import java.util.Map; /** * @author 秃破天际 * @version 10.0 * Created by 秃破天际 on 2021/7/23 **/ public class Demo extends AbstractSiteTransformer { //请求转发到本地服务器 private static final String HOST = "http://localhost:8075/webroot/decision/shequ"; private static final Map<String,String> sites = new HashMap<String,String>(1); static{ //要转发的具体路由 sites.put("bbs.login.api","/v1/user/login/"); sites.put("sms_app","/v1/sms/"); sites.put("sms_info","/v1/sms/user_info"); sites.put("ping","/v1/ping"); } @Override public boolean match(String old) { return sites.containsKey(old); } @Override public String transform(String old){ return HOST + sites.get(old); } @Override public String transform() { return StringUtils.EMPTY; } }
注:本文中所示代码,仅用于简单教学演示使用!无法作为正式生产环境使用,生产环境使用需要开发者自行完善相关的结构、权限设计并且完善需要代理的请求
package com.tptj.demo.hg.third.sms; import com.fr.decision.webservice.annotation.LoginStatusChecker; import com.fr.general.GeneralUtils; import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.third.springframework.stereotype.Controller; import com.fr.third.springframework.web.bind.annotation.RequestMapping; import com.fr.third.springframework.web.bind.annotation.ResponseBody; import com.fr.web.utils.WebUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 秃破天际 * @version 10.0 * Created by 秃破天际 on 2021/7/23 **/ @Controller("SmsThirdSheQu") @RequestMapping(value = "/shequ") @LoginStatusChecker(required = false) public class DemoResource { @RequestMapping(value = "/**") @ResponseBody public void dispatcher( HttpServletRequest request, HttpServletResponse response ) throws Exception{ String info = request.getPathInfo(); String method = request.getMethod(); if( "/shequ/v1/user/login/".equals(info) ){ //内网下模拟帆软通行证登录 print(request,response,"{\"code\":200,\"message\":\"success\",\"data\":{\"access_token\":\"Um5rO7Ef5gvCqBWQw08LJkRilxtc4SGN\",\"expires_time\":1627015460,\"refresh_token\":\"HQqs6A9dTn1CElwP3tLJ4McX387pj2Uu\",\"refresh_expires_time\":1628217860,\"client\":{\"appid\":\"shequapp\",\"uid\":99999,\"username\":\"三方集成\"}},\"status\":0}"); }else if("/shequ/v1/sms/".equals(info) && "POST".equals(method)){ //内网下验证短信开启 print(request,response,"{\"status\":\"success\",\"data\":{\"app_key\":\"third_app_key\",\"app_secret\":\"third_app_secret\"}}"); }else if( "/shequ/v1/sms/user_info".equals(info) && "POST".equals(method) ){ //内网下获取短信模板 print( request, response, SMSUserInfo.DATA.toString() ); }else if( "/shequ/v1/ping".equals(info) ){ //内网下模拟在线 WebUtils.printAsString(response, StringUtils.EMPTY); } } private static void print(HttpServletRequest req, HttpServletResponse res, String response){ try{ JSONObject obj = new JSONObject(response); WebUtils.flushSuccessMessageAutoClose(req,res,obj); }catch(Exception e){ FineLoggerFactory.getLogger().error(e.getMessage(),e); } } }
4、利用SMSServiceProvider接口,进行第三方短信集成
免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。若作为商用一切后果责任由使用者自行承担。