> 技术文档 > 常用设计模式+集成websocket_actionjava设计模式

常用设计模式+集成websocket_actionjava设计模式


文章目录

    • 1.模板设计模式
        • 1.超类型
          • Action.java 行为能力接口
        • 2.具体模板
          • ApiTemplate.java 聚合行为能力,不同的行为能力,使得模板有不同的表现
        • 3.客户端
          • 1.ApiDemo.java
    • 2.工厂+策略设计模式
        • 1.PayChannelEnum.java 策略标识枚举
        • 2.超类型
          • PayHandler.java 策略能力接口
        • 3.具体实现
          • 1.BankPayHandler.java 银行支付策略
          • 2.WxPayHandler.java 微信支付策略
          • 3.ZfbPayHandler.java 支付宝支付策略
        • 4.支付策略工厂
          • PayFactory.java
        • 5.客户端
          • 1.ServiceHandler.java 业务层,根据code可以直接执行对应策略
          • 2.TestController.java 测试的controller
  • 集成websocket
    • 1.环境搭建
        • 1.创建新模块 sun-common-websocket
          • 1.pom.xml
          • 2.sun-common统一管理子模块
          • 3.删除sun-frame对websocket模块的管理
        • 2.配置依赖
          • 1.sun-dependencies
          • 2.sun-common-websocket
    • 2.基础应用
        • 1.目录结构
        • 2.WebSocketConfig.java(固定配置)
        • 3.WebSocketServerConfig.java
    • 3.sun-demo使用websocket
        • 1.引入依赖
        • 2.SysWebSocket.java

1.模板设计模式

1.超类型
Action.java 行为能力接口
package com.sunxiansheng.designPattern.template;/** * Description: 行为能力接口 * @Author sun * @Create 2024/7/22 10:18 * @Version 1.0 */public interface Action { /** * 参数校验 */ void validate(); /** * 执行 */ void execute(); /** * 后续 */ void after();}
2.具体模板
ApiTemplate.java 聚合行为能力,不同的行为能力,使得模板有不同的表现
package com.sunxiansheng.designPattern.template;import com.sunxiansheng.response.Result;/** * Description: api模板 * @Author sun * @Create 2024/7/22 10:17 * @Version 1.0 */public class ApiTemplate { /** * 执行方法聚合Action的不同对象逻辑,从而实现模板的动态变化 * @param result * @param action */ public void execute(Result result, final Action action) { try { action.validate(); action.execute(); action.after(); result.setSuccess(true); result.setCode(200); } catch (Exception e) { result.setSuccess(false); result.setCode(500); } }}
3.客户端
1.ApiDemo.java
package com.sunxiansheng.designPattern.template;import com.sunxiansheng.response.Result;/** * Description: * @Author sun * @Create 2024/7/22 10:23 * @Version 1.0 */public class ApiDemo { public static void main(String[] args) { ApiTemplate apiTemplate = new ApiTemplate(); Result result = Result.ok(); // 这个模板,根据传入的不同行为,就会有不同的体现 apiTemplate.execute(result, new Action() { @Override public void validate() { System.out.println(\"开始校验\"); } @Override public void execute() { System.out.println(\"执行\"); } @Override public void after() { System.out.println(\"后续执行\"); } }); }}

2.工厂+策略设计模式

1.PayChannelEnum.java 策略标识枚举
package com.sunxiansheng.designPattern.factoryandstragy;import lombok.Getter;/** * Description: 支付策略的类型枚举 * @Author sun * @Create 2024/7/22 10:54 * @Version 1.0 */@Getterpublic enum PayChannelEnum { ZFB_PAY(0, \"支付宝支付\"), WX_PAY(1, \"微信支付\"), BANK_PAY(2, \"银行支付\"); private int code; private String desc; PayChannelEnum(int code, String desc) { this.code = code; this.desc = desc; } /** * 根据code来获取枚举 * @param code * @return */ public static PayChannelEnum getByCode(int code) { for (PayChannelEnum payChannelEnum : PayChannelEnum.values()) { if (payChannelEnum.code == code) { return payChannelEnum; } } return null; }}
2.超类型
PayHandler.java 策略能力接口
package com.sunxiansheng.designPattern.factoryandstragy;/** * Description: 支付策略的能力接口 * @Author sun * @Create 2024/7/22 10:53 * @Version 1.0 */public interface PayHandler { /** * 标识自己的类型的能力 * @return */ PayChannelEnum getChannel(); /** * 解决支付的能力 */ void dealPay();}
3.具体实现
1.BankPayHandler.java 银行支付策略
package com.sunxiansheng.designPattern.factoryandstragy.handler;import com.sunxiansheng.designPattern.factoryandstragy.PayChannelEnum;import com.sunxiansheng.designPattern.factoryandstragy.PayHandler;import org.springframework.stereotype.Component;/** * Description: 银行支付策略 * @Author sun * @Create 2024/7/22 10:51 * @Version 1.0 */@Componentpublic class BankPayHandler implements PayHandler { /** * 标识自己的类型 * @return */ @Override public PayChannelEnum getChannel() { return PayChannelEnum.BANK_PAY; } /** * 银行支付策略 */ @Override public void dealPay() { System.out.println(\"银行支付策略\"); }}
2.WxPayHandler.java 微信支付策略
package com.sunxiansheng.designPattern.factoryandstragy.handler;import com.sunxiansheng.designPattern.factoryandstragy.PayChannelEnum;import com.sunxiansheng.designPattern.factoryandstragy.PayHandler;import org.springframework.stereotype.Component;/** * Description: 微信支付策略 * @Author sun * @Create 2024/7/22 10:51 * @Version 1.0 */@Componentpublic class WxPayHandler implements PayHandler { /** * 标识自己的类型 * @return */ @Override public PayChannelEnum getChannel() { return PayChannelEnum.WX_PAY; } @Override public void dealPay() { System.out.println(\"微信支付策略\"); }}
3.ZfbPayHandler.java 支付宝支付策略
package com.sunxiansheng.designPattern.factoryandstragy.handler;import com.sunxiansheng.designPattern.factoryandstragy.PayChannelEnum;import com.sunxiansheng.designPattern.factoryandstragy.PayHandler;import org.springframework.stereotype.Component;/** * Description: 支付宝支付策略 * @Author sun * @Create 2024/7/22 10:51 * @Version 1.0 */@Componentpublic class ZfbPayHandler implements PayHandler { /** * 标识自己的类型 * @return */ @Override public PayChannelEnum getChannel() { return PayChannelEnum.ZFB_PAY; } @Override public void dealPay() { System.out.println(\"支付宝支付策略\"); }}
4.支付策略工厂
PayFactory.java
package com.sunxiansheng.designPattern.factoryandstragy;import org.springframework.beans.factory.InitializingBean;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.util.HashMap;import java.util.List;import java.util.Map;/** * Description: 获取策略对象的工厂 * @Author sun * @Create 2024/7/22 11:07 * @Version 1.0 */@Componentpublic class PayFactory implements InitializingBean { /** * 所有的具体支付策略的对象逻辑会被注入到这里 */ @Resource private List<PayHandler> payHandlerList; /** * 存储策略标识和具体策略的map */ private Map<PayChannelEnum, PayHandler> handlerMap = new HashMap<>(); /** * 根据枚举的code来获取对应的策略 * @param code * @return */ public PayHandler getHandlerByCode(int code) { PayChannelEnum byCode = PayChannelEnum.getByCode(code); return handlerMap.get(byCode); } /** * 在bean初始化之后,这个方法会被调用 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { // 将所有的策略从list放到map中,直接通过枚举即可获得对应的策略 for (PayHandler payHandler : payHandlerList) { handlerMap.put(payHandler.getChannel(), payHandler); } }}
5.客户端
1.ServiceHandler.java 业务层,根据code可以直接执行对应策略
package com.sunxiansheng.designPattern.factoryandstragy;import org.springframework.stereotype.Service;import javax.annotation.Resource;/** * Description: 业务层 * @Author sun * @Create 2024/7/22 12:10 * @Version 1.0 */@Servicepublic class ServiceHandler { /** * 依赖存放策略的策略工厂 */ @Resource private PayFactory payFactory; public void dealPay(int code) { PayHandler handlerByCode = payFactory.getHandlerByCode(code); handlerByCode.dealPay(); }}
2.TestController.java 测试的controller
package com.sunxiansheng.designPattern.factoryandstragy;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import javax.annotation.Resource;import java.util.Objects;/** * Description: 测试的controller * @Author sun * @Create 2024/7/22 12:15 * @Version 1.0 */@Controllerpublic class PayTestController { @Resource private ServiceHandler serviceHandler; @RequestMapping(\"/payTest/{payType}\") public void test(@PathVariable(\"payType\") String payType) { // 根据类型来判断使用哪个策略 if (Objects.equals(payType, \"支付宝\")) { serviceHandler.dealPay(PayChannelEnum.ZFB_PAY.getCode()); } else if (Objects.equals(payType, \"微信\")) { serviceHandler.dealPay(PayChannelEnum.WX_PAY.getCode()); } else if (Objects.equals(payType, \"银行\")) { serviceHandler.dealPay(PayChannelEnum.BANK_PAY.getCode()); } }}

集成websocket

1.环境搭建

1.创建新模块 sun-common-websocket
1.pom.xml
<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"> <modelVersion>4.0.0</modelVersion>  <parent> <groupId>com.sunxiansheng</groupId> <artifactId>sun-common</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>sun-common-websocket</artifactId>  <version>${children.version}</version></project>
2.sun-common统一管理子模块
3.删除sun-frame对websocket模块的管理
2.配置依赖
1.sun-dependencies
 <spring.websocket.version>2.4.2</spring.websocket.version> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>${spring.websocket.version}</version> </dependency>
2.sun-common-websocket
 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies>

2.基础应用

1.目录结构
2.WebSocketConfig.java(固定配置)
package com.sunxiansheng.websocket.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * Description: websocket配置类(固定配置) * @Author sun * @Create 2024/7/23 10:07 * @Version 1.0 */@Configurationpublic class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}
3.WebSocketServerConfig.java
package com.sunxiansheng.websocket.config;import org.springframework.stereotype.Component;import org.springframework.util.CollectionUtils;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import javax.websocket.HandshakeResponse;import javax.websocket.server.HandshakeRequest;import javax.websocket.server.ServerEndpointConfig;import java.util.List;import java.util.Map;/** * Description: websocket鉴权和获取信息 * @Author sun * @Create 2024/7/23 10:10 * @Version 1.0 */@Componentpublic class WebSocketServerConfig extends ServerEndpointConfig.Configurator { /** * 鉴权 * @param originHeaderValue * @return */ @Override public boolean checkOrigin(String originHeaderValue) { // 获取request ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = servletRequestAttributes.getRequest(); // ============================== 校验逻辑 ============================== // 校验失败就返回false // ============================== 校验逻辑 ============================== return true; } /** * 获取信息 * @param sec * @param request * @param response */ @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { Map<String, List<String>> parameterMap = request.getParameterMap(); // 这里从参数中获取名为erp的信息 List<String> erpList = parameterMap.get(\"erp\"); // 如果不为空,就放到UserProperties中,使得socket可以读取 if (!CollectionUtils.isEmpty(erpList)) { sec.getUserProperties().put(\"erp\", erpList.get(0)); } }}

3.sun-demo使用websocket

1.引入依赖
  <dependency> <groupId>com.sunxiansheng</groupId> <artifactId>sun-common-websocket</artifactId> <version>${sun-common-version}</version> </dependency>
2.SysWebSocket.java
package com.sunxiansheng.user.websocket;import com.sunxiansheng.websocket.config.WebSocketServerConfig;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.atomic.AtomicInteger;@Slf4j// 设置WebSocket路径,配置创建的WebSocketCheckConfig鉴权配置类@ServerEndpoint(value = \"/sys/socket\", configurator = WebSocketServerConfig.class)@Componentpublic class SysWebSocket { /** * 记录当前在线连接数 */ private static AtomicInteger onlineCount = new AtomicInteger(0); /** * 存放所有在线的客户端 */ private static Map<String, SysWebSocket> clients = new ConcurrentHashMap<>(); /** * 与某个客户端的连接会话,需要通过它来给客户端发送数据 */ private Session session; /** * 当前会话的唯一标识key */ private String erp = \"\"; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session, EndpointConfig conf) throws IOException { //获取用户信息 try { // 获取用户配置 Map<String, Object> userProperties = conf.getUserProperties(); // 从用户配置中获取\"erp\"的用户内容 String erp = (String) userProperties.get(\"erp\"); this.erp = erp; this.session = session; // 如果在线的客户端中存在这个用户,则先关闭下线 if (clients.containsKey(this.erp)) { clients.get(this.erp).session.close(); clients.remove(this.erp); onlineCount.decrementAndGet(); } // 将当前用户再连接上去 clients.put(this.erp, this); onlineCount.incrementAndGet(); log.info(\"有新连接加入:{},当前在线人数为:{}\", erp, onlineCount.get()); sendMessage(\"连接成功\", this.session); } catch (Exception e) { log.error(\"建立链接错误{}\", e.getMessage(), e); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { try { if (clients.containsKey(erp)) { clients.get(erp).session.close(); clients.remove(erp); onlineCount.decrementAndGet(); } log.info(\"有一连接关闭:{},当前在线人数为:{}\", this.erp, onlineCount.get()); } catch (Exception e) { log.error(\"连接关闭错误,错误原因{}\", e.getMessage(), e); } } /** * 收到客户端消息后调用的方法 */ @OnMessage public void onMessage(String message, Session session) { log.info(\"服务端收到客户端[{}]的消息:{}\", this.erp, message); // 模拟心跳机制: // 前端可以通过setInterval定时任务每个15秒钟调用一次reconnect函数 // reconnect会通过socket.readyState来判断这个websocket连接是否正常 // 如果不正常就会触发定时连接,每15s钟重试一次,直到连接成功 if (message.equals(\"ping\")) { this.sendMessage(\"pong\", session); } } @OnError public void onError(Session session, Throwable error) { log.error(\"Socket:{},发生错误,错误原因{}\", erp, error.getMessage(), error); try { session.close(); } catch (Exception e) { log.error(\"onError.Exception{}\", e.getMessage(), e); } } /** * 指定发送消息 */ public void sendMessage(String message, Session session) { log.info(\"服务端给客户端[{}]发送消息:{}\", this.erp, message); try { session.getBasicRemote().sendText(message); } catch (IOException e) { log.error(\"{}发送消息发生异常,异常原因{}\", this.erp, message); } } /** * 群发消息 */ public void sendMessage(String message) { for (Map.Entry<String, SysWebSocket> sessionEntry : clients.entrySet()) { String erp = sessionEntry.getKey(); SysWebSocket socket = sessionEntry.getValue(); Session session = socket.session; log.info(\"服务端给客户端[{}]发送消息{}\", erp, message); try { session.getBasicRemote().sendText(message); } catch (IOException e) { log.error(\"{}发送消息发生异常,异常原因{}\", this.erp, message); } } }}