当前位置: 首页 > news >正文

阿里云1核2g服务器能建设几个网站网站后台加密

阿里云1核2g服务器能建设几个网站,网站后台加密,新强生产建设兵团网站,wordpress建站吧重学 Java 设计模式#xff1a;实战状态模式「模拟系统营销活动#xff0c;状态流程审核发布上线场景」 一、前言 写好代码三个关键点 如果把写代码想象成家里的软装#xff0c;你肯定会想到家里需要有一个非常不错格局最好是南北通透的#xff0c;买回来的家具最好是品…重学 Java 设计模式实战状态模式「模拟系统营销活动状态流程审核发布上线场景」 一、前言 写好代码三个关键点 如果把写代码想象成家里的软装你肯定会想到家里需要有一个非常不错格局最好是南北通透的买回来的家具最好是品牌保证质量的之后呢是大小合适不能摆放完了看着别扭。那么把这一过程抽象成写代码就是需要三个核心的关键点架构(房间的格局)、命名(品牌和质量)、注释(尺寸大小说明书)只有这三个点都做好才能完成出一套赏心悦目的家。 平原走码易放难收 上学期间你写了多少代码上班一年你能写多少代码回家自己学习写了多少代码个人素养的技术栈地基都是一块一块砖码出来的写的越广越深根基就越牢固。当根基牢固了以后在再上层建设就变得迎刃而解了也更容易建设了。往往最难的就是一层一层阶段的突破突破就像破壳一样也像夯实地基短时间看不到成绩也看不出高度。但以后谁能走的稳就靠着默默的沉淀。 技术传承的重要性 可能是现在时间节奏太快一个需求下来恨不得当天就上线(这个需求很简单怎么实现我不管明天上线)导致团队的人都很慌、很急、很累、很崩溃最终反反复复的人员更替项目在这个过程中也交接了N次文档不全、代码混乱、错综复杂谁在后面接手也都只能修修补补就像烂尾楼。这个没有传承、没有沉淀的项目很难跟随业务的发展。最终根基不牢一地鸡毛。 二、开发环境 JDK 1.8Idea Maven涉及工程三个可以通过关注公众号bugstack虫洞栈回复源码下载获取(打开获取的链接找到序号18) 工程描述itstack-demo-design-19-00场景模拟工程模拟营销活动操作服务(查询、审核)itstack-demo-design-19-01使用一坨代码实现业务需求itstack-demo-design-19-02通过设计模式优化改造代码产生对比性从而学习 三、状态模式介绍 图片来自https://refactoringguru.cn/design-patterns/state 状态模式描述的是一个行为下的多种状态变更比如我们最常见的一个网站的页面在你登录与不登录下展示的内容是略有差异的(不登录不能展示个人信息)而这种登录与不登录就是我们通过改变状态而让整个行为发生了变化。 至少80后、90后的小伙伴基本都用过这种磁带放音机(可能没有这个好看)它的上面是一排按钮当放入磁带后通过上面的按钮就可以让放音机播放磁带上的内容(listen to 英语听力考试)而且有些按钮是互斥的当在某个状态下才可以按另外的按钮(这在设计模式里也是一个关键的点)。 四、案例场景模拟 在本案例中我们模拟营销活动审核状态流转场景(一个活动的上线是多个层级审核上线的) 在上图中也可以看到我们的流程节点中包括了各个状态到下一个状态扭转的关联条件比如审核通过才能到活动中而不能从编辑中直接到活动中而这些状态的转变就是我们要完成的场景处理。 大部分程序员基本都开发过类似的业务场景需要对活动或者一些配置需要审核后才能对外发布而这个审核的过程往往会随着系统的重要程度而设立多级控制来保证一个活动可以安全上线避免造成资损。 当然有时候会用到一些审批流的过程配置也是非常方便开发类似的流程的也可以在配置中设定某个节点的审批人员。但这不是我们主要体现的点在本案例中我们主要是模拟学习对一个活动的多个状态节点的审核控制。 1. 场景模拟工程 itstack-demo-design-19-00 └── src└── main└── java└── org.itstack.demo.design├── ActivityInfo.java├── Status.java└── ActivityService.java在这个模拟工程里我们提供了三个类包括状态枚举(Status)、活动对象(ActivityInfo)、活动服务(ActivityService)三个服务类。接下来我们就分别介绍三个类包括的内容。 2. 代码实现 2.1 基本活动信息 public class ActivityInfo {private String activityId; // 活动IDprivate String activityName; // 活动名称private EnumStatus status; // 活动状态private Date beginTime; // 开始时间private Date endTime; // 结束时间// ...get/set } 一些基本的活动信息活动ID、活动名称、活动状态、开始时间、结束时间。 2.2 活动枚举状态 public enum Status {// 1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)Editing, Check, Pass, Refuse, Doing, Close, Open}活动的枚举1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中) 2.3 活动服务接口 public class ActivityService {private static MapString, EnumStatus statusMap new ConcurrentHashMapString, EnumStatus();public static void init(String activityId, EnumStatus status) {// 模拟查询活动信息ActivityInfo activityInfo new ActivityInfo();activityInfo.setActivityId(activityId);activityInfo.setActivityName(早起学习打卡领奖活动);activityInfo.setStatus(status);activityInfo.setBeginTime(new Date());activityInfo.setEndTime(new Date());statusMap.put(activityId, status);}/*** 查询活动信息** param activityId 活动ID* return 查询结果*/public static ActivityInfo queryActivityInfo(String activityId) {// 模拟查询活动信息ActivityInfo activityInfo new ActivityInfo();activityInfo.setActivityId(activityId);activityInfo.setActivityName(早起学习打卡领奖活动);activityInfo.setStatus(statusMap.get(activityId));activityInfo.setBeginTime(new Date());activityInfo.setEndTime(new Date());return activityInfo;}/*** 查询活动状态** param activityId 活动ID* return 查询结果*/public static EnumStatus queryActivityStatus(String activityId) {return statusMap.get(activityId);}/*** 执行状态变更** param activityId 活动ID* param beforeStatus 变更前状态* param afterStatus 变更后状态 b*/public static synchronized void execStatus(String activityId, EnumStatus beforeStatus, EnumStatus afterStatus) {if (!beforeStatus.equals(statusMap.get(activityId))) return;statusMap.put(activityId, afterStatus);}}在这个静态类中提供了活动的查询和状态变更接口queryActivityInfo、queryActivityStatus、execStatus。同时使用Map的结构来记录活动ID和状态变化信息另外还有init方法来初始化活动数据。实际的开发中这类信息基本都是从数据库或者Redis中获取。 五、用一坨坨代码实现 这里我们先使用最粗暴的方式来实现功能 对于这样各种状态的变更最让我们直接想到的就是使用if和else进行判断处理。每一个状态可以流转到下一个什么状态都可以使用嵌套的if实现。 1. 工程结构 itstack-demo-design-19-01 └── src└── main└── java└── org.itstack.demo.design├── ActivityExecStatusController.java└── Result.java整个实现的工程结构比较简单只包括了两个类ActivityExecStatusController、Result一个是处理流程状态另外一个是返回的对象。 2. 代码实现 public class ActivityExecStatusController {/*** 活动状态变更* 1. 编辑中 - 提审、关闭* 2. 审核通过 - 拒绝、关闭、活动中* 3. 审核拒绝 - 撤审、关闭* 4. 活动中 - 关闭* 5. 活动关闭 - 开启* 6. 活动开启 - 关闭** param activityId 活动ID* param beforeStatus 变更前状态* param afterStatus 变更后状态* return 返回结果*/public Result execStatus(String activityId, EnumStatus beforeStatus, EnumStatus afterStatus) {// 1. 编辑中 - 提审、关闭if (Status.Editing.equals(beforeStatus)) {if (Status.Check.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}// 2. 审核通过 - 拒绝、关闭、活动中if (Status.Pass.equals(beforeStatus)) {if (Status.Refuse.equals(afterStatus) || Status.Doing.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}// 3. 审核拒绝 - 撤审、关闭if (Status.Refuse.equals(beforeStatus)) {if (Status.Editing.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}// 4. 活动中 - 关闭if (Status.Doing.equals(beforeStatus)) {if (Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}// 5. 活动关闭 - 开启if (Status.Close.equals(beforeStatus)) {if (Status.Open.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}// 6. 活动开启 - 关闭if (Status.Open.equals(beforeStatus)) {if (Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result(0000, 变更状态成功);} else {return new Result(0001, 变更状态拒绝);}}return new Result(0001, 非可处理的活动状态变更);}}这里我们只需要看一下代码实现的结构即可。从上到下是一整篇的ifelse基本这也是大部分初级程序员的开发方式。这样的面向过程式开发方式对于不需要改动代码也不需要二次迭代的还是可以使用的(但基本不可能不迭代)。而且随着状态和需求变化会越来越难以维护后面的人也不好看懂并且很容易填充其他的流程进去。越来越乱就是从点滴开始的 3. 测试验证 3.1 编写测试类 Test public void test() {// 初始化数据String activityId 100001;ActivityService.init(activityId, Status.Editing); ActivityExecStatusController activityExecStatusController new ActivityExecStatusController();Result resultRefuse activityExecStatusController.execStatus(activityId, Status.Editing, Status.Refuse); logger.info(测试结果(编辑中To审核拒绝){}, JSON.toJSONString(resultRefuse)); Result resultCheck activityExecStatusController.execStatus(activityId, Status.Editing, Status.Check);logger.info(测试结果(编辑中To提交审核){}, JSON.toJSONString(resultCheck)); }我们的测试代码包括了两个功能的验证一个是从编辑中到审核拒绝另外一个是从编辑中到提交审核。因为从我们的场景流程中可以看到编辑中的活动是不能直接到审核拒绝的这中间还需要提审。 3.2 测试结果 23:24:30.774 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To审核拒绝){code:0001,info:变更状态拒绝} 23:24:30.778 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To提交审核){code:0000,info:变更状态成功}Process finished with exit code 0从测试结果和我们的状态流程的流转中可以看到是符合测试结果预期的。除了不好维护外这样的开发过程还是蛮快的但不建议这么搞 六、状态模式重构代码 接下来使用状态模式来进行代码优化也算是一次很小的重构。 重构的重点往往是处理掉ifelse而想处理掉ifelse基本离不开接口与抽象类另外还需要重新改造代码结构。 1. 工程结构 itstack-demo-design-19-02 └── src└── main└── java└── org.itstack.demo.design├── event│ ├── CheckState.java│ └── CloseState.java│ └── DoingState.java│ └── EditingState.java│ └── OpenState.java│ └── PassState.java│ └── RefuseState.java├── Result.java├── State.java└── StateHandler.java状态模式模型结构 以上是状态模式的整个工程结构模型State是一个抽象类定义了各种操作接口(提审、审核、拒审等)。右侧的不同颜色状态与我们场景模拟中的颜色保持一致是各种状态流程流转的实现操作。这里的实现有一个关键点就是每一种状态到下一个状态都分配到各个实现方法中控制也就不需要if语言进行判断了。最后是StateHandler对状态流程的统一处理里面提供Map结构的各项服务接口调用也就避免了使用if判断各项状态转变的流程。 2. 代码实现 2.1 定义状态抽象类 public abstract class State {/*** 活动提审** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result arraignment(String activityId, EnumStatus currentStatus);/*** 审核通过** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result checkPass(String activityId, EnumStatus currentStatus);/*** 审核拒绝** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result checkRefuse(String activityId, EnumStatus currentStatus);/*** 撤审撤销** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result checkRevoke(String activityId, EnumStatus currentStatus);/*** 活动关闭** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result close(String activityId, EnumStatus currentStatus);/*** 活动开启** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result open(String activityId, EnumStatus currentStatus);/*** 活动执行** param activityId 活动ID* param currentStatus 当前状态* return 执行结果*/public abstract Result doing(String activityId, EnumStatus currentStatus);}在整个接口中提供了各项状态流转服务的接口例如活动提审、审核通过、审核拒绝、撤审撤销等7个方法。在这些方法中所有的入参都是一样的activityId(活动ID)、currentStatus(当前状态)只有他们的具体实现是不同的。 2.2 部分状态流转实现 编辑 public class EditingState extends State {public Result arraignment(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Check);return new Result(0000, 活动提审成功);}public Result checkPass(String activityId, EnumStatus currentStatus) {return new Result(0001, 编辑中不可审核通过);}public Result checkRefuse(String activityId, EnumStatus currentStatus) {return new Result(0001, 编辑中不可审核拒绝);}Overridepublic Result checkRevoke(String activityId, EnumStatus currentStatus) {return new Result(0001, 编辑中不可撤销审核);}public Result close(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Close);return new Result(0000, 活动关闭成功);}public Result open(String activityId, EnumStatus currentStatus) {return new Result(0001, 非关闭活动不可开启);}public Result doing(String activityId, EnumStatus currentStatus) {return new Result(0001, 编辑中活动不可执行活动中变更);}}提审 public class CheckState extends State {public Result arraignment(String activityId, EnumStatus currentStatus) {return new Result(0001, 待审核状态不可重复提审);}public Result checkPass(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Pass);return new Result(0000, 活动审核通过完成);}public Result checkRefuse(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Refuse);return new Result(0000, 活动审核拒绝完成);}Overridepublic Result checkRevoke(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Editing);return new Result(0000, 活动审核撤销回到编辑中);}public Result close(String activityId, EnumStatus currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Close);return new Result(0000, 活动审核关闭完成);}public Result open(String activityId, EnumStatus currentStatus) {return new Result(0001, 非关闭活动不可开启);}public Result doing(String activityId, EnumStatus currentStatus) {return new Result(0001, 待审核活动不可执行活动中变更);}}这里提供了两个具体实现类的内容编辑状态和提审状态。例如在这两个实现类中checkRefuse这个方法对于不同的类中有不同的实现也就是不同状态下能做的下一步流转操作已经可以在每一个方法中具体控制了。其他5个类的操作是类似的具体就不在这里演示了大部分都是重复代码。可以通过源码进行学习理解。 2.3 状态处理服务 public class StateHandler {private MapEnumStatus, State stateMap new ConcurrentHashMapEnumStatus, State();public StateHandler() {stateMap.put(Status.Check, new CheckState()); // 待审核stateMap.put(Status.Close, new CloseState()); // 已关闭stateMap.put(Status.Doing, new DoingState()); // 活动中stateMap.put(Status.Editing, new EditingState()); // 编辑中stateMap.put(Status.Open, new OpenState()); // 已开启stateMap.put(Status.Pass, new PassState()); // 审核通过stateMap.put(Status.Refuse, new RefuseState()); // 审核拒绝}public Result arraignment(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).arraignment(activityId, currentStatus);}public Result checkPass(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).checkPass(activityId, currentStatus);}public Result checkRefuse(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);}public Result checkRevoke(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);}public Result close(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).close(activityId, currentStatus);}public Result open(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).open(activityId, currentStatus);}public Result doing(String activityId, EnumStatus currentStatus) {return stateMap.get(currentStatus).doing(activityId, currentStatus);}}这是对状态服务的统一控制中心可以看到在构造函数中提供了所有状态和实现的具体关联放到Map数据结构中。同时提供了不同名称的接口操作类让外部调用方可以更加容易的使用此项功能接口而不需要像在itstack-demo-design-19-01例子中还得传两个状态来判断。 3. 测试验证 3.1 编写测试类(Editing2Arraignment) Test public void test_Editing2Arraignment() {String activityId 100001;ActivityService.init(activityId, Status.Editing);StateHandler stateHandler new StateHandler();Result result stateHandler.arraignment(activityId, Status.Editing);logger.info(测试结果(编辑中To提审活动){}, JSON.toJSONString(result));logger.info(活动信息{} 状态{}, JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())); }测试结果 23:59:20.883 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To提审活动){code:0000,info:活动提审成功} 23:59:20.907 [main] INFO org.itstack.demo.design.test.ApiTest - 活动信息{activityId:100001,activityName:早起学习打卡领奖活动,beginTime:1593694760892,endTime:1593694760892,status:Check} 状态CheckProcess finished with exit code 0测试编辑中To提审活动的状态流转。 3.2 编写测试类(Editing2Open) Test public void test_Editing2Open() {String activityId 100001;ActivityService.init(activityId, Status.Editing);StateHandler stateHandler new StateHandler();Result result stateHandler.open(activityId, Status.Editing);logger.info(测试结果(编辑中To开启活动){}, JSON.toJSONString(result));logger.info(活动信息{} 状态{}, JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())); }测试结果 23:59:36.904 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To开启活动){code:0001,info:非关闭活动不可开启} 23:59:36.914 [main] INFO org.itstack.demo.design.test.ApiTest - 活动信息{activityId:100001,activityName:早起学习打卡领奖活动,beginTime:1593694776907,endTime:1593694776907,status:Editing} 状态EditingProcess finished with exit code 0测试编辑中To开启活动的状态流转。 3.3 编写测试类(Refuse2Doing) Test public void test_Refuse2Doing() {String activityId 100001;ActivityService.init(activityId, Status.Refuse);StateHandler stateHandler new StateHandler();Result result stateHandler.doing(activityId, Status.Refuse);logger.info(测试结果(拒绝To活动中){}, JSON.toJSONString(result));logger.info(活动信息{} 状态{}, JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())); }测试结果 23:59:46.339 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(拒绝To活动中){code:0001,info:审核拒绝不可执行活动为进行中} 23:59:46.352 [main] INFO org.itstack.demo.design.test.ApiTest - 活动信息{activityId:100001,activityName:早起学习打卡领奖活动,beginTime:1593694786342,endTime:1593694786342,status:Refuse} 状态RefuseProcess finished with exit code 0测试拒绝To活动中的状态流转。 3.4 编写测试类(Refuse2Revoke) Test public void test_Refuse2Revoke() {String activityId 100001;ActivityService.init(activityId, Status.Refuse);StateHandler stateHandler new StateHandler();Result result stateHandler.checkRevoke(activityId, Status.Refuse);logger.info(测试结果(拒绝To撤审){}, JSON.toJSONString(result));logger.info(活动信息{} 状态{}, JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())); }测试结果 23:59:50.197 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果(拒绝To撤审){code:0000,info:撤销审核完成} 23:59:50.208 [main] INFO org.itstack.demo.design.test.ApiTest - 活动信息{activityId:100001,activityName:早起学习打卡领奖活动,beginTime:1593694810201,endTime:1593694810201,status:Editing} 状态EditingProcess finished with exit code 0测试测试结果(拒绝To撤审)的状态流转。 综上以上四个测试类分别模拟了不同状态之间的有效流转和拒绝流转不同的状态服务处理不同的服务内容。 七、总结 从以上的两种方式对一个需求的实现中可以看到在第二种使用设计模式处理后已经没有了ifelse代码的结构也更加清晰易于扩展。这就是设计模式的好处可以非常强大的改变原有代码的结构让以后的扩展和维护都变得容易些。在实现结构的编码方式上可以看到这不再是面向过程的编程而是面向对象的结构。并且这样的设计模式满足了单一职责和开闭原则当你只有满足这样的结构下才会发现代码的扩展是容易的也就是增加和修改功能不会影响整体的变化。但如果状态和各项流转较多像本文的案例中就会产生较多的实现类。因此可能也会让代码的实现上带来了时间成本因为如果遇到这样的场景可以按需评估投入回报率。主要点在于看是否经常修改、是否可以做成组件化、抽离业务与非业务功能。
http://www.zqtcl.cn/news/992504/

相关文章:

  • 怎样审请网站集成装修全屋定制
  • 好看响应式网站模板下载可以访问的国外网站
  • 做电脑网站宽度网站建立安全连接失败
  • 西安网站设计哪家公司好my12777域名查询
  • 西宁网站建设排名网站设计对网站建设有哪些意义?
  • 北京平台网站建设价位怎样做网站卖网站
  • 网站建设与维护试题a卷建设银行官方网站买五粮液酒
  • 安装网站源码做文艺文创产品的网站
  • 软件公司网站设计与制作电子商务成功网站的案例
  • 购物车功能网站怎么做的建设众筹类网站
  • 哪些网站做的美爱站工具网
  • 对网站开发的理解源码资源网
  • 有哪些做兼职的网站网站建设的项目计划书
  • 如何做行业网站江苏城乡建设部网站首页
  • 淘客网站怎么做 知乎wordpress 删除插件
  • 深圳市住房和建设局人事调整公司网站seo怎么做
  • 小型影视网站源码好看的个人博客
  • 哈密建设厅网站西安培训机构
  • 网站建设公众号小程序开发密云网站开发
  • 南宁网站开发制作网站数据库分离怎么做
  • 不能打开建设银行网站怎么办自己做网站要会什么软件下载
  • 微软网站怎么做的diy个性定制
  • 洛阳做网站的公司宣传品牌网站建设
  • 公司网站开发招标书电子商务网站系统
  • 哪个旅游网站做的最好营销策划方案范文免费下载
  • 德州哪家网站优化公司专业单页网站seo如何优化
  • 南昌汉邦网站建设城建局
  • 网站建设:中企动力招聘网58同城招聘发布
  • 惠州住房和建设局网站物流网站建设方案范文
  • 做网站架构需要什么步骤wordpress插件连不上