Springboot集成redis和mybatis-plus及websocket异常框架代码封装

在软件开发过程中,一款封装完善简洁大气的全家桶框架,能大大提升开发人员的工作效率,同时还能降低代码的复杂程序,也便于后期方便维护。本文所涉及源代码在文章最后,有下载链接。

本文章所涉及封装的框架,可直接用于项目开发。

在集成软件开发框架时,我们需要考虑哪些要素:

1、用哪些技术

2、异常信息的处理

3、日志的打印,最好是能带参数打印sql日志(非问号形式的带参sql),本框架就是带参数打印sql,方便调试

4、接口返回数据格式的封装(瞧不起一些垃圾封装)

本博文主要分五大块讲解,分别为websocket的使用、mybatis-plus的使用、redis的使用、异常信息怎么使用、日志打印(重点是带参数打印sql语句,方便开发调式)

一、Websockt的集成
1、初始化配置
@Configuration
public class WebSocketConfig  {
    /**
     * 会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     * 要注意,如果使用独立的servlet容器,
     * 而不是直接使用springboot的内置容器,
     * 就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
2、服务端收消息
@Slf4j
@Component
@ServerEndpoint(value = "/websocket")
public class WebsocketGet {

    /**
     * 连接事件,加入注解
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        String orderId = WebsocketSend.getParam(WebsocketSend.sessionKey, session);
        log.info("Websocket连接已打开,当前orderId为:"+orderId);
        // 添加到session的映射关系中
        WebsocketSend.addSession(orderId, session);
        //测试发送消息
        WebsocketSend.sendMessage(orderId, WsResultVo.success("恭喜,已建立连接"));
    }
    /**
     * 一、websocker (2)接收到客户端用户上传的消息
     * @param session
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("收到Websocket消息:"+message);
    }
    /**
     * 连接事件,加入注解
     * 用户断开链接
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        String orderId = WebsocketSend.getParam(WebsocketSend.sessionKey, session);
        // 删除映射关系
        WebsocketSend.removeSession(orderId);
    }

    /**
     * 处理用户活连接异常
     *
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        try {
            if (session.isOpen()) {
                session.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        throwable.printStackTrace();
    }
}
3、向客户端发送消息
/**
 * Websocket工具类
 * 记录当前在线的链接对链接进行操作
 */
public class WebsocketSend {
    /**
     * 日志信息
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketSend.class);
    /**
     * 记录当前在线的Session
     */
    private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
    public static final String sessionKey = "orderId";

    /**
     * 添加session
     *
     * @param userId
     * @param session
     */
    public static void addSession(String userId, Session session) {
        // 此处只允许一个用户的session链接。一个用户的多个连接,我们视为无效。
        ONLINE_SESSION.putIfAbsent(userId, session);
    }

    /**
     * 关闭session
     *
     * @param userId
     */
    public static void removeSession(String userId) {
        ONLINE_SESSION.remove(userId);
    }

    /**
     * 给单个用户推送消息
     *
     * @param session
     * @param message
     */
    public static void sendMessage(Session session, String message) {
        if (session == null) {
            return;
        }

        // 同步
        RemoteEndpoint.Async async = session.getAsyncRemote();
        async.sendText(message);
    }

    /**
     * 向所有在线人发送消息
     *
     * @param message
     */
    public static void sendMessageForAll(String message) {
        //jdk8 新方法
        ONLINE_SESSION.forEach((sessionId, session) -> {
            if (session.isOpen()) {
                sendMessage(session, message);
            }
        });
    }

    /**
     * 根据用户ID发送消息
     *
     * @param result
     */
    public static void sendMessage(String sessionId, WsResultVo result) {
        sendMessage(sessionId, JSON.toJSONString(result));
    }

    /**
     * 根据用户ID发送消息
     *
     * @param message
     */
    public static void sendMessage(String sessionId, String message) {
        Session session = ONLINE_SESSION.get(sessionId);
        //判断是否存在该用户的session,判断是否还在线
        if (session == null || !session.isOpen()) {
            return;
        }
        sendMessage(session, message);
    }

    /**
     * 根据ID获取Session
     *
     * @param sessionId
     */
    public static Session getSession(String sessionId) {
        Session session = ONLINE_SESSION.get(sessionId);
        return session;
    }

    /**
     * 根据传过来的key获取session中的参数
     * @param key
     * @param session
     * @return
     */
    public static String getParam(String key, Session session) {
        Map map = session.getRequestParameterMap();
        Object userId1 = map.get(key);
        if (userId1 == null) {
            return null;
        }

        String s = userId1.toString();
        s = s.replaceAll("\\[", "").replaceAll("]", "");

        if (!StringUtils.isEmpty(s)) {
            return s;
        }
        return null;
    }

}
4,websocket测试(客户端我们用apifox软件,自行百度下载)

先启动服务端,运行ServerApplication.java,然后apifox,点击连接服务器,如下截图

点击【连接】请求地址:ws://127.0.0.1:8080/ck/websocket?orderId=123456,注意参数orderId必填

(1)客户端apifox向服务端发送消息

(2)服务器端向客户端发送消息,打开swagger地址:http://localhost:8080/ck/swagger-ui.html

通过swagger调用后端接口,后端收到接口请求,再向websocket客户端发送消息

二、Mybatis-plus的集成
1、初始化配置
@Configuration
@MapperScan("com.ck.server.web.mapper")
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }
}
2、接口的使用

 打开swagger地址:http://localhost:8080/ck/swagger-ui.html

3、mybatis-pluse的增、删、查、保存

controller部分

@GetMapping("/mybatis-plus/getPage")
    @ApiOperation("二、Mybatis-plus查询(1)分页查询")
    public PageBeanVo<User> getPage(UserParam param) {
        PageBeanVo pageBeanVo = userService.getPage(param);
        return pageBeanVo;
    }

    @PostMapping("/mybatis-plus/save")
    @ApiOperation("二、Mybatis-plus查询(2)保存")
    public ResultInfoVo save(String name,Integer age,String email) {
        User user = new User();
        user.setName(name);
        user.setAge(age);
        user.setEmail(email);
        userService.save(user);
        return new ResultInfoVo();
    }

    @GetMapping("/mybatis-plus/getById")
    @ApiOperation("二、Mybatis-plus查询(3)根据id查询")
    public ResultInfoVo<User> getById(Integer id) {
        User user = userService.getById(id);
        return new ResultInfoVo(user);
    }

    @DeleteMapping("/mybatis-plus/deleteById")
    @ApiOperation("二、Mybatis-plus查询(4)根据id删除")
    public ResultInfoVo<User> deleteById(Integer id) {
         userService.deleteById(id);
        return new ResultInfoVo();
    }

service部分

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 根据id查询
     * @param id
     * @return
     */
    public User getById(Integer id){
        return userMapper.selectById(id);
    }
    /**
     * 分页查询
     * @param param
     * @return
     */
    public PageBeanVo<User> getPage(UserParam param){
        IPage<User> page = userMapper.getPage(param);
        System.out.println(page);
        return new PageBeanVo(page.getTotal(),page.getRecords());
    }
    /**
     * 保付
     * @param user
     */
    @Transactional
    public void save(User user){
        userMapper.insert(user);
    }
    /**
     * 保付
     * @param id
     */
    @Transactional
    public void deleteById(Integer id){
        userMapper.deleteById(id);
    }
}

mapper部分

public interface UserMapper extends BaseMapper<User> {
    /**
     * 分页查询
     * @param pageParam
     * @return
     */
    IPage<User> getPage(IPage pageParam);
}

mapper对应的xml的部分

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ck.server.web.mapper.UserMapper">
    <select id="getPage" resultType="com.ck.server.web.model.User">
        SELECT * FROM  user WHERE 1=1
        <if test="id!= null and id!= ''">
            and id =#{id}
        </if>
        <if test="name!= null and name!= ''">
            and name like concat('%',#{name},'%')
        </if>
    </select>
</mapper>

来个分页查询的截图:

三、redis集成
1、初始化配置
@Configuration
public class RedisConfig {
	@Bean
	public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
		RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
//		redisTemplate.setKeySerializer(new StringRedisSerializer());
//		redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
		RedisSerializer stringSerializer = new StringRedisSerializer();
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);

		redisTemplate.setKeySerializer(stringSerializer);
		redisTemplate.setHashKeySerializer(stringSerializer);

		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.setConnectionFactory(connectionFactory);
		return redisTemplate;
	}
}
2、redis的使用
@PostMapping("/redis/redisSave")
    @ApiOperation("三、redis缓存(1)保存到redis")
    public ResultInfoVo<User> redisSave(String key,String value) {
        redisService.addString(key,value);
        return new ResultInfoVo();
    }

    @GetMapping("/redis/redisFind")
    @ApiOperation("三、redis缓存(2)查询redis")
    public ResultInfoVo<User> redisFind(String key) {
        String value = redisService.getString(key);
        return new ResultInfoVo(value);
    }

3、保存和查询截图

四、异常信息

异常信息结构和接口数据返回的数据结构是一致的

如接口返回的结构如下

1、封装对象
@ToString
@ApiModel()
public class ResultInfoVo<T> {

    public static final String SUCCESS="success";
    public static final String FAILED="failed";

    @ApiModelProperty(value = "业务code:成功为success,失败为其它业务,如roleIdIsNull")
    private String code="success";//业务code 成功为 success  失败为 其它业务编号,如paramIsNull
    @ApiModelProperty(value = "描述信息")
    private String message="处理成功";//描述信息
    @ApiModelProperty(value = "业务数据")
    public T data;//页数据


    public ResultInfoVo(){}

    public ResultInfoVo(T data) {
        this.data = data;
    }

    public ResultInfoVo(String message,T data) {
        this.message = message;
        this.data = data;
    }

    public ResultInfoVo(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public ResultInfoVo( String code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
}

异常信息返回的对象

public class CKException extends RuntimeException {
    private Log logger = LogFactory.getLog(getClass());
    @ApiModelProperty(value = "业务code:成都为success,失败为其它业务,如roleIdIsNull")
    private String code;//业务错误码
    @ApiModelProperty(value = "描述信息")
    private String message;//错误详情
    @ApiModelProperty(value = "其它数据")
    private Object data;//其它数据


    public CKException(String code, String message) {
        this.code = code;
        this.message = message;
        this.data=data;
    }


    public CKException(String code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data=data;
    }
}

2、使用:

五、接口返回数据格式的封装
package com.ck.server.web.model.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.ToString;

/**
 * Created by Administrator on 2018/7/2.
 */
@ToString
@ApiModel()
public class ResultInfoVo<T> {

    public static final String SUCCESS="success";
    public static final String FAILED="failed";

    @ApiModelProperty(value = "业务code:成功为success,失败为其它业务,如roleIdIsNull")
    private String code="success";//业务code 成功为 success  失败为 其它业务编号,如paramIsNull
    @ApiModelProperty(value = "描述信息")
    private String message="处理成功";//描述信息
    @ApiModelProperty(value = "业务数据")
    public T data;//页数据


    public ResultInfoVo(){}

    public ResultInfoVo(T data) {
        this.data = data;
    }

    public ResultInfoVo(String message,T data) {
        this.message = message;
        this.data = data;
    }

    public ResultInfoVo(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public ResultInfoVo( String code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
六、源代码下载:

链接:https://pan.baidu.com/s/16snuaL2X3oPelNm6uSMv4Q?pwd=dy7p 
提取码:dy7p

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/121201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android修行手册-实现利用POI将图片插入到Excel中(文末送书)

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

C# 查询腾讯云直播流是否存在的API实现

应用场景 在云考试中&#xff0c;为防止作弊行为的发生&#xff0c;会在考生端部署音视频监控系统&#xff0c;当然还有考官方监控墙系统。在实际应用中&#xff0c;考生一方至少包括两路直播流&#xff1a; &#xff08;1&#xff09;前置摄像头&#xff1a;答题的设备要求使…

Spring Boot + EasyUI Datebox和Datetimebox样例

使用EasyUI的Datebox和Datetimebox组件&#xff0c;并对其进行适当的改造&#xff0c;比如更改日期格式、设置默认值或者将当前时间设置为默认值。 一、运行结果 二、实现代码 1.代码框架 2.实现代码 SpringBootMainApplication.java: package com.xj.main;import org.spri…

奇安信360天擎getsimilarlist存在SQL注入漏洞

奇安信360天擎getsimilarlist存在SQL注入漏洞 一、产品描述二、漏洞描述三、漏洞复现1.手动复现2.自动化复现①nulei扫描yaml ②小龙POC检测工具下载地址 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的…

oled显示器程序(IIC)从stm32f103移植到stm32f429出现bug不显示-解决移植失败问题

出现问题处&#xff1a; 刚开始更换了这两行代码&#xff0c;然后更换位置后&#xff0c;oled正常显示&#xff0c;如下为正确顺序 I2C_Configuration();//配置CPU的硬件I2COLED_Init();//OLED初始化 在这段代码中&#xff0c;I2C_Configuration() 函数用于配置CPU的硬件 I2C…

什么变量能够影响苦艾酒的味道?

没有一个答案可以描述每种苦艾酒的味道&#xff0c;因为每个生产商生产的苦艾酒都不一样。甜苦艾酒的味道与干苦艾酒不同&#xff0c;即使在这些类别中&#xff0c;甜的和干的苦艾酒的味道也会彼此不同&#xff0c;这取决于制造商、他们使用的草药和植物药的类型、他们用这些植…

如何估算业务需要多少代理IP量?

在互联网相关的行业中&#xff0c;很多业务都需要用到代理IP工具&#xff0c;比如数据采集、市场调查、SEO优化、品牌保护、跨境运营等&#xff0c;可以说代理IP已成为许多业务中不可或缺的一部分。代理IP可以帮助用户隐蔽真实IP地址&#xff0c;提高网络活动的范围和安全性&am…

会打字就能编程,自动写代码的ai助手 | 通义灵码

通义灵码介绍 通义灵码是一款由阿里云出品的智能编码辅助工具。 它基于通义大模型&#xff0c;可以提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力。 它支持Java、Python、Go、C/C、JavaScript、Type…

机器人阻抗与导纳控制的区别

机器人自身的非线性动力学&#xff08;由柔软性引起的&#xff09;导致控制精度下降&#xff0c;因此难以描述准确的动力学。 导纳控制和阻抗控制都是基于位置与力关系的模式&#xff0c;被认为具有鲁棒性和安全性。然而&#xff0c;当机器人与刚体接触时&#xff0c;导纳控制常…

【Qt之QVariant】使用

介绍 QVariant类类似于最常见的Qt数据类型的联合。由于C禁止联合类型包括具有非默认构造函数或析构函数的类型&#xff0c;大多数有趣的Qt类不能在联合中使用。如果没有QVariant&#xff0c;则QObject::property()和数据库操作等将会受到影响。 QVariant对象同时持有一个单一…

基于单片机的多层电梯控制仿真系统

**单片机设计介绍&#xff0c; 基于单片机的多层电梯控制仿真系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的多层电梯控制仿真系统是一个复杂的系统&#xff0c;它需要结合单片机技术、控制理论、电子技术以及人…

使用swagger-typescript-api

引言 前后端分离大致是这样的 后端&#xff1a;控制层 / 业务层 / 数据操作层前端&#xff1a;控制层 / 视图层 前后端的控制层&#xff0c;实际上就是前后端接口的对接 前后端分离&#xff0c;实现了更好地解耦合&#xff0c;但也引入了接口对接的过程&#xff0c;这个过程…

C++ STL - map 与 multimap用法和区别

目录 一、概述 二、用法 2.1、插入 2.2、拷贝与赋值 2.3、查找 2.4、删除 2.5、完整代码 三、其他成员类型 一、概述 map 与 multimap是存储key-value&#xff08;键-值 对&#xff09;类型的容器。不同之处在于&#xff1a;map只允许key与 value一一对应&#xff1b;…

asp.net core mvc之路由

一、默认路由 &#xff08;Startup.cs文件&#xff09; routes.MapRoute(name: "default",template: "{controllerHome}/{actionIndex}/{id?}" ); 默认访问可以匹配到 https://localhost:44302/home/index/1 https://localhost:44302/home/index https:…

PTL货位指引标签为仓储管理打开新思路

PTL货位指引标签是一种新型的仓储管理技术&#xff0c;它通过LED灯光指引和数字显示&#xff0c;为仓库管理带来了全新的管理思路和效率提升&#xff0c;成为现代物流仓库管理中的重要工具。 首先&#xff0c;PTL货位指引标签为仓储管理业务带来了管理新思路。传统的仓库管理中…

OFDM深入学习及MATLAB仿真

文章目录 前言一、OFDM 基本原理及概念1、OFDM 简介2、子载波3、符号4、子载波间隔与符号长度之间的关系 二、涉及的技术1、保护间隔2、交织3、信道编码4、扩频5、导频6、RF&#xff08;射频&#xff09;调制7、信道估计 三、变量间的关系四、IEEE 802.11a WLAN PHY 层标准五、…

matlab中的mapminmax函数初步理解和应用

matlab中的mapminmax函数初步认识 一、mapminmax 顾名思义&#xff1a;映射最大最小 二、语法及举例 2.1 语法1 [Y,PS] mapminmax(X) 将矩阵X映射形成矩阵Y, Y中每行中的最小值对应-1&#xff0c;最大值对应1。PS是一个包含映射信息的结构体。 举例&#xff1a; clc cle…

Jupyter Notebook 闪退

造成这个的原因非常非常多&#xff01; 比如什么环境变量没有配置&#xff0c;或者说jupyter和python版本不兼容&#xff0c;库不兼容等等。 但是我呢&#xff0c;以上都不是。 我是因为手残&#xff0c;删掉了不该删的文件&#xff1a; 这个操作就是打开"Anaconda Prom…

在react中组件间过渡动画如何实现?

一、是什么 在日常开发中&#xff0c;页面切换时的转场动画是比较基础的一个场景 当一个组件在显示与消失过程中存在过渡动画&#xff0c;可以很好的增加用户的体验 在react中实现过渡动画效果会有很多种选择&#xff0c;如react-transition-group&#xff0c;react-motion&…

Vb6 TCP Server服务端监听多个RFID读卡器客户端上传的刷卡数据

本示例使用设备介绍&#xff1a;WIFI无线4G网络RFID云读卡器远程网络开关物流网阅读器TTS语音-淘宝网 (taobao.com) Option ExplicitConst BUSY As Boolean False 定义常量 Const FREE As Boolean TrueDim ConnectState() As Boolean 定义连接状态 Dim ServerSendbuf(…