目录

1、业务背景

2、代码示例

3、总结


1、业务背景

我们的一套H5应用程序前、后端只有一套部署,但是domain确有Fenqile、JiaoYiMao、Mp、ThunderMP、Thunder、Wifi这些域名解析,并且有扩展的需求,也就是说后期会继续增加新的渠道,在这种扩展性需求下,
必须考虑业务的扩展,所以利用了策略模式、模板模式对业务代码进行局部重构,代码片段主要着重关注登录login这一块业务,也就是说不同的域名其登录业务逻辑有区别。

示例代码使用到了:工厂方法模式、享元模式、模板方法模式,需要自己体会与思考。

2、代码示例

客户端调用代码:

@RestController
@Slf4j
@RequestMapping(UrlConstant.H5HomeControllerUrl.CONTROLLER_PREFIX)
public class H5HomeController extends BaseController {private static final String referer = "referer";@Autowiredprivate BannerService bannerService;@Autowiredprivate RedisOpenServiceImpl redisOpenService;@RequestMapping(UrlConstant.H5HomeControllerUrl.LOGIN)public Result login(HttpServletRequest request) {log.info("开始执行H5HomeController.login()方法,输入参数,request-headers:{},request-parameters:{}",RequestUtil.getHeadersInfoWithJsonStr(request, referer),JSONUtil.toJsonStr(request.getParameterMap()));this.parameterValidate(request);SubjectUtil.setIp(RequestUtil.getIpAdrress(request));String platformDomainStr = RequestUtil.getHost(request);Result result = null;try {PlatformConfigParamEnum platform = H5HomeServiceFactory.getInstance().getPlatform(platformDomainStr);RequestUtil.setPlatform(platform);AbsH5HomeService h5HomeService = H5HomeServiceFactory.getInstance().getInstance(platform);Map<String, String> parameterMap = RequestUtil.getParamerterMap(request);result = h5HomeService.login(parameterMap);} catch (Exception e) {log.error("执行H5HomeController.login()方法,出现异常, ", request, e);throw e;}log.info("结束执行H5HomeController.login()方法,返回值,result:{}", result);return result;}}

AbsH5HomeService是工厂方法返回的抽象产品类

  public AbsH5HomeService getInstance(PlatformConfigParamEnum platform) {if (null == platform) {log.error("空的platform");throw new H5LoginException(H5LoginException.ExceptionCode.CONFIGBEAN_IS_NULL);}Map<String, AbsH5HomeService> absH5HomeServiceMap = H5SpringUtil.getApplicationContext().getBeansOfType(AbsH5HomeService.class);for (AbsH5HomeService absH5HomeService : absH5HomeServiceMap.values()) {if (absH5HomeService.getPlatform() == platform) {return absH5HomeService;}}return defaultH5HomeService;}

H5HomeFenqileServiceImpl是AbsH5HomeService其中的一个渠道实现:分期乐渠道

package com.fulu.game.h5.service.impl.home;import java.util.Date;
import java.util.Map;import javax.annotation.PostConstruct;
import javax.annotation.Resource;import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.fulu.game.common.Result;
import com.fulu.game.common.enums.PlatformConfigParamEnum;
import com.fulu.game.common.enums.RedisKeyEnum;
import com.fulu.game.common.enums.PlatformConfigParamEnum.ConfigBean;
import com.fulu.game.common.exception.DataException;
import com.fulu.game.common.exception.LoginException;
import com.fulu.game.common.exception.ParamsException;
import com.fulu.game.common.utils.SubjectUtil;
import com.fulu.game.core.entity.User;
import com.fulu.game.h5.entity.bo.PlayUserToken;
import com.fulu.game.h5.service.AbsH5OrderService;
import com.fulu.game.h5.service.exception.H5LoginShiroException;
import com.fulu.game.h5.service.impl.order.FenqileH5OrderService;
import com.fulu.game.thirdparty.fenqile.entity.CodeSessionResult;
import com.fulu.game.thirdparty.fenqile.service.FenqileAuthService;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;@Slf4j
@Service
/*** * @function 分期乐实现* @date 2018年11月14日 下午1:31:45* @author 李桥* @version 1.0*/
public class H5HomeFenqileServiceImpl extends AbsH5HomeService
{@Resource (type = FenqileH5OrderService.class)private AbsH5OrderService fenqileAbsOrderOpenService;@Autowiredprivate FenqileAuthService fenqileAuthService;@Overridepublic Result loginSelfDefined (Map <String, String> requestMap){String code = requestMap.get (KeyConstant.code);CodeSessionResult session = null;try{session = fenqileAuthService.accessToken (code);log.info catch (Exception e);}catch (Exception e){log.error ("分期乐授权错误", e);return Result.noLogin().msg(LoginException.ExceptionCode.FENQILE_AUTH_ERROR.getMsg());}// 1.认证和凭据的tokenPlayUserToken playUserToken = PlayUserToken.newBuilder (super.platForm).fqlOpenid (session.getUid ()).accessToken (session.getAccessToken ()).build ();playUserToken.setHost (SubjectUtil.getIp ());("分期乐授权成功session:{}", session);}// 2.提交认证和凭据给身份验证系统try{User user = super.loginWithUpdate (playUserToken, true);Map <String, Object> result = BeanUtil.beanToMap (user);result.put (KeyConstant.token, SubjectUtil.getToken ());result.put (KeyConstant.userId, user.getId ());return Result.success ().data (result).msg ("登录成功!");}catch (H5LoginShiroException h5LoginShiroException){log.error ("h5LoginShiroException:{}", h5LoginShiroException);throw h5LoginShiroException;}catch (Exception e){log.error ("登录异常!", e);return Result.error ().msg ("登陆异常!");}}@Overridepublic void parameterValidateForLoginSelfDefined (Map <String, String> paraMap){String code = paraMap.get (KeyConstant.code);if (StringUtils.isBlank (code)){throw new ParamsException (ParamsException.ExceptionCode.PARAM_NULL_EXCEPTION);}}@Overridepublic Result submitOrder (Map <String, String> paraMap){// 第一步:获取参数并进行参数校验this.parameterValidateForSubmitOrder (paraMap);String productIdStr = paraMap.get (KeyConstant.productId);Integer productId = (Integer.parseInt (productIdStr));String numStr = paraMap.get (KeyConstant.num);Integer num = (Integer.parseInt (numStr));Date beginTime = DateUtil.parse (paraMap.get (KeyConstant.beginTime), "yyyy-MM-dd HH:mm:ss");String sessionkey = paraMap.get (KeyConstant.sessionkey);String couponNo = paraMap.get (KeyConstant.couponNo);Integer contactType = (Integer.parseInt (paraMap.get (KeyConstant.contactType)));String contactInfo = paraMap.get (KeyConstant.contactInfo);// 第二步:业务逻辑处理User user = userService.getCurrentUser ();if (!redisOpenService.hasKey (RedisKeyEnum.GLOBAL_FORM_TOKEN.generateKey (sessionkey))){log.error ("验证sessionkey错误:productId:{};num:{};couponNo:{};sessionkey:{};userId:{}", productId, num,couponNo, sessionkey, user.getId ());throw new DataException (DataException.ExceptionCode.NO_FORM_TOKEN_ERROR);}try{ConfigBean configBean =  super.platForm.getConfigBean ();Object[] paraObjectArray = new Object[]{ Integer.valueOf (productId), Integer.valueOf (num),beginTime, couponNo, SubjectUtil.getIp (), contactType,contactInfo, configBean };String orderNo = getAbOrderOpenServiceImpl ().submitOrderForAll (paraObjectArray);return Result.success ().data (orderNo).msg ("创建分期乐订单成功!");}finally{redisOpenService.delete (RedisKeyEnum.GLOBAL_FORM_TOKEN.generateKey (sessionkey));}}private void parameterValidateForSubmitOrder (Map <String, String> paraMap){String productIdStr = paraMap.get (KeyConstant.productId);if (StringUtils.isBlank (productIdStr)){log.error ("productId为空!");throw new ParamsException (ParamsException.ExceptionCode.PARAM_NULL_EXCEPTION);}String numStr = paraMap.get (KeyConstant.num);if (StringUtils.isBlank (numStr)){log.error ("num为空!");throw new ParamsException (ParamsException.ExceptionCode.PARAM_NULL_EXCEPTION);}String beginTimeStr = paraMap.get (KeyConstant.beginTime);if (StringUtils.isBlank (beginTimeStr)){log.error ("beginTimeStr为空!");throw new ParamsException (ParamsException.ExceptionCode.PARAM_NULL_EXCEPTION);}String sessionkey = paraMap.get (KeyConstant.sessionkey);if (StringUtils.isBlank (sessionkey)){log.error ("sessionkey为空!");throw new ParamsException (ParamsException.ExceptionCode.PARAM_NULL_EXCEPTION);}}@PostConstructprivate void init (){super.platForm = PlatformConfigParamEnum.FENQILE;super.absOrderOpenService= fenqileAbsOrderOpenService;}/** Key常量 */private static interface KeyConstant{String token = "token";String code = "code";String userId = "userId";String productId = "productId";String num = "num";String sessionkey = "sessionkey";String couponNo = "couponNo";String contactType = "contactType";String contactInfo = "contactInfo";String beginTime = "beginTime";}
package com.fulu.game.h5.service.impl.home;import com.fulu.game.common.Result;
import com.fulu.game.common.enums.PlatformConfigParamEnum;
import com.fulu.game.common.exception.OrderException;
import com.fulu.game.common.utils.RequestUtil;
import com.fulu.game.common.utils.SubjectUtil;
import com.fulu.game.core.entity.User;
import com.fulu.game.core.service.UserService;
import com.fulu.game.core.service.abs.AbsOrderOpenService;
import com.fulu.game.core.service.impl.RedisOpenServiceImpl;
import com.fulu.game.h5.entity.bo.PlayUserToken;
import com.fulu.game.h5.service.component.H5HomeServiceFactory;
import com.fulu.game.h5.service.exception.H5LoginException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Map;@Service
@Slf4j
public abstract class AbsH5HomeService {@Autowiredprotected H5HomeServiceFactory h5HomeServiceFactory;@Autowiredprotected UserService userService;@Autowiredprotected RedisOpenServiceImpl redisOpenService;@Autowiredprotected RedisOpenServiceImpl redisOpenServiceImpl;protected PlatformConfigParamEnum platForm;protected AbsOrderOpenService absOrderOpenService;/*** @function 每个渠道自定义的登录逻辑* @date 2018年11月9日 上午10:40:40* @author 李桥* @version 1.0*/protected abstract Result loginSelfDefined(Map<String, String> requestMap);public PlatformConfigParamEnum getPlatform() {return platForm;}/*** @function 校验参数的合法性, 子类可以按自己的需求进行覆盖* @date 2018年11月8日 下午2:16:39* @author 李桥* @version 1.0*/protected abstract void parameterValidateForLoginSelfDefined(Map<String, String> paraMap);public Result login(Map<String, String> requestMap) {log.info("开始执行AbsH5HomeService.login()方法,入参,platform:{},requestMap:{}", RequestUtil.getPlatform().name(),requestMap);PlatformConfigParamEnum platform = RequestUtil.getPlatform();if (null == platform) {throw new H5LoginException(H5LoginException.ExceptionCode.CONFIGBEAN_IS_NULL);}this.parameterValidateForLoginSelfDefined(requestMap);return this.loginSelfDefined(requestMap);}}

3、总结

局部重构之后,每次进行扩展新渠道域名时,方便方便,只需要增加一个新的Platform枚举项,一个新的AbsH5HomeService 实现,对原文渠道无任何影响。

记录策略模式模板模式的一次应用过程相关推荐

  1. 设计模式之策略模式+工厂模式+模板模式结合

    设计模式之策略模式+模板模式 为什么总是学不好设计模式 从"登录功能"中发现问题. 首先我们简单的了解功能需求: 于是你开始干活了: 1.控制层代码如下,根据不同的登录方式调用不同 ...

  2. Java设计模式之策略模式+工厂模式+模板模式

    Java设计模式之策略模式+工厂模式+模板模式 1.策略模式+工厂模式+模板模式 个人的理解:实际开发工程中,一些业务很复杂的逻辑使用很多的 if 或者 if···else 语句,不利于维护和扩展,为 ...

  3. 常用设计模式-策略模式+工厂模式+模板模式(使用场景、解决方案)

    在策略模式+工厂模式中,没有使用到模板模式,因为张三和李四的业务逻辑都是调用AAA方法,如果现在在增加一个方法,次方法只需要李四一人去实现BBB方法,此时张三的handel中就会报错,需要张三也去实现 ...

  4. 行为模式(模板模式命令模式备忘录模式)

    目录 模板方法模式(Template) 介绍 实现 命令模式(Command) 介绍 实现 备忘录模式(Memento) 介绍 实现 模板方法模式(Template) 一个抽象类公开定义了执行它的方法 ...

  5. 第十三章行为型模式—模板模式

    文章目录 模板模式 解决的问题 结构 实例 存在的问题 适用场景 JDK源码 - InputStream 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对 ...

  6. 模板方法模式(模板模式)——钩子方法

    豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程选材->添加配料->浸泡->放到豆浆机打碎 通过添加不同的配料,可以制作出不同口味的豆浆 选材.浸泡和放到豆浆机打碎这几个 ...

  7. Java设计模式(七)策略模式 模板模式

    (十三)策略模式 策略图案限定了多个封装算法,该算法可以相互替换包.法的客户.借用还有一位大神的样例. interface ICalculator{public int calculate(Strin ...

  8. 精妙绝伦的设计模式:策略模式+模板模式+工厂模式

    还是以经典的会员价格策略为依托场景: 一.首先加入maven依赖,此依赖用于扫描并获取特定含有特定注解的类 二.定义个一个自定义注解,用来定义并判断价格区间 三.写一个策略接口类,用于定义获取折后价格 ...

  9. 设计模式学习笔记(二)工厂模式、模板模式和策略模式的混合使用

    一.工厂模式(Factory pattern) 工厂模式又叫做工厂方法模式,是一种创建型设计模式,一般是在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 1.1 工厂模式介绍 工厂模式是 ...

最新文章

  1. DOS批处理的字符串功能
  2. 计算机专业术语lcd,LCD的专业术语.pdf
  3. MySQL 联合查询实质_1.多表查询 = 转化为一张联合大表 2.可视化工具 3.pymysql模块...
  4. java提高篇之理解java的三大特性——多态
  5. cf1556E. Equilibrium
  6. (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  7. 力扣46. 全排列(JavaScript)
  8. 零信任时代,开放式安全沙箱让管控更灵活
  9. 希捷服务器硬盘格式化不了,希捷硬盘专用分区格式化Seagate DiscWizard16.0 官方版...
  10. android手机屏分辨率和屏幕逻辑,手机屏幕分辨率术语:逻辑分辨率和物理分辨率...
  11. c52传感器温度显示c语言编程,单片机中使用DS18B20温度传感器C语言程序
  12. android 自定义locale,关于android:设置Locale.setDefault(locale)后,如何获取手机语言?...
  13. Datahero inc智能合约技术重塑供应链金融模式
  14. 大华技术股份有限公司测开笔试题分享
  15. 触摸屏单个按键远程控制led
  16. airpods二代降噪吗_小白初次入手AirPods,究竟有怎样的体验呢?
  17. BloomFilter怎么用?使用布隆过滤器来判断key是否存在?
  18. micropython gui_T-Watch手表初试micropython之电子秤教程
  19. 奥巴马胜选演说·文言版
  20. 《Euclidea3》-Eta-07

热门文章

  1. 关于Knuth的八卦
  2. VR开发基础—VR视频
  3. 进化计算之遗传算法的简单介绍
  4. win7农行证书解决办法
  5. 2021年茶艺师(中级)考试及茶艺师(中级)新版试题
  6. 蟠桃记c语言当输入0结束循环,杭电OJ第11页2010-2019道题(C语言)
  7. 自制编程语言crowbar(v0.1)构建解析器时分配内存
  8. 仓库管理系统是什么?具备哪些功能?如何选择?
  9. 【电信学】【2009.06】基于实验数据的参考MIMO天线构型性能研究
  10. LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping