当前位置:   article > 正文

快速应用模板方法设计模式_模版模式使用

模版模式使用

目录

前言

基本理解与应用举例

业务应用

业务失败重试机制

基本模版代码

具体业务处理

使用及测试展示

测试代码

 使用框架实现业务失败重试机制

业务前置检查流程模版

基本代码依赖

模版代码准备

业务应用前置检查

业务实现

测试及结果展示

基本常规业务处理模版

分页处理模版

滚动处理模版

业务使用模版定义

业务模拟服务

具体模拟业务

测试及展示

业务处理统一相关处理模版

基本的业务处理模版BizTemplate

支持SpringValidator的业务处理模版

没有入参调用的业务处理模版

没有返回参数调用的业务处理模版

业务使用举例


干货分享,感谢您的阅读!

前言

模版模式应该是工作中最常用的设计模式之一,直白的讲就是如果的一些处理方式是有一定的模版流程处理的,那么在应用中使用该模式在合适不过了。对于其基本的业务应用,我简单写了以下三个基本的通用模版(业务失败重试机制、业务前置检查流程模版、Thrift远程调用处理模版)来展示,有问题的可以留言纠正,谢谢!相关源码见:ZYF基本练习

基本理解与应用举例

GoF《设计模式》一书中,定义如下:

    Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

基本结合业务使用可以翻译为:模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。算法骨架,其实就是指的我们定义的业务处理流程模版。

应用举例平时在看源码的时候基本都可以看到,比方说以下的几个举例:

  • spring 中 Hibernate 比如开启事务、获取 Session、关闭 Session 等规范化流程的设计和实现;
  • HttpServlet的service()模板方法,定义了整个HTTP请求的执行流程,doGet()、doPost()是模板中可以由子类来定制的部分;
  • Java IO类库中,比如InputStream、OutputStream、Reader、Writer的设计都使用了模板模式

业务应用

实际中只有业务上有很固定的流程基本都可以使用模版模式进行定义和解决问题,这边的就我自身来看,具体的业务的一定不方便拿出来举例,所以暂时想了以下三个业务场景较为公用的拿出来与大家分享,有需要纠正的请大家留言纠正。

业务失败重试机制

我们在实际业务处理中经常会遇到调用远程方法如果因为超时或一些其他原因失败的话,最好在进行重试调用一次,而重试简单的来看主要的模版流程基本有按业务实际调用失败后规定休眠一段时间后再次重试一次,如果超过重试次数则返回报错,如果中间重试成功则按成功的处理,所以我们可以简单的写一个业务失败重试机制的模版

基本模版代码

  1. package org.zyf.javabasic.designpatterns.strategy.template.retry;
  2. import lombok.extern.log4j.Log4j2;
  3. /**
  4. * @author yanfengzhang
  5. * @description 模板方式处理重试逻辑
  6. * @date 2022/3/15 00:13
  7. */
  8. @Log4j2
  9. public abstract class RetryTemplate<R> {
  10. /**
  11. * 默认重试次数
  12. */
  13. private static final int DEFAULT_RETRY_TIME = 1;
  14. /**
  15. * 定义重试次数
  16. */
  17. private int retryTime = DEFAULT_RETRY_TIME;
  18. /**
  19. * 重试的睡眠时间
  20. */
  21. private int sleepMills = 0;
  22. /**
  23. * 业务处理的睡眠时间
  24. *
  25. * @return 睡眠时间
  26. */
  27. public int getSleepMills() {
  28. return sleepMills;
  29. }
  30. /**
  31. * 获取重试次数
  32. *
  33. * @return 重试次数
  34. */
  35. public int getRetryTime() {
  36. return retryTime;
  37. }
  38. /**
  39. * 规定业务处理的睡眠时间
  40. *
  41. * @param sleepMills 睡眠时间(毫秒)
  42. * @return 重试模版
  43. */
  44. public RetryTemplate<R> setSleepMills(int sleepMills) {
  45. if (sleepMills < 0) {
  46. throw new IllegalArgumentException("sleepMills should equal or bigger than 0");
  47. }
  48. this.sleepMills = sleepMills;
  49. return this;
  50. }
  51. /**
  52. * 规定业务处理的重试次数
  53. *
  54. * @param retryTime 业务处理的重试次数
  55. * @return 重试模版
  56. */
  57. public RetryTemplate<R> setRetryTime(int retryTime) {
  58. if (retryTime <= 0) {
  59. throw new IllegalArgumentException("retryTime should bigger than 0");
  60. }
  61. this.retryTime = retryTime;
  62. return this;
  63. }
  64. /**
  65. * 重试的业务执行代码
  66. * 失败时请抛出一个异常
  67. */
  68. protected abstract Object doBiz() throws Exception;
  69. /**
  70. * 重试的主要业务逻辑
  71. *
  72. * @return 实际业务处理返回内容
  73. * @throws InterruptedException 中断异常
  74. */
  75. public R execute() throws InterruptedException {
  76. for (int i = 0; i < retryTime; i++) {
  77. try {
  78. return (R) doBiz();
  79. } catch (Exception e) {
  80. log.warn("业务执行出现异常,e: ", e);
  81. Thread.sleep(sleepMills);
  82. }
  83. }
  84. return null;
  85. }
  86. }

具体业务处理

  1. package org.zyf.javabasic.designpatterns.strategy.template.retry;
  2. import com.google.common.collect.Maps;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.commons.lang3.StringUtils;
  5. import org.springframework.stereotype.Service;
  6. import java.util.Map;
  7. import java.util.Random;
  8. /**
  9. * @author yanfengzhang
  10. * @description
  11. * @date 2022/3/15 00:20
  12. */
  13. @Service
  14. @Slf4j
  15. public class RetryBizService {
  16. private static Map<Integer, String> aphorisms = Maps.newHashMap();
  17. static {
  18. aphorisms.put(1, "知人者智,自知者明。胜人者有力,自胜者强。——老子");
  19. aphorisms.put(2, "要知道对好事的称颂过于夸大,也会招来人们的反感轻蔑和嫉妒。——培根");
  20. aphorisms.put(5, "业精于勤,荒于嬉;行成于思,毁于随。——韩愈");
  21. aphorisms.put(7, "最大的骄傲于最大的自卑都表示心灵的最软弱无力。——斯宾诺莎");
  22. aphorisms.put(9, "知之者不如好之者,好之者不如乐之者。——孔子");
  23. }
  24. /**
  25. * 获取名言警句
  26. *
  27. * @return 名言警句
  28. */
  29. public String getAphorisms() throws Exception {
  30. int randomNumber = new Random().nextInt(10);
  31. String rersult = aphorisms.get(randomNumber);
  32. if (StringUtils.isBlank(rersult)) {
  33. throw new Exception("抱歉!系统异常,暂无数据可进行返回!randomNumber=" + randomNumber);
  34. }
  35. return rersult;
  36. }
  37. }

使用及测试展示

测试代码

  1. package org.zyf.javabasic.designpatterns.strategy.template.retry;
  2. import com.github.rholder.retry.RetryException;
  3. import com.github.rholder.retry.Retryer;
  4. import com.github.rholder.retry.RetryerBuilder;
  5. import com.github.rholder.retry.StopStrategies;
  6. import com.github.rholder.retry.WaitStrategies;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.junit.Test;
  10. import org.junit.runner.RunWith;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.boot.test.context.SpringBootTest;
  13. import org.springframework.test.context.junit4.SpringRunner;
  14. import org.zyf.javabasic.ZYFApplication;
  15. import java.util.Objects;
  16. import java.util.concurrent.Callable;
  17. import java.util.concurrent.ExecutionException;
  18. import java.util.concurrent.TimeUnit;
  19. /**
  20. * @author yanfengzhang
  21. * @description
  22. * @date 2022/3/2022/3/15 00:23
  23. */
  24. @RunWith(SpringRunner.class)
  25. @SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  26. @Slf4j
  27. public class RetryTemplateTest {
  28. @Autowired
  29. private RetryBizService retryBizService;
  30. @Test
  31. public void testRetryBizService() {
  32. String aphorisms = null;
  33. try {
  34. aphorisms = (String) new RetryTemplate() {
  35. @Override
  36. protected Object doBiz() throws Exception {
  37. return retryBizService.getAphorisms();
  38. }
  39. }.setRetryTime(3).setSleepMills(200).execute();
  40. } catch (Exception e) {
  41. log.warn("[RetryBizService名言警句展示] 系统系统进行重试调用失败!");
  42. }
  43. if (StringUtils.isEmpty(aphorisms)) {
  44. log.error("[RetryBizService名言警句展示异常,请稍后重试]");
  45. return;
  46. }
  47. log.info("测试成功,得到的名言警句为:{}", aphorisms);
  48. }
  49. }

测试结果展示

 使用框架实现业务失败重试机制

但是实际中,以上的实现还是较为简单,比如像高并发等场景基本没有进行考虑,所以实际应用中我建议使用guava的重试模版进行处理比较好

引入pom

  1. <!-- 引入对应的guava重试机制相关功能 -->
  2. <dependency>
  3. <groupId>com.github.rholder</groupId>
  4. <artifactId>guava-retrying</artifactId>
  5. <version>2.0.0</version>
  6. </dependency>

使用及测试展示

  1. package org.zyf.javabasic.designpatterns.strategy.template.retry;
  2. import com.github.rholder.retry.RetryException;
  3. import com.github.rholder.retry.Retryer;
  4. import com.github.rholder.retry.RetryerBuilder;
  5. import com.github.rholder.retry.StopStrategies;
  6. import com.github.rholder.retry.WaitStrategies;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.junit.Test;
  10. import org.junit.runner.RunWith;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.boot.test.context.SpringBootTest;
  13. import org.springframework.test.context.junit4.SpringRunner;
  14. import org.zyf.javabasic.ZYFApplication;
  15. import java.util.Objects;
  16. import java.util.concurrent.Callable;
  17. import java.util.concurrent.ExecutionException;
  18. import java.util.concurrent.TimeUnit;
  19. /**
  20. * @author yanfengzhang
  21. * @description
  22. * @date 2022/3/2022/3/15 00:23
  23. */
  24. @RunWith(SpringRunner.class)
  25. @SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  26. @Slf4j
  27. public class RetryTemplateTest {
  28. @Autowired
  29. private RetryBizService retryBizService;
  30. @Test
  31. public void testGuavaRetrying() {
  32. Callable<String> callable = () -> {
  33. /*业务逻辑*/
  34. return retryBizService.getAphorisms();
  35. };
  36. /*定义重试器*/
  37. Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
  38. /*如果结果为空则重试*/
  39. .retryIfResult(Objects::isNull)
  40. /*发生IO异常则重试*/
  41. .retryIfExceptionOfType(Exception.class)
  42. /*发生运行时异常则重试*/
  43. .retryIfRuntimeException()
  44. /*等待*/
  45. .withWaitStrategy(WaitStrategies.incrementingWait(100, TimeUnit.MILLISECONDS,
  46. 100, TimeUnit.MILLISECONDS))
  47. /*允许执行4次(首次执行 + 最多重试3次)*/
  48. .withStopStrategy(StopStrategies.stopAfterAttempt(4))
  49. .build();
  50. try {
  51. /*执行*/
  52. String aphorisms = retryer.call(callable);
  53. if (StringUtils.isEmpty(aphorisms)) {
  54. log.error("[RetryBizService名言警句展示异常,请稍后重试]");
  55. return;
  56. }
  57. log.info("测试成功,得到的名言警句为:{}", aphorisms);
  58. } catch (RetryException | ExecutionException e) {
  59. /*重试次数超过阈值或被强制中断*/
  60. log.warn("[RetryBizService名言警句展示] 系统系统进行重试调用失败!");
  61. }
  62. }
  63. }

业务前置检查流程模版

平时我们对于业务的基本入参可能会有一些指定的业务检查流程需要检查,比方依次有基础参数检查、业务逻辑检查、冲突关联检查、验证码校验、二次弹窗校验等,于是将其整合一下即可有业务前置检查流程模版。

基本代码依赖

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. /**
  5. * @author yanfengzhang
  6. * @description 校验基本返回结构
  7. * @date 2022/3/16 23:29
  8. */
  9. @Data
  10. @Builder
  11. public class CheckResponse {
  12. /**
  13. * 成功标志:true-校验通过,false-校验未通过
  14. */
  15. private boolean pass;
  16. /**
  17. * 校验码
  18. */
  19. private Integer code;
  20. /**
  21. * 未通过原因
  22. */
  23. private String errorMsg;
  24. }

模版代码准备

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.stereotype.Service;
  4. /**
  5. * @author yanfengzhang
  6. * @description 业务数据校验模版
  7. * @date 2022/3/16 23:35
  8. */
  9. @Slf4j
  10. @Service
  11. public abstract class BizCheckTemplate<P> {
  12. /**
  13. * 校验全流程模版
  14. *
  15. * @param param 基本入参
  16. * @return 校验结果
  17. * @throws Exception 业务异常
  18. */
  19. public CheckResponse checkProcess(P param) {
  20. /*1.基础参数校验*/
  21. CheckResponse checkResponse = checkParam(param);
  22. if (!checkResponse.isPass()) {
  23. return checkResponse;
  24. }
  25. /*2.业务逻辑校验*/
  26. checkResponse = checkBiz(param);
  27. if (!checkResponse.isPass()) {
  28. return checkResponse;
  29. }
  30. /*3.冲突关联校验*/
  31. checkResponse = checkConflict(param);
  32. if (!checkResponse.isPass()) {
  33. return checkResponse;
  34. }
  35. /*4.验证码校验*/
  36. checkResponse = checkVerifyCode(param);
  37. if (!checkResponse.isPass()) {
  38. return checkResponse;
  39. }
  40. /*5.二次弹窗校验*/
  41. checkResponse = checkTwicePopup(param);
  42. if (!checkResponse.isPass()) {
  43. return checkResponse;
  44. }
  45. return checkResponse;
  46. }
  47. protected abstract CheckResponse checkParam(P param);
  48. protected abstract CheckResponse checkBiz(P param);
  49. protected abstract CheckResponse checkTwicePopup(P param);
  50. protected abstract CheckResponse checkVerifyCode(P param);
  51. protected abstract CheckResponse checkConflict(P param);
  52. }

业务应用前置检查

假如有一个申诉的业务系统,其需要进行以上前置的检查处理,我们定义其基本检查的实现类如下:

申诉提交检查

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. /**
  6. * @author yanfengzhang
  7. * @description 申诉内容创建检查
  8. * @date 2022/3/16 20:24
  9. */
  10. @Service
  11. @Slf4j
  12. public class AppealCreateCheck extends BizCheckTemplate<AppealMatters> {
  13. @Autowired
  14. private AppealCheckService appealCheckService;
  15. /**
  16. * 申诉内容参数检查
  17. *
  18. * @param param 请求参数信息
  19. * @return 校验结果
  20. */
  21. @Override
  22. protected CheckResponse checkParam(AppealMatters param) {
  23. if (!param.getType().equals(1)) {
  24. /*为了用于测试*/
  25. return CheckResponse.builder().pass(false).errorMsg("新增申诉内容类型不符合要求!").build();
  26. }
  27. return CheckResponse.builder().pass(true).build();
  28. }
  29. /**
  30. * 申诉内容业务逻辑检查
  31. *
  32. * @param param 请求参数信息
  33. * @return 校验结果
  34. */
  35. @Override
  36. protected CheckResponse checkBiz(AppealMatters param) {
  37. /*业务检查1:申诉的内容编码是唯一的,当前重复申诉*/
  38. /*业务检查2:申诉的内容项不得包含非法指定的相关内容*/
  39. /*业务检查3:申诉人对应的申诉项中和申诉人当前享有的权益不匹配*/
  40. return CheckResponse.builder().pass(true).build();
  41. }
  42. /**
  43. * 申诉二次弹窗检查(不涉及直接返回通过)
  44. *
  45. * @param param 请求参数信息
  46. * @return 校验结果
  47. */
  48. @Override
  49. protected CheckResponse checkTwicePopup(AppealMatters param) {
  50. return CheckResponse.builder().pass(true).build();
  51. }
  52. /**
  53. * 申诉验证码校验(不涉及直接返回通过)
  54. *
  55. * @param param 请求参数信息
  56. * @return 校验结果
  57. */
  58. @Override
  59. protected CheckResponse checkVerifyCode(AppealMatters param) {
  60. return CheckResponse.builder().pass(true).build();
  61. }
  62. /**
  63. * 申诉关联冲突校验
  64. *
  65. * @param param 请求参数信息
  66. * @return 校验结果
  67. */
  68. @Override
  69. protected CheckResponse checkConflict(AppealMatters param) {
  70. return appealCheckService.checkConflict(param);
  71. }
  72. }

申诉修改检查

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. /**
  6. * @author yanfengzhang
  7. * @description 申诉内容修改检查
  8. * @date 2022/3/16 23:43
  9. */
  10. @Service
  11. @Slf4j
  12. public class AppealUpdateCheck extends BizCheckTemplate<AppealMatters> {
  13. @Autowired
  14. private AppealCheckService appealCheckService;
  15. /**
  16. * 申诉内容参数检查
  17. *
  18. * @param param 请求参数信息
  19. * @return 校验结果
  20. */
  21. @Override
  22. protected CheckResponse checkParam(AppealMatters param) {
  23. if (!param.getType().equals(2)) {
  24. /*为了用于测试*/
  25. return CheckResponse.builder().pass(false).errorMsg("修改申诉内容类型不符合要求!").build();
  26. }
  27. return CheckResponse.builder().pass(true).build();
  28. }
  29. /**
  30. * 申诉内容业务逻辑检查
  31. *
  32. * @param param 请求参数信息
  33. * @return 校验结果
  34. */
  35. @Override
  36. protected CheckResponse checkBiz(AppealMatters param) {
  37. /*业务检查1:申诉的内容编码不能修改*/
  38. /*业务检查2:申诉的内容项已进行处理的不能在修改,新增的申诉项不得包含非法指定的相关内容*/
  39. /*业务检查3:新增的申诉项中,申诉人对应的申诉项中和申诉人当前享有的权益不匹配*/
  40. return CheckResponse.builder().pass(true).build();
  41. }
  42. /**
  43. * 申诉二次弹窗检查
  44. *
  45. * @param param 请求参数信息
  46. * @return 校验结果
  47. */
  48. @Override
  49. protected CheckResponse checkTwicePopup(AppealMatters param) {
  50. /*二次弹窗检查检查1:申诉的内容存在修改次数,请确认是否修改*/
  51. return CheckResponse.builder().pass(true).build();
  52. }
  53. /**
  54. * 申诉验证码校验
  55. *
  56. * @param param 请求参数信息
  57. * @return 校验结果
  58. */
  59. @Override
  60. protected CheckResponse checkVerifyCode(AppealMatters param) {
  61. /*验证码校验检查1:修改操作需本人进行验证码确认*/
  62. return CheckResponse.builder().pass(true).build();
  63. }
  64. /**
  65. * 申诉关联冲突校验
  66. *
  67. * @param param 请求参数信息
  68. * @return 校验结果
  69. */
  70. @Override
  71. protected CheckResponse checkConflict(AppealMatters param) {
  72. return appealCheckService.checkConflict(param);
  73. }
  74. }

申诉删除检查

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. /**
  6. * @author yanfengzhang
  7. * @description 申诉内容删除检查
  8. * @date 2022/3/16 23:44
  9. */
  10. @Service
  11. @Slf4j
  12. public class AppealDeleteCheck extends BizCheckTemplate<Long> {
  13. @Autowired
  14. private AppealCheckService appealCheckService;
  15. /**
  16. * 申诉内容参数检查
  17. *
  18. * @return 校验结果
  19. * @id id 请求参数信息
  20. */
  21. @Override
  22. protected CheckResponse checkParam(Long id) {
  23. if (!checkPosInteger(id)) {
  24. return CheckResponse.builder().pass(false).errorMsg("申诉内容id不合法!").build();
  25. }
  26. /*id必须为有效ID*/
  27. return CheckResponse.builder().pass(true).build();
  28. }
  29. /**
  30. * 申诉内容业务逻辑检查
  31. *
  32. * @return 校验结果
  33. * @id id 请求参数信息
  34. */
  35. @Override
  36. protected CheckResponse checkBiz(Long id) {
  37. /*业务检查1:申诉的内容必须存在*/
  38. /*业务检查2:申诉的内容项全部处理完成的不能删除*/
  39. /*业务检查3:申诉人当前享有的权益存在需要进行续费的暂时不能删除申诉内容*/
  40. return CheckResponse.builder().pass(true).build();
  41. }
  42. /**
  43. * 申诉二次弹窗检查
  44. *
  45. * @return 校验结果
  46. * @id id 请求参数信息
  47. */
  48. @Override
  49. protected CheckResponse checkTwicePopup(Long id) {
  50. /*二次弹窗检查检查1:申请确认是否删除*/
  51. /*二次弹窗检查检查2:相关未享受的权益删除后不再享有,申请确认是否删除*/
  52. return CheckResponse.builder().pass(true).build();
  53. }
  54. /**
  55. * 申诉验证码校验
  56. *
  57. * @return 校验结果
  58. * @id id 请求参数信息
  59. */
  60. @Override
  61. protected CheckResponse checkVerifyCode(Long id) {
  62. /*验证码校验检查1:修改操作需本人进行验证码确认*/
  63. return CheckResponse.builder().pass(true).build();
  64. }
  65. /**
  66. * 申诉关联冲突校验(不涉及直接返回通过)
  67. *
  68. * @return 校验结果
  69. * @id id 请求参数信息
  70. */
  71. @Override
  72. protected CheckResponse checkConflict(Long id) {
  73. return CheckResponse.builder().pass(true).build();
  74. }
  75. /**
  76. * ID信息合法性:必须为正整数
  77. *
  78. * @param id id信息
  79. * @return true-合法;false-非法
  80. */
  81. public static boolean checkPosInteger(Long id) {
  82. return null != id && id > 0L;
  83. }
  84. }

公用检查

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.springframework.stereotype.Service;
  5. import java.util.Objects;
  6. /**
  7. * @author yanfengzhang
  8. * @description 申诉基本校验检查(公用)
  9. * @date 2022/3/16 23:40
  10. */
  11. @Service
  12. @Slf4j
  13. public class AppealCheckService {
  14. /**
  15. * 公用的创建和修改必要参数检查
  16. *
  17. * @param param 必要参数信息
  18. * @return 检查结果
  19. */
  20. public CheckResponse checkParam(AppealMatters param) {
  21. if (Objects.isNull(param)) {
  22. return CheckResponse.builder().pass(false).errorMsg("创建消息不能为空!").build();
  23. }
  24. if (StringUtils.isBlank(param.getCode())) {
  25. return CheckResponse.builder().pass(false).errorMsg("申诉编码不能为空!").build();
  26. }
  27. if (Objects.isNull(param.getType())) {
  28. return CheckResponse.builder().pass(false).errorMsg("申诉类型不能为空且必须为规定的类型!").build();
  29. }
  30. return CheckResponse.builder().pass(true).build();
  31. }
  32. /**
  33. * 公用的创建和修改关联冲突校验
  34. *
  35. * @param param 请求参数信息
  36. * @return 检查结果
  37. */
  38. public CheckResponse checkConflict(AppealMatters param) {
  39. /*关联冲突检查1:申诉的内容对应的申诉类型在当前系统指定暂停办理中,请进行替换*/
  40. /*关联冲突检查2:申诉的内容项直接存在相同申诉问题,请重新归类提交*/
  41. /*关联冲突检查3:申诉的内容项与实际享有权益存在冲突,请确认避免后续被系统锁定*/
  42. /*关联冲突检查4:申诉人当前存在其他非法内容,则本次提交需解决之前的内容*/
  43. return CheckResponse.builder().pass(true).build();
  44. }
  45. }

业务实现

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. /**
  6. * @author yanfengzhang
  7. * @description 申诉相关业务逻辑
  8. * @date 2022/3/16 22:02
  9. */
  10. @Service
  11. @Slf4j
  12. public class AppealService {
  13. @Autowired
  14. private AppealCheckService appealCheckService;
  15. @Autowired
  16. private AppealCreateCheck appealCreateCheck;
  17. @Autowired
  18. private AppealUpdateCheck appealUpdateCheck;
  19. @Autowired
  20. private AppealDeleteCheck appealDeleteCheck;
  21. /**
  22. * 申诉内容留档
  23. *
  24. * @param appealMatters 申诉内容
  25. */
  26. public void saveAppealMatters(AppealMatters appealMatters) throws Exception {
  27. /*1.基本必要参数检查*/
  28. CheckResponse checkResponse = appealCheckService.checkParam(appealMatters);
  29. if (!checkResponse.isPass()) {
  30. throw new Exception(checkResponse.getErrorMsg());
  31. }
  32. /*2.实际业务操作*/
  33. if (checkPosInteger(appealMatters.getId())) {
  34. checkResponse = appealCreateCheck.checkProcess(appealMatters);
  35. if (!checkResponse.isPass()) {
  36. throw new Exception(checkResponse.getErrorMsg());
  37. }
  38. /*业务处理,省略*/
  39. }
  40. checkResponse = appealUpdateCheck.checkProcess(appealMatters);
  41. if (!checkResponse.isPass()) {
  42. throw new Exception(checkResponse.getErrorMsg());
  43. }
  44. /*业务处理,省略*/
  45. }
  46. /**
  47. * 申诉内容留档
  48. *
  49. * @param appealMattersId 申诉内容id
  50. */
  51. public void deleteAppealMatters(Long appealMattersId) throws Exception {
  52. /*1.基本必要参数检查*/
  53. CheckResponse checkResponse = appealDeleteCheck.checkProcess(appealMattersId);
  54. if (!checkResponse.isPass()) {
  55. throw new Exception(checkResponse.getErrorMsg());
  56. }
  57. /*业务处理,省略*/
  58. }
  59. /**
  60. * ID信息合法性:必须为正整数
  61. *
  62. * @param id id信息
  63. * @return true-合法;false-非法
  64. */
  65. public static boolean checkPosInteger(Long id) {
  66. return null != id && id > 0L;
  67. }
  68. }

测试及结果展示

  1. package org.zyf.javabasic.designpatterns.strategy.template.check;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import org.springframework.test.context.junit4.SpringRunner;
  8. import org.zyf.javabasic.ZYFApplication;
  9. import java.util.Arrays;
  10. import java.util.List;
  11. /**
  12. * @author yanfengzhang
  13. * @description
  14. * @date 2022/3/17 00:15
  15. */
  16. @RunWith(SpringRunner.class)
  17. @SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  18. @Slf4j
  19. public class BizCheckTemplateTest {
  20. @Autowired
  21. private AppealService appealService;
  22. @Test
  23. public void testAppealService() throws Exception {
  24. List<String> appealItems = Arrays.asList("隔壁搬来的邻居真他妈的吵!", "小区的健身房器械就不能在多一些练腿的?");
  25. AppealMatters appealMatters = AppealMatters.builder()
  26. .code("shvhf2736gbbnvhbb")
  27. .declarant("zyf")
  28. .type(2)
  29. .appealItems(appealItems).build();
  30. log.info("测试新建");
  31. appealService.saveAppealMatters(appealMatters);
  32. log.info("测试更新");
  33. appealMatters.setId(7L);
  34. appealMatters.setType(2);
  35. appealService.saveAppealMatters(appealMatters);
  36. log.info("测试删除");
  37. appealService.deleteAppealMatters(7L);
  38. }
  39. }

结果展示

 Thrift远程调用处理模版

平时可能在使用调用thrift接口的时候往往会使用分页获取调用或者使用滚动的方式进行处理,我们针对这样的业务场景页也共用的定义一套业务模版去处理,具体如下:

基本常规业务处理模版

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import com.google.common.collect.Lists;
  3. import lombok.Data;
  4. import lombok.extern.slf4j.Slf4j;
  5. import java.util.List;
  6. import java.util.Objects;
  7. /**
  8. * @author yanfengzhang
  9. * @description 业务thrift调用基本类
  10. * * TC : thrift请求
  11. * * TR : thrift返回
  12. * * FR : 业务实际真正要的处理结果
  13. * @date 2022/3/18 23:18
  14. */
  15. @Data
  16. @Slf4j
  17. public abstract class ThriftInvokeCommand<TC, TR, FR> {
  18. /**
  19. * thrift请求
  20. */
  21. protected TC command;
  22. /**
  23. * 每个命令最多翻滚多少页
  24. */
  25. private int maxPageCount = ConfigUtils.getThriftScrollMaxPageLimit();
  26. /**
  27. * 每个命令的最大重试个数
  28. */
  29. private int maxRetryCount = ConfigUtils.getThriftMaxInvokeRetryCount();
  30. /**
  31. * 每个命令的休眠时间
  32. */
  33. private int sleepMs = ConfigUtils.getThriftScrollRate();
  34. /**
  35. * 每个命令的查询页数
  36. */
  37. private int pageSize = ConfigUtils.getThriftScrollPageSize();
  38. public ThriftInvokeCommand(TC command) {
  39. this.command = command;
  40. }
  41. /**
  42. * 核心处理逻辑:获取指定结果
  43. */
  44. public List<FR> getResult() {
  45. /*执行的页数*/
  46. int currPageNo = 0;
  47. /*command 设置 pageSize*/
  48. setPageSize(command, pageSize);
  49. /*调用接口的失败次数*/
  50. int errorCount = 0;
  51. TR thriftResult = null;
  52. List<FR> rList = Lists.newArrayList();
  53. while (true) {
  54. try {
  55. /*1.前置处理*/
  56. preHandle();
  57. /*2.业务转发调用*/
  58. thriftResult = invoke(command);
  59. /*3.从thriftResult提取结果并转换为实际需要的*/
  60. rList.addAll(convertThriftResult(thriftResult));
  61. /*4.后置处理*/
  62. afterHandle(thriftResult);
  63. } catch (Exception e) {
  64. log.error("", e);
  65. errorCount++;
  66. }
  67. /*thrift调用无结果则直接停止循转*/
  68. if (Objects.isNull(thriftResult) || 0 == getResultSize(thriftResult)) {
  69. break;
  70. }
  71. if (errorCount >= maxRetryCount || currPageNo >= maxPageCount) {
  72. String msg = errorCount >= maxRetryCount ? "重试次数过多,已达最大尝试次数:" + maxRetryCount : "循环次数过多,已达最大尝试次数:" + maxPageCount;
  73. log.warn("ThriftInvokeCommand 处理警告:{}", msg);
  74. break;
  75. }
  76. currPageNo++;
  77. /*5.停顿,降低调用频率*/
  78. sleepInvoke();
  79. }
  80. return rList;
  81. }
  82. /**
  83. * thrift调用前置处理
  84. */
  85. protected abstract void preHandle();
  86. /**
  87. * thrift调用后置处理
  88. *
  89. * @param thriftResult thrift调用结果
  90. */
  91. protected abstract void afterHandle(TR thriftResult);
  92. /**
  93. * 核心逻辑, 通过命令获取结果
  94. *
  95. * @param command thrift调用请求
  96. * @return thrift调用结果
  97. */
  98. protected abstract TR invoke(TC command) throws Exception;
  99. /**
  100. * command 设置 pageSize
  101. */
  102. protected abstract void setPageSize(TC command, int pageSize);
  103. /**
  104. * 从 thriftResult 获取 结果长度,若是 0 ,那么 break 退出
  105. */
  106. protected abstract int getResultSize(TR thriftResult);
  107. /**
  108. * 从 thriftResult 提取结果
  109. */
  110. protected abstract List<FR> convertThriftResult(TR thriftResult);
  111. /**
  112. * 休眠调整处理
  113. */
  114. private void sleepInvoke() {
  115. if (sleepMs <= 0) {
  116. return;
  117. }
  118. try {
  119. Thread.sleep(sleepMs);
  120. } catch (InterruptedException ignored) {
  121. }
  122. }
  123. public ThriftInvokeCommand setPageSize(int pageSize) {
  124. this.pageSize = pageSize;
  125. return this;
  126. }
  127. public ThriftInvokeCommand setSleepMs(int sleepMs) {
  128. this.sleepMs = sleepMs;
  129. return this;
  130. }
  131. }

分页处理模版

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. /**
  3. * @author yanfengzhang
  4. * @description 用于利用分页形式滚动调用thrift
  5. * @date 2022/3/18 23:25
  6. */
  7. public abstract class ThriftInvokePageCommand<TC, TR, FR> extends ThriftInvokeCommand<TC, TR, FR> {
  8. private int pageNo = 1;
  9. public ThriftInvokePageCommand(TC command) {
  10. super(command);
  11. }
  12. @Override
  13. public void preHandle() {
  14. /*command 设置 pageNo*/
  15. setPageNo(command, pageNo);
  16. }
  17. @Override
  18. public void afterHandle(TR thriftResult) {
  19. /*页数加 1*/
  20. pageNo++;
  21. }
  22. /**
  23. * command 设置 pageNo
  24. */
  25. protected abstract void setPageNo(TC command, int pageNo);
  26. }

滚动处理模版

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. /**
  3. * @author yanfengzhang
  4. * @description 用于利用scroll形式滚动调用thrift
  5. * @date 2022/3/18 23:23
  6. */
  7. public abstract class ThriftInvokeScrollCommand<TC, TR, FR> extends ThriftInvokeCommand<TC, TR, FR> {
  8. private Long scrollId = 0L;
  9. public ThriftInvokeScrollCommand(TC command) {
  10. super(command);
  11. }
  12. @Override
  13. public void preHandle() {
  14. /*command 设置 ScrollId*/
  15. setScrollId(command, scrollId);
  16. }
  17. @Override
  18. public void afterHandle(TR thriftResult) {
  19. /*从 thriftResult 获取 scrollId*/
  20. scrollId = getNextScrollId(thriftResult);
  21. }
  22. /**
  23. * command 设置 ScrollId
  24. */
  25. protected abstract void setScrollId(TC command, Long scrollId);
  26. /**
  27. * 从 thriftResult 获取 scrollId
  28. */
  29. protected abstract Long getNextScrollId(TR thriftResult);
  30. }

业务使用模版定义

假设获取电影资源thrift有两套模版基本如下

获取电影thrift接口分页处理

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.collections.CollectionUtils;
  4. import org.assertj.core.util.Lists;
  5. import java.util.List;
  6. import java.util.Objects;
  7. import java.util.stream.Collectors;
  8. /**
  9. * @author yanfengzhang
  10. * @description 获取电影thrift接口分页处理
  11. * @date 2022/3/18 23:32
  12. */
  13. @Slf4j
  14. public class GetMoviesByConditionPage extends ThriftInvokePageCommand<MoviesConditions, MoviesResult, MovieBasicInfo> {
  15. /**
  16. * 实际thrift接口(此处只做模拟)
  17. * 实际该处应该类似为:private MoviesInfoThriftService.Iface moviesInfoThriftService;
  18. */
  19. private MoviesInfoThriftService moviesInfoThriftService;
  20. /**
  21. * 实际分页调用构造器
  22. *
  23. * @param moviesConditions 请求查询分页请求
  24. * @param moviesInfoThriftService 实际分页调用电影ThriftService
  25. */
  26. public GetMoviesByConditionPage(MoviesConditions moviesConditions, MoviesInfoThriftService moviesInfoThriftService) {
  27. super(moviesConditions);
  28. this.moviesInfoThriftService = moviesInfoThriftService;
  29. }
  30. /**
  31. * 设置实际页号
  32. *
  33. * @param moviesConditions 请求查询分页请求
  34. * @param pageNo 页号
  35. */
  36. @Override
  37. protected void setPageNo(MoviesConditions moviesConditions, int pageNo) {
  38. if (Objects.isNull(moviesConditions)) {
  39. return;
  40. }
  41. moviesConditions.setPageNo(pageNo);
  42. }
  43. /**
  44. * 设置实际页大小
  45. *
  46. * @param moviesConditions 请求查询分页请求
  47. * @param pageSize 页大小
  48. */
  49. @Override
  50. protected void setPageSize(MoviesConditions moviesConditions, int pageSize) {
  51. if (Objects.isNull(moviesConditions)) {
  52. return;
  53. }
  54. moviesConditions.setPageSize(pageSize);
  55. }
  56. /**
  57. * 获取实际数据大小
  58. *
  59. * @param moviesResult 请求查询分页请求
  60. * @return 实际数据大小
  61. */
  62. @Override
  63. protected int getResultSize(MoviesResult moviesResult) {
  64. if (Objects.isNull(moviesResult)) {
  65. return 0;
  66. }
  67. return moviesResult.getMovieInfos().size();
  68. }
  69. /**
  70. * 实际业务调用thrift接口
  71. *
  72. * @param moviesConditions 请求查询分页请求
  73. * @return 实际业务调用thrift接口返回
  74. * @throws Exception 业务异常
  75. */
  76. @Override
  77. protected MoviesResult invoke(MoviesConditions moviesConditions) throws Exception {
  78. if (Objects.isNull(moviesConditions)) {
  79. return null;
  80. }
  81. return moviesInfoThriftService.getMoviesByConditionPage(moviesConditions);
  82. }
  83. /**
  84. * 获取实际业务需要的结果(进行实际的转换)
  85. *
  86. * @param moviesResult 实际业务调用thrift接口返回
  87. * @return 实际业务需要的电影基本信息
  88. */
  89. @Override
  90. protected List<MovieBasicInfo> convertThriftResult(MoviesResult moviesResult) {
  91. if (Objects.isNull(moviesResult) || CollectionUtils.isEmpty(moviesResult.getMovieInfos())) {
  92. return Lists.newArrayList();
  93. }
  94. return moviesResult.getMovieInfos().stream().map(movieInfo -> MovieBasicInfo.builder()
  95. .id(movieInfo.getId())
  96. .name(movieInfo.getName())
  97. .desc(movieInfo.getDesc())
  98. .director(movieInfo.getDirector())
  99. .actor(movieInfo.getActor())
  100. .duration(movieInfo.getDuration())
  101. .year(movieInfo.getYear())
  102. .score(movieInfo.getScore()).build()).collect(Collectors.toList());
  103. }
  104. }

获取电影thrift接口滚动处理

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.collections.CollectionUtils;
  4. import org.assertj.core.util.Lists;
  5. import java.util.List;
  6. import java.util.Objects;
  7. import java.util.stream.Collectors;
  8. /**
  9. * @author yanfengzhang
  10. * @description 获取电影thrift接口滚动处理
  11. * @date 2022/3/20 17:37
  12. */
  13. @Slf4j
  14. public class GetMoviesByConditionScroll extends ThriftInvokeScrollCommand<MoviesConditions, MoviesResult, MovieBasicInfo> {
  15. /**
  16. * 实际thrift接口(此处只做模拟)
  17. * 实际该处应该类似为:private MoviesInfoThriftService.Iface moviesInfoThriftService;
  18. */
  19. private MoviesInfoThriftService moviesInfoThriftService;
  20. /**
  21. * 实际分页调用构造器
  22. *
  23. * @param moviesConditions 请求查询分页请求
  24. * @param moviesInfoThriftService 实际分页调用电影ThriftService
  25. */
  26. public GetMoviesByConditionScroll(MoviesConditions moviesConditions, MoviesInfoThriftService moviesInfoThriftService) {
  27. super(moviesConditions);
  28. this.moviesInfoThriftService = moviesInfoThriftService;
  29. }
  30. /**
  31. * @param moviesConditions 请求查询分页请求
  32. * @param scrollId 当前滚动ID
  33. */
  34. @Override
  35. protected void setScrollId(MoviesConditions moviesConditions, Long scrollId) {
  36. if (Objects.isNull(moviesConditions)) {
  37. return;
  38. }
  39. moviesConditions.setScrollId(scrollId);
  40. }
  41. /**
  42. * @param thriftResult 请求查询分页请求
  43. * @return 下一个滚动ID
  44. */
  45. @Override
  46. protected Long getNextScrollId(MoviesResult thriftResult) {
  47. if (Objects.isNull(thriftResult)) {
  48. return 0L;
  49. }
  50. return thriftResult.getNextScrollId();
  51. }
  52. /**
  53. * 设置实际页大小
  54. *
  55. * @param moviesConditions 请求查询分页请求
  56. * @param pageSize 页大小
  57. */
  58. @Override
  59. protected void setPageSize(MoviesConditions moviesConditions, int pageSize) {
  60. if (Objects.isNull(moviesConditions)) {
  61. return;
  62. }
  63. moviesConditions.setPageSize(pageSize);
  64. }
  65. /**
  66. * 获取实际数据大小
  67. *
  68. * @param moviesResult 请求查询分页请求
  69. * @return 实际数据大小
  70. */
  71. @Override
  72. protected int getResultSize(MoviesResult moviesResult) {
  73. if (Objects.isNull(moviesResult)) {
  74. return 0;
  75. }
  76. return moviesResult.getMovieInfos().size();
  77. }
  78. /**
  79. * 实际业务调用thrift接口
  80. *
  81. * @param moviesConditions 请求查询分页请求
  82. * @return 实际业务调用thrift接口返回
  83. * @throws Exception 业务异常
  84. */
  85. @Override
  86. protected MoviesResult invoke(MoviesConditions moviesConditions) throws Exception {
  87. if (Objects.isNull(moviesConditions)) {
  88. return null;
  89. }
  90. return moviesInfoThriftService.getMoviesByConditionScroll(moviesConditions);
  91. }
  92. /**
  93. * 获取实际业务需要的结果(进行实际的转换)
  94. *
  95. * @param moviesResult 实际业务调用thrift接口返回
  96. * @return 实际业务需要的电影基本信息
  97. */
  98. @Override
  99. protected List<MovieBasicInfo> convertThriftResult(MoviesResult moviesResult) {
  100. if (Objects.isNull(moviesResult) || CollectionUtils.isEmpty(moviesResult.getMovieInfos())) {
  101. return Lists.newArrayList();
  102. }
  103. return moviesResult.getMovieInfos().stream().map(movieInfo -> MovieBasicInfo.builder()
  104. .id(movieInfo.getId())
  105. .name(movieInfo.getName())
  106. .desc(movieInfo.getDesc())
  107. .director(movieInfo.getDirector())
  108. .actor(movieInfo.getActor())
  109. .duration(movieInfo.getDuration())
  110. .year(movieInfo.getYear())
  111. .score(movieInfo.getScore()).build()).collect(Collectors.toList());
  112. }
  113. }

业务模拟服务

前置准备数据

查询电影资源条件集合

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. /**
  5. * @author yanfengzhang
  6. * @description 查询电影资源条件集合
  7. * @date 2022/3/18 23:33
  8. */
  9. @Data
  10. @Builder
  11. public class MoviesConditions {
  12. /**
  13. * 综合排序类型:1-热播榜,2-好评榜,3-新上线,4-爱奇艺自制(热播),5-腾讯自制(热播),6-优酷自制(热播)
  14. */
  15. private int sortType;
  16. /**
  17. * 播放类型:1-剧情,2-喜剧,3-动作,4-爱情,5-惊悚,6-犯罪,7-悬疑,8-战争,9-科幻,10-动画,11-恐怖
  18. * 12-家庭,13-传记,14-冒险,15-奇幻,16-武侠,17-历史,18-运动,19-歌舞,20-音乐,21-记录
  19. * 22-伦理,23-西部
  20. */
  21. private int playType;
  22. /**
  23. * 电影产地归类:1-内地,2-中国香港,3-美国,4-欧洲,5-日本,6-韩国,7-英国,8-法国,9-德国,10-泰国
  24. * 11-印度,12-意大利,13-西班牙,14-加拿大,15-澳大利亚,16-中国台湾,17-拉丁美洲,18-越南
  25. * 19-俄罗斯,20-其他
  26. */
  27. private int productPlace;
  28. /**
  29. * 电影源:1-院线,2-蓝光,3-奥斯卡,4-自制电影,5-独播,6-烂片,7-网络电影,8-巨制
  30. */
  31. private int source;
  32. /**
  33. * 付费类型:1-免费,2-付费,3-VIP
  34. */
  35. private int paymentType;
  36. /**
  37. * 年份归类:1-2022年,2-2021年,3-2020年,4-2019年,5-20211-2018年
  38. * 6-2000-2010年,7-90年代,8-80年代,9-更早
  39. */
  40. private int years;
  41. /**
  42. * 页号
  43. */
  44. private int pageNo;
  45. /**
  46. * 页大小
  47. */
  48. private int pageSize;
  49. /**
  50. * 当前滚动ID
  51. */
  52. private Long scrollId;
  53. }

电影资源信息(只是样板)

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import java.util.List;
  5. /**
  6. * @author yanfengzhang
  7. * @description 电影资源信息(只是样板)
  8. * @date 2022/3/18 23:33
  9. */
  10. @Data
  11. @Builder
  12. public class MovieInfo {
  13. /**
  14. * ID编号
  15. */
  16. private Long id;
  17. /**
  18. * 电影名称
  19. */
  20. private String name;
  21. /**
  22. * 电影简介
  23. */
  24. private String desc;
  25. /**
  26. * 电影导演
  27. */
  28. private String director;
  29. /**
  30. * 电影演员
  31. */
  32. private String actor;
  33. /**
  34. * 电影综合评分
  35. */
  36. private Integer score;
  37. /**
  38. * 电影时长
  39. */
  40. private Integer duration;
  41. /**
  42. * 归属排序:1-热播榜,2-好评榜,3-新上线,4-爱奇艺自制(热播),5-腾讯自制(热播),6-优酷自制(热播)
  43. */
  44. private int belong;
  45. /**
  46. * 播放类型:1-剧情,2-喜剧,3-动作,4-爱情,5-惊悚,6-犯罪,7-悬疑,8-战争,9-科幻,10-动画,11-恐怖
  47. * 12-家庭,13-传记,14-冒险,15-奇幻,16-武侠,17-历史,18-运动,19-歌舞,20-音乐,21-记录
  48. * 22-伦理,23-西部
  49. */
  50. private List<Integer> playTypes;
  51. /**
  52. * 电影产地归类:1-内地,2-中国香港,3-美国,4-欧洲,5-日本,6-韩国,7-英国,8-法国,9-德国,10-泰国
  53. * 11-印度,12-意大利,13-西班牙,14-加拿大,15-澳大利亚,16-中国台湾,17-拉丁美洲,18-越南
  54. * 19-俄罗斯,20-其他
  55. */
  56. private int productPlace;
  57. /**
  58. * 电影源:1-院线,2-蓝光,3-奥斯卡,4-自制电影,5-独播,6-烂片,7-网络电影,8-巨制
  59. */
  60. private List<Integer> sources;
  61. /**
  62. * 付费类型:1-免费,2-付费,3-VIP
  63. */
  64. private int paymentType;
  65. /**
  66. * 上映年份
  67. */
  68. private int year;
  69. }

基本电影信息

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. /**
  5. * @author yanfengzhang
  6. * @description 基本电影信息
  7. * @date 2022/3/18 23:35
  8. */
  9. @Data
  10. @Builder
  11. public class MovieBasicInfo {
  12. /**
  13. * ID编号
  14. */
  15. private Long id;
  16. /**
  17. * 电影名称
  18. */
  19. private String name;
  20. /**
  21. * 电影简介
  22. */
  23. private String desc;
  24. /**
  25. * 电影导演
  26. */
  27. private String director;
  28. /**
  29. * 电影演员
  30. */
  31. private String actor;
  32. /**
  33. * 电影综合评分
  34. */
  35. private Integer score;
  36. /**
  37. * 电影时长
  38. */
  39. private Integer duration;
  40. /**
  41. * 上映年份
  42. */
  43. private int year;
  44. }

获取的电影集合

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import java.util.List;
  5. /**
  6. * @author yanfengzhang
  7. * @description 获取的电影集合
  8. * @date 2022/3/18 23:35
  9. */
  10. @Data
  11. @Builder
  12. public class MoviesResult {
  13. /**
  14. * 总数目
  15. */
  16. private long total;
  17. /**
  18. * 具体电影信息
  19. */
  20. public List<MovieInfo> movieInfos;
  21. /**
  22. * 电影ID集合
  23. */
  24. public List<Long> movieIdList;
  25. /**
  26. * 下一个滚动ID
  27. */
  28. private Long nextScrollId;
  29. }

具体模拟业务

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import com.google.common.collect.Maps;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.assertj.core.util.Lists;
  5. import org.springframework.stereotype.Service;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Random;
  9. /**
  10. * @author yanfengzhang
  11. * @description 模拟实际电影thrift接口
  12. * @date 2022/3/18 23:39
  13. */
  14. @Service
  15. @Slf4j
  16. public class MoviesInfoThriftService {
  17. private static Map<Integer, String> descWords = Maps.newHashMap();
  18. static {
  19. descWords.put(1, "人生若无悔,那该多无趣啊。——《一代宗师》");
  20. descWords.put(2, "冬天冷,是因为为了让我们懂得周围人的温暖,是多么的珍贵。——《熔炉》");
  21. descWords.put(3, "你要尽全力保护你的梦想。那些嘲笑你梦想的人,他们注定失败,他们想把你变成和他们一样。我坚信,只要心中有梦想,我就会与众不同。你也是。——《当幸福来敲门》");
  22. descWords.put(5, "成功的含义不在于得到什么,而是在于你从那个奋斗的起点走了多远。——《心灵捕手》");
  23. descWords.put(6, "让朋友低估你的优点,让敌人高估你的缺点。——《教父》");
  24. descWords.put(7, "所有大人都曾是小孩,虽然只有少数人记得。——《小王子》");
  25. descWords.put(8, "记住,希望是好事,也许是人间至善,而美好的事物永不消逝。——《肖申克的救赎》");
  26. descWords.put(9, "当你不能再拥有的时候,唯一可以做的,就是令自己不要忘记。——《东邪西毒》");
  27. descWords.put(10, "我们要学会珍惜我们生活的每一天,因为,这每一天的开始,都将是我们余下生命之中的第一天。除非我们即将死去。——《美国美人》");
  28. }
  29. public MoviesResult getMoviesByConditionPage(MoviesConditions moviesConditions) {
  30. if (!checkPosInteger(moviesConditions.getPageSize())) {
  31. return null;
  32. }
  33. List<MovieInfo> movieInfos = Lists.newArrayList();
  34. List<Long> movieIdList = Lists.newArrayList();
  35. /*模拟数据,返回第一页数据和指定的页面大小*/
  36. if (moviesConditions.getPageNo() == 1) {
  37. for (int i = 1; i <= moviesConditions.getPageSize(); i++) {
  38. movieIdList.add((long) i);
  39. movieInfos.add(MovieInfo.builder()
  40. .id((long) i)
  41. .name("张彦峰喜欢的电影" + i)
  42. .desc(descWords.get(i))
  43. .actor("张彦峰")
  44. .director("张彦峰")
  45. .belong(2)
  46. .score(new Random().nextInt(10) % (10 - i + 1) + i).build());
  47. }
  48. }
  49. if (moviesConditions.getPageNo() == 2) {
  50. for (int i = 6; i <= moviesConditions.getPageSize() + 5; i++) {
  51. movieIdList.add((long) i);
  52. movieInfos.add(MovieInfo.builder()
  53. .id((long) i)
  54. .name("张彦峰喜欢的电影" + i)
  55. .desc(descWords.get(i))
  56. .actor("张彦峰")
  57. .director("张彦峰")
  58. .belong(2)
  59. .score(new Random().nextInt(10) % (10 - i + 1) + i).build());
  60. }
  61. }
  62. return MoviesResult.builder().total(5).movieIdList(movieIdList).movieInfos(movieInfos).build();
  63. }
  64. public MoviesResult getMoviesByConditionScroll(MoviesConditions moviesConditions) {
  65. if (!checkPosInteger(moviesConditions.getPageSize()) || moviesConditions.getScrollId() < 0) {
  66. return null;
  67. }
  68. List<MovieInfo> movieInfos = Lists.newArrayList();
  69. List<Long> movieIdList = Lists.newArrayList();
  70. /*模拟数据,返回第一页数据和指定的页面大小*/
  71. if (moviesConditions.getScrollId() == 0) {
  72. for (int i = 1; i <= moviesConditions.getPageSize(); i++) {
  73. movieIdList.add((long) i);
  74. movieInfos.add(MovieInfo.builder()
  75. .id((long) i)
  76. .name("张彦峰喜欢的电影" + i)
  77. .desc(descWords.get(i))
  78. .actor("张彦峰")
  79. .director("张彦峰")
  80. .belong(2)
  81. .score(new Random().nextInt(10) % (10 - i + 1) + i).build());
  82. }
  83. return MoviesResult.builder().total(5).movieIdList(movieIdList).movieInfos(movieInfos).nextScrollId(1L).build();
  84. }
  85. if (moviesConditions.getScrollId() == 1) {
  86. for (int i = 6; i <= moviesConditions.getPageSize() + 5; i++) {
  87. movieIdList.add((long) i);
  88. movieInfos.add(MovieInfo.builder()
  89. .id((long) i)
  90. .name("张彦峰喜欢的电影" + i)
  91. .desc(descWords.get(i))
  92. .actor("张彦峰")
  93. .director("张彦峰")
  94. .belong(2)
  95. .score(new Random().nextInt(10) % (10 - i + 1) + i).build());
  96. }
  97. }
  98. return MoviesResult.builder().total(5).movieIdList(movieIdList).movieInfos(movieInfos).nextScrollId(-1L).build();
  99. }
  100. /**
  101. * ID信息合法性:必须为正整数
  102. *
  103. * @param id id信息
  104. * @return true-合法;false-非法
  105. */
  106. public static boolean checkPosInteger(Integer id) {
  107. return null != id && id > 0L;
  108. }
  109. }

测试及展示

测试代码

  1. package org.zyf.javabasic.designpatterns.strategy.template.thrift;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import org.springframework.test.context.junit4.SpringRunner;
  8. import org.zyf.javabasic.ZYFApplication;
  9. import java.util.List;
  10. /**
  11. * @author yanfengzhang
  12. * @description 测试按页获取远程数据
  13. * @date 2022/3/20 17:21
  14. */
  15. @RunWith(SpringRunner.class)
  16. @SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  17. @Slf4j
  18. public class ThriftInvokeCommandTest {
  19. @Autowired
  20. private MoviesInfoThriftService moviesInfoThriftService;
  21. @Test
  22. public void testGetMoviesByCondition() {
  23. log.info("测试分页获取数据:");
  24. MoviesConditions moviesConditions1 = MoviesConditions.builder()
  25. .pageNo(1)
  26. .pageSize(2)
  27. .build();
  28. List movieBasicInfos1 = new GetMoviesByConditionPage(moviesConditions1, moviesInfoThriftService)
  29. .setPageSize(5)
  30. .setSleepMs(100)
  31. .getResult();
  32. log.info("按实际条件返回的基本结果为:{}", movieBasicInfos1);
  33. log.info("测试滚动获取数据:");
  34. MoviesConditions moviesConditions2 = MoviesConditions.builder()
  35. .pageNo(1)
  36. .pageSize(2)
  37. .scrollId(0L)
  38. .build();
  39. List<MovieBasicInfo> movieBasicInfos2 = new GetMoviesByConditionScroll(moviesConditions2, moviesInfoThriftService)
  40. .setPageSize(5)
  41. .setSleepMs(100)
  42. .getResult();
  43. log.info("按实际条件返回的基本结果为:{}", movieBasicInfos2);
  44. }
  45. }

业务处理统一相关处理模版

可以根据业务要求也安排一些常规的模版流程进行处理,同时对于其基本的操作而言,可以在细化为三种类型:支持SpringValidator的业务处理模版、没有入参调用的业务处理模版、没有返回参数调用的业务处理模版,主要代码如下:

基本的业务处理模版BizTemplate

  1. package org.zyf.javabasic.designpatterns.template.biz;
  2. import org.apache.commons.collections.CollectionUtils;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. /**
  9. * @author yanfengzhang
  10. * @description 基本的业务处理模版
  11. * @date 2022/4/24 23:10
  12. */
  13. public abstract class BizTemplate<Command extends BaseCommand, Result extends BaseResult> {
  14. protected BizResponse<Result> response = BizResponse.success();
  15. /**
  16. * 请求参数
  17. */
  18. protected Command command;
  19. /**
  20. * 请求结果
  21. */
  22. protected Result result;
  23. /**
  24. * 方法名称,用于记录日志
  25. */
  26. protected String methodName;
  27. /**
  28. * 日志
  29. */
  30. protected Logger templateLogger = LoggerFactory.getLogger(BizTemplate.class);
  31. /**
  32. * 验证器集合
  33. */
  34. protected List<Validation> validationList = new ArrayList<>(10);
  35. public BizTemplate(Command command, Result result) {
  36. this.methodName = this.getClass().getName();
  37. this.command = command;
  38. this.result = result;
  39. }
  40. public BizTemplate(Result result) {
  41. this.methodName = this.getClass().getName();
  42. this.command = (Command) new BaseCommand();
  43. this.result = result;
  44. }
  45. public BizTemplate(Command command) {
  46. this.methodName = this.getClass().getName();
  47. this.command = command;
  48. this.result = (Result) new BaseResult();
  49. }
  50. /**
  51. * check template
  52. *
  53. * @return
  54. */
  55. protected boolean templateValidate() {
  56. if (command == null || result == null || StringUtils.isBlank(methodName) || templateLogger == null) {
  57. return false;
  58. }
  59. return true;
  60. }
  61. /**
  62. * before
  63. * you can write the logic code that execute before the primay business logic
  64. * for example validate paramaters, check preposed data and so on
  65. */
  66. public abstract void doBefore();
  67. /**
  68. * primay business logic
  69. */
  70. public abstract void doBiz() throws Exception;
  71. public void doException() throws Exception {
  72. }
  73. /**
  74. * after
  75. * you can write the logic code that execute after the primay business logic
  76. */
  77. public void doAfter() {
  78. }
  79. /**
  80. * add validation
  81. *
  82. * @param check
  83. * @param msg
  84. */
  85. public void addValidation(boolean check, String msg) {
  86. this.validationList.add(new Validation(check, msg));
  87. }
  88. /**
  89. * execute validation
  90. *
  91. * @param msg, result
  92. * @param flag, record if the result is false, default is false
  93. */
  94. protected void doValidate(StringBuilder msg, boolean flag) {
  95. if (CollectionUtils.isNotEmpty(validationList)) {
  96. for (Validation validation : validationList) {
  97. if (!validation.check) {
  98. msg.append(" ");
  99. msg.append(validation.msg);
  100. msg.append(" ");
  101. flag = true;
  102. }
  103. }
  104. }
  105. if (flag) {
  106. throw new ZYFServerException(ErrorCode.PARAMS_CHECK_FAILED.getCode(), String.format(ErrorCode.PARAMS_CHECK_FAILED.getMsg(), msg.toString()));
  107. }
  108. }
  109. /**
  110. * execute
  111. *
  112. * @return
  113. */
  114. public BizResponse<Result> execute() throws Exception {
  115. long threadId = Thread.currentThread().getId();
  116. if (!this.templateValidate()) {
  117. throw new IllegalArgumentException("the usage of WebControllerBizTemplate is illegal");
  118. }
  119. this.doBefore();
  120. this.doValidate(new StringBuilder(), false);
  121. long startTime = System.currentTimeMillis();
  122. try {
  123. this.doBiz();
  124. } catch (Exception e) {
  125. this.doException();
  126. throw e;
  127. }
  128. this.doAfter();
  129. response.setData(result);
  130. return response;
  131. }
  132. /**
  133. * validator
  134. *
  135. * @author sunwei
  136. */
  137. class Validation {
  138. boolean check;
  139. String msg;
  140. public Validation(boolean check, String msg) {
  141. super();
  142. this.check = check;
  143. this.msg = msg;
  144. }
  145. }
  146. public String getMethodName() {
  147. return methodName;
  148. }
  149. public void setMethodName(String methodName) {
  150. this.methodName = methodName;
  151. }
  152. public Logger getTemplateLogger() {
  153. return templateLogger;
  154. }
  155. public void setTemplateLogger(Logger templateLogger) {
  156. this.templateLogger = templateLogger;
  157. }
  158. }

支持SpringValidator的业务处理模版

  1. package org.zyf.javabasic.designpatterns.template.biz;
  2. import org.springframework.validation.BindingResult;
  3. import org.springframework.validation.ObjectError;
  4. /**
  5. * @author yanfengzhang
  6. * @description 支持Spring Validator
  7. * @date 2022/4/24 23:22
  8. */
  9. public abstract class BizTemplateWithSpringValidator<Command extends BaseCommand, Result extends BaseResult> extends BizTemplate<Command, Result> {
  10. private BindingResult br;
  11. public BizTemplateWithSpringValidator(Command command, Result result, BindingResult br) {
  12. super(command, result);
  13. this.br = br;
  14. }
  15. @Override
  16. protected void doValidate(StringBuilder msg, boolean flag) {
  17. if (br.hasErrors()) {
  18. for (ObjectError error : br.getAllErrors()) {
  19. msg.append(" ");
  20. msg.append(error.getDefaultMessage());
  21. msg.append(" ");
  22. }
  23. }
  24. flag = br.hasErrors();
  25. super.doValidate(msg, flag);
  26. }
  27. }

没有入参调用的业务处理模版

  1. package org.zyf.javabasic.designpatterns.template.biz;
  2. import org.apache.commons.lang3.StringUtils;
  3. /**
  4. * @author yanfengzhang
  5. * @description 没有入参的调用
  6. * @date 2022/4/24 23:23
  7. */
  8. public abstract class BizWithoutCommandTemplate<Result extends BaseResult> extends BizTemplate<BaseCommand, Result> {
  9. public BizWithoutCommandTemplate(Result result) {
  10. super(new BaseCommand(), result);
  11. }
  12. @Override
  13. protected boolean templateValidate() {
  14. if (result == null || StringUtils.isBlank(methodName) || templateLogger == null) {
  15. return false;
  16. }
  17. return true;
  18. }
  19. }

没有返回参数调用的业务处理模版

  1. package org.zyf.javabasic.designpatterns.template.biz;
  2. import org.apache.commons.lang3.StringUtils;
  3. /**
  4. * @author yanfengzhang
  5. * @description 没有入参的调用
  6. * @date 2022/4/24 23:23
  7. */
  8. public abstract class BizWithoutCommandTemplate<Result extends BaseResult> extends BizTemplate<BaseCommand, Result> {
  9. public BizWithoutCommandTemplate(Result result) {
  10. super(new BaseCommand(), result);
  11. }
  12. @Override
  13. protected boolean templateValidate() {
  14. if (result == null || StringUtils.isBlank(methodName) || templateLogger == null) {
  15. return false;
  16. }
  17. return true;
  18. }
  19. }

业务使用举例

  1. package org.zyf.javabasic.designpatterns.template.biz;
  2. import com.google.common.collect.Lists;
  3. import lombok.AllArgsConstructor;
  4. import lombok.Getter;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.collections.CollectionUtils;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.validation.BindingResult;
  9. import org.springframework.web.bind.annotation.RequestBody;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RequestMethod;
  12. import org.springframework.web.bind.annotation.ResponseBody;
  13. import javax.annotation.Nullable;
  14. import java.util.List;
  15. /**
  16. * @author yanfengzhang
  17. * @description
  18. * @date 2022/4/24 23:32
  19. */
  20. @Controller
  21. @RequestMapping("/org/zyf")
  22. @Slf4j
  23. public class ZYFBizTemplateController {
  24. @RequestMapping("r/listSubBrand")
  25. @ResponseBody
  26. public BizResponse<ListSubBrandResult> listSubBrand(ListSubBrandCommand command, final BindingResult br)
  27. throws Exception {
  28. return new BizTemplateWithSpringValidator<ListSubBrandCommand, ListSubBrandResult>(command,
  29. new ListSubBrandResult(), br) {
  30. void brandValidator() {
  31. /*根据接口查看传入品牌是否是有效品牌*/
  32. List<Long> illegalBrands = Lists.newArrayList();
  33. if (CollectionUtils.isEmpty(command.getBrandIds())) {
  34. return;
  35. }
  36. /*模拟调用返回无效品牌*/
  37. illegalBrands.addAll(command.getBrandIds());
  38. this.addValidation(CollectionUtils.isEmpty(illegalBrands), String.format("存在不合法品牌信息[%s]", command.getBrandIds()));
  39. }
  40. @Override
  41. public void doBefore() {
  42. /*1.对入参进行调整或默认填充,比方说command的基本必要参数未填写可默认指定处理*/
  43. /*2.对基本参数进行检查等*/
  44. this.addValidation(command.getParentId() > 0, "parentId必须大于0");
  45. this.brandValidator();
  46. }
  47. @Override
  48. public void doBiz() throws Exception {
  49. List<ListSubBrandResult.CRUXStandardProductLibBrand> brandList = Lists.newArrayList();
  50. result.convert2CruxBrand(brandList);
  51. }
  52. }.execute();
  53. }
  54. @RequestMapping(value = "r/getStandardCategoryTagValueList")
  55. @ResponseBody
  56. public BizResponse<GetSpCategoryMetaAttrValueListResult> getStandardCategoryTagValueList() throws Exception {
  57. return new BizWithoutCommandTemplate<GetSpCategoryMetaAttrValueListResult>(new GetSpCategoryMetaAttrValueListResult()) {
  58. @Override
  59. public void doBefore() {
  60. }
  61. @Override
  62. public void doBiz() throws Exception {
  63. /*模拟调用*/
  64. //CRUXStandardProductCategoryMetaAttrValueListResult thriftResult = cruxStandardProductCategoryThriftService.getCategoryMetaAttrValueListByMetacode(MetaAttrEnum.STANDARD_CATEGORY_TAG.getCode());
  65. CRUXStandardProductCategoryMetaAttrValueListResult thriftResult = new CRUXStandardProductCategoryMetaAttrValueListResult();
  66. if (thriftResult == null) {
  67. throw new ZYFServerException(ErrorCode.DATA_NOT_FOUND.getCode(), ErrorCode.DATA_NOT_FOUND.getMsg());
  68. }
  69. if (CollectionUtils.isEmpty(thriftResult.getCategoryMetaAttrValueList())) {
  70. return;
  71. }
  72. for (ScSpCategoryMetaAttrValue value : thriftResult.getCategoryMetaAttrValueList()) {
  73. result.getSpCategoryMetaAttrValueList().add(new ScSpCategoryMetaAttrValueVo());
  74. }
  75. }
  76. }.execute();
  77. }
  78. @RequestMapping(value = "strategy/w/strategyDeploy", method = RequestMethod.POST)
  79. @ResponseBody
  80. public BizResponse<BaseResult> batchDeployStrategy(@RequestBody BatchDeployStrategyCommand command) throws Exception {
  81. return new BizWithoutResultTemplate<BatchDeployStrategyCommand>(command) {
  82. @Override
  83. public void doBefore() {
  84. addValidation(command.getProcessBizType() != null, "processBizType不能为null,请参考com.sankuai.meituan.tsp.product.bizconsistency.enums.BizTypeEnum");
  85. addValidation(command.getProcessDataType() != null, "processDataType不能为null,请参考com.sankuai.meituan.tsp.product.bizconsistency.enums.DataTypeEnum");
  86. addValidation(command.getOperation() != null, "operation不能为null,1-发布策略 2-撤销策略");
  87. }
  88. @Override
  89. public void doBiz() throws Exception {
  90. BizTypeEnum bizTypeEnum = BizTypeEnum.findByType(command.getProcessBizType());
  91. if (bizTypeEnum == null) {
  92. throw new IllegalArgumentException(String.format("%d是非法的processBizType", command.getProcessBizType()));
  93. }
  94. DataTypeEnum dataTypeEnum = DataTypeEnum.findByType(command.getProcessDataType());
  95. if (dataTypeEnum == null) {
  96. throw new IllegalArgumentException(String.format("%d是非法的processDataType", command.getProcessDataType()));
  97. }
  98. if (command.isDeploy()) {
  99. // productBcpService.batchDeployStrategy(bizTypeEnum, dataTypeEnum, command.getStrategyIdList());
  100. } else if (command.isUndeploy()) {
  101. // productBcpService.batchUndeployStrategy(bizTypeEnum, dataTypeEnum, command.getStrategyIdList());
  102. }
  103. }
  104. }.execute();
  105. }
  106. @AllArgsConstructor
  107. @Getter
  108. public enum BizTypeEnum {
  109. /**
  110. * 业务模型类型
  111. */
  112. PRODUCT_SUPPLY_SPU(1, "spuId", "商品供给业务SPU"),
  113. PRODUCT_SUPPLY_SKU(2, "skuId", "商品供给业务SKU"),
  114. PRODUCT_SUPPLY_TAG(3, "tagId", "商品供给业务TAG"),
  115. ;
  116. private int type;
  117. private String bizId;
  118. private String desc;
  119. @Nullable
  120. public static BizTypeEnum findByType(int type) {
  121. for (BizTypeEnum each : BizTypeEnum.values()) {
  122. if (each.getType() == type) {
  123. return each;
  124. }
  125. }
  126. return null;
  127. }
  128. }
  129. @AllArgsConstructor
  130. @Getter
  131. public enum DataTypeEnum {
  132. /**
  133. * 不一致问题数据类型
  134. */
  135. MYSQL_ONLY(1, "仅Mysql"),
  136. MYSQL_AND_ES(2, "Mysql和ES"),
  137. MYSQL_AND_TAIR(3, "Mysql和Tair"),
  138. MYSQL_AND_REDIS(4, "Mysql和Redis"),
  139. MYSQL_AND_MTSEARCH(5, "Mysql和大搜"),
  140. ;
  141. private int type;
  142. private String desc;
  143. public static DataTypeEnum findByType(int type) {
  144. for (DataTypeEnum each : DataTypeEnum.values()) {
  145. if (each.getType() == type) {
  146. return each;
  147. }
  148. }
  149. return null;
  150. }
  151. }
  152. }
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号