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

news2024/11/24 2:33:23

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis系列-Redis过期策略以及内存淘汰机制【6】

目录 Redis系列-Redis过期策略以及内存淘汰机制【6】redis过期策略内存淘汰机制算法LRU算法LFU 其他场景对过期key的处理FAQ为什么不用定时删除策略? Ref 个人主页: 【⭐️个人主页】 需要您的【&#x1f496; 点赞关注】支持 &#x1f4af; Redis系列-Redis过期策略以及内存淘…

js:React中使用classnames实现按照条件将类名连接起来

参考文档 https://www.npmjs.com/package/classnameshttps://github.com/JedWatson/classnames 安装 npm install classnames示例 import classNames from "classnames";// 字符串合并 console.log(classNames("foo", "bar")); // foo bar//…

学之思开源考试系统部署至Centos7

学之思开源考试系统部署至Centos7 1、下载源码 源码下载&#xff1a; https://gitee.com/mindskip/xzs-mysql 数据库脚本下载&#xff1a; https://www.mindskip.net:999/ 2、项目打包 分别在\source\vue\xzs-student目录和source\vue\xzs-admin目录&#xff0c;执行前端打…

Improved Population Control for More Efficient Multimodal Optimizers

多模态优化 NC-VMO means ‘Niche-Clearing-based VMO’&#xff0c;ASD means ‘Adaptive Species Discovery’&#xff0c;HVcMO means ‘Clustering-based Variable Mesh Optimization’ N c A _c^A cA​是A的推荐种群规模&#xff0c;inc means ‘increment’&#xff0c;…

中国芯片产能加速增长,美芯销量下滑,难怪美芯和ASML都低头了

日前分析机构给出的数据指中国的芯片产量呈现加速增长的趋势&#xff0c;伴随的就是芯片进口在下滑&#xff0c;国产芯片的加速替代&#xff0c;已给美国芯片等海外芯片行业造成巨大的打击。 分析机构给出的数据指今年3-6月中国的芯片产能都在稳步增长&#xff0c;不过增长为个…

如何检测小红书账号是否被限流?哪些原因会导致账号被限流?

hi&#xff0c;同学们&#xff0c;本期是第5期AI运营技巧篇&#xff0c;文章底部准备了粉丝福利&#xff0c;看完后可领取&#xff01; 最近好多新手学员运营小红书账号&#xff0c;可能会遇到这样的问题&#xff1a;发布的内容小眼睛少得可怜&#xff1f;搜索不到自己的笔记&…

Qt开发环境搭建

Index of /official_releases/online_installers (qt.io)

Xmake v2.8.5 发布,支持链接排序和单元测试

Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量&#xff0c;没有任何依赖&#xff0c;因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建&#xff0c;相比 makefile/CMakeLists.txt&#xff0c;配置语法更加简洁直观&#xff0c;对新手非常友好&#x…

(六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题

前言 本节内容是关于使用分布式锁解决并发访问“超卖”问题的最终篇&#xff0c;在前面的章节中我们介绍了使用mysql的行锁、乐观锁、悲观锁解决并发访问导致的超卖问题&#xff0c;存在的问题是行锁、乐观锁、悲观锁不太灵活&#xff0c;需要和具体的业务耦合到一起&#xff…

盘点几种常用加密算法

文章目录 前言常用算法DES算法DES算法特点DES算法示例 AES算法AES算法特点AES算法示例 RSA算法RSA算法特点RSA算法示例 MD5算法MD5算法特点MD5算法示例 SHA算法SHA算法特点SHA算法示例 总结写在最后 前言 随着互联网的发展,信息安全问题日益受到重视。加密算法在保证信息安全传…

力扣算法-----一刷总结

之前学习算法题坚持不了几天就很容易放弃&#xff0c;一直没怎么系统的练习&#xff0c;偶然发现代码随想录居然推出了算法训练营&#xff0c;趁着时间比较足报了名跟着学习了两个月。 过去的两个月&#xff0c;中间伴着各种琐事&#xff0c;但还是坚持了下来&#xff0c;走过…

网络安全之CSRF漏洞原理和实战,以及CSRF漏洞防护方法

一、引言 总体来说CSRF属于一种欺骗行为&#xff0c;是一种针对网站的恶意利用&#xff0c;尽管听起来像跨站脚本&#xff08;XSS&#xff09;&#xff0c;但是与XSS非常不同&#xff0c;并且攻击方式几乎向佐。XSS利用站点内的信任用户&#xff0c;而CSRF则通过伪装来自受信任…

如何使用ArcGIS Pro制作个性三维地形图

制作三维地图制作的多了&#xff0c;想着能不能换个“口味”&#xff0c;恰好看见制作六边形蜂窝图&#xff0c;灵光一闪&#xff0c;想着将二者结合&#xff0c;将平滑的三维地形图改成柱状图&#xff0c;从结果来看还可以&#xff0c;这里将制作方法分享给大家&#xff0c;希…

基于51单片机太阳能热水器控制系统-proteus仿真-程序

、系统方案 系统设计将软件设计内容分为了六大模块&#xff0c;分别是蜂鸣器报警、水位检测、DS18B20模块、液晶显示、加热模块、按键模块&#xff0c;系统将其进行分别设计&#xff0c;接通电源之后&#xff0c;单片机分别向LCD1602液晶显示器、DS18B20模块、和按键发出初始化…

C【整数正序分解】

// 整数正序分解 #include <stdio.h> #include <stdlib.h>int main() {int x;scanf("%d", &x);// 13425/10000->1(int一个d)// 13425%10000->3425(这是x)// 10000/10-.1000(这是mask)int mask 1;int t x;while (t > 9){t / 10;mask * 10;…

安装dubbo-admin报错node版本和test错误

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;dubbo-admin安装 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0…

JAVA安全之Log4j-Jndi注入原理以及利用方式

什么是JNDI&#xff1f; JDNI&#xff08;Java Naming and Directory Interface&#xff09;是Java命名和目录接口&#xff0c;它提供了统一的访问命名和目录服务的API。 JDNI主要通过JNDI SPI&#xff08;Service Provider Interface&#xff09;规范来实现&#xff0c;该规…

matlab中实现画函数图像添加坐标轴

大家好&#xff0c;我是带我去滑雪&#xff01; 主函数matlab代码&#xff1a; function PlotAxisAtOrigin(x,y); if nargin 2 plot(x,y);hold on; elsedisplay( Not 2D Data set !) end; Xget(gca,Xtick); Yget(gca,Ytick); XLget(gca,XtickLabel); YLget(gca,YtickLabel)…

csdn初始模板【自用】

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

C++ Qt 学习(五):Qt Web 编程

1. Chrome 技术介绍 大多数 web 技术都是基于 chrome&#xff0c;例如 CEF、QCefView 以及 QWebEngineView&#xff0c;这些都是在 native 界面里用来显示 html 网页&#xff0c;并且可以与 web 交互 例如常见的登录窗口、优酷的视频区域、WPS 的稻壳商城等&#xff0c;这些都…