西安电子商务网站开发,电脑网页游戏排行,展厅装饰公司,水平线设计公司官网一、JacksonConfig 全局序列化反序列化配置
1.1yml中配置 #时区 spring.jackson.time-zoneGMT8 #日期格式 spring.jackson.date-formatyyyy-MM-dd HH:mm:ss #默认转json的属性#xff0c;这里设置为非空才转json spring.jackson.default-property-inclusionnon_null #设置属性…一、JacksonConfig 全局序列化反序列化配置
1.1yml中配置 #时区 spring.jackson.time-zoneGMT8 #日期格式 spring.jackson.date-formatyyyy-MM-dd HH:mm:ss #默认转json的属性这里设置为非空才转json spring.jackson.default-property-inclusionnon_null #设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值SNAKE_CASE-返回的json驼峰式转下划线json body下划线传到后端自动转驼峰式 spring.jackson.property-naming-strategySNAKE_CASE #对象为空时是否报错默认true spring.jackson.serialization.fail-on-empty-beanstrue #返回的java.util.date转换成timestamp spring.jackson.serialization.write-dates-as-timestampstrue #json中含pojo不存在属性时是否失败报错,默认true spring.jackson.deserialization.fail-on-unknown-propertiesfalse #是否允许出现单引号,默认false spring.jackson.parser.allow-single-quotestrue 1.2配置文件中配置 光标定位置在builder后面ALT ENTER选择 replace lambda with anonymous class可以显示 lambda为普通方法。此处定义了一下常见类型的序列化方法 Slf4j
Configuration
public class JacksonConfig {Beanpublic Jackson2ObjectMapperBuilderCustomizer customizer() {return new Jackson2ObjectMapperBuilderCustomizer() {Overridepublic void customize(Jackson2ObjectMapperBuilder builder) {// 全局配置序列化返回 JSON 处理JavaTimeModule javaTimeModule new JavaTimeModule();javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));builder.modules(javaTimeModule);builder.timeZone(TimeZone.getDefault());log.info(初始化 jackson 配置);}};}} ruoyi-admin/src/main/resources/application.yml 中配置jackon
jackson:# 日期格式化date-format: yyyy-MM-dd HH:mm:ssserialization:# 格式化输出indent_output: false# 忽略无法转换的对象fail_on_empty_beans: falsedeserialization:# 允许对象忽略json中不存在的属性fail_on_unknown_properties: false 点击Jackson2ObjectMapperBuilderCustomizer 可以查看自动配置类JacksonAutoConfiguration Configuration(proxyBeanMethods false)ConditionalOnClass(Jackson2ObjectMapperBuilder.class)static class JacksonObjectMapperBuilderConfiguration {BeanScope(prototype)ConditionalOnMissingBeanJackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,ListJackson2ObjectMapperBuilderCustomizer customizers) {Jackson2ObjectMapperBuilder builder new Jackson2ObjectMapperBuilder();builder.applicationContext(applicationContext);customize(builder, customizers);return builder;}private void customize(Jackson2ObjectMapperBuilder builder,ListJackson2ObjectMapperBuilderCustomizer customizers) {for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) {customizer.customize(builder);}}}
1.3常见jackon注解 JsonIgnore 忽略序列化用于属性上 JsonInclude(JsonInclude.Include.NON_EMPTY) 不为空时候才进行序列化和反序列化 JsonSerialize(using DictDataJsonSerializer.class) 序列化如下DictDataJsonSerializer 是字典序列化的处理工具 /*** 字典数据json序列化工具** author itino* deprecated 建议使用通用翻译注解*/
Deprecated
Slf4j
public class DictDataJsonSerializer extends JsonSerializerString implements ContextualSerializer {private String dictType;Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {try {DictService dictService SpringUtils.getBean(DictService.class);if (ObjectUtil.isNotNull(dictService)) {String label dictService.getDictLabel(dictType, value);gen.writeString(StringUtils.isNotBlank(label) ? label : value);} else {gen.writeString(value);}} catch (BeansException e) {log.error(字典数据未查到, 采用默认处理 {}, e.getMessage());gen.writeString(value);}}Overridepublic JsonSerializer? createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {DictDataMapper anno property.getAnnotation(DictDataMapper.class);if (Objects.nonNull(anno) StrUtil.isNotBlank(anno.dictType())) {this.dictType anno.dictType();return this;}return prov.findValueSerializer(property.getType(), property);}
}JsonProperty( value pass) 接受和序列化都用 pass 而不是 password JsonIgnore
JsonProperty( value pass)
public String getPassword() {return password;
} JsonFormat(pattern yyyy-MM-dd) 系列化格式 1.4 若依jackson工具包 com.ruoyi.common.utils.JsonUtils 提供序列化和反序列化 一些常用方法 二、MybatisPlus 依赖 dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion${mybatis-plus.version}/version/dependency ruoyi-admin/src/main/resources/application.yml 配置文件 配置了Mapper 接口的扫描配置Mapper对应XML的扫描配置实体类domain扫描配字段驼峰规则以及 p6spy的日志分析配置主键生成规则以及CRUD策略 # MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:# 不支持多包, 如有需要可在注解配置 或 提升扫包等级# 例如 com.**.**.mapper com.ruoyi.system.mappermapperPackage: com.ruoyi.**.mapper# 对应的 XML 文件位置mapperLocations: classpath*:mapper/**/*Mapper.xml# 实体扫描多个package用逗号或者分号分隔typeAliasesPackage: com.ruoyi.**.domain# 启动时是否检查 MyBatis XML 文件的存在默认不检查checkConfigLocation: falseconfiguration:# 自动驼峰命名规则camel case映射mapUnderscoreToCamelCase: true# MyBatis 自动映射策略# NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射autoMappingBehavior: PARTIAL# MyBatis 自动映射时未知列或未知属性处理策# NONE不做处理 WARNING打印相关警告 FAILING抛出异常和详细信息autoMappingUnknownColumnBehavior: NONE# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpllogImpl: org.apache.ibatis.logging.nologging.NoLoggingImplglobal-config:# 是否打印 Logo bannerbanner: truedbConfig:# 主键类型# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUIDidType: ASSIGN_ID# 逻辑已删除值logicDeleteValue: 2# 逻辑未删除值logicNotDeleteValue: 0# 字段验证策略之 insert,在 insert 的时候的字段验证策略# IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQLinsertStrategy: NOT_NULL# 字段验证策略之 update,在 update 的时候的字段验证策略updateStrategy: NOT_NULL# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件where-strategy: NOT_NULL com.ruoyi.framework.config.MybatisPlusConfig 配置文件,主要配置以下自行查看 // 数据权限处理 // 分页插件 // 乐观锁插件 // 指定字段的填充策略 使用网卡信息绑定雪花生成器,防止集群雪花ID重复 1.1 常见注解 TableName(sys_user) 标注数据库表名称 TableId(value user_id) 主键 Version 乐观锁比如查询携带上 version字段才回去更新版本 TableLogic 删除标志0代表存在 2代表删除上面 yml配置的逻辑删除 标注该注解的字段数据库要默认设置 0TableField属性fill 指定字段的填充策略如自动填充创建时间、更新时间等。需要实现 MyBatis-Plus 提供的 MetaObjectHandler 接口 并重写 insertFill 和 updateFill 方法。 若依具体实现类com.ruoyi.framework.handler.CreateAndUpdateMetaObjectHandler exist 标记是否为数据库表字段默认为 true。如果设置为 false则表示该字段不是数据库表的字段不会参与 SQL 语句的生成 示例
TableField(exist false)
private ListSysRole roles; value 数据库字段名用于指定实体类字段对应的数据库字段名。当实体类字段名与数据库字段名不一致时使用。示例TableField(db_column_name)update 用于 SQL 的 SET 语句设置字段更新的策略。通常与 TableLogic 注解一起使用实现逻辑删除。示例TableField(update deleted1)nsertStrategy 和 updateStrategy 字段的插入和更新策略。FieldStrategy 是一个枚举类包含以下值IGNORED忽略、NOT_NULL非 NULL 则更新、NOT_EMPTY非空则更新、ALWAYS总是更新。示例TableField( insertStrategy FieldStrategy.NOT_EMPTY, updateStrategy FieldStrategy.NOT_EMPTY, whereStrategy FieldStrategy.NOT_EMPTY )select 是否进行 select 查询。默认为 true表示该字段会参与查询。如果设置为 false则查询时不会包含该字段。示例TableField(select false)jdbcType 字段的 JDBC 类型。通常用于指定某些特殊类型的字段如枚举类型。 示例 TableField(updateStrategy FieldStrategy.IGNORED, jdbcType JdbcType.VARCHAR) el 支持 EL 表达式用于复杂字段的映射处理。示例TableField(el column _suffix)condition 用于 SQL WHERE 语句的条件通常与 Select 注解一起使用实现动态 SQL。示例TableField(condition name ! null and name #{name})strategy 字段验证策略与 insertStrategy 和 updateStrategy 功能类似但用于全局配置。示例TableField(strategy FieldStrategy.NOT_EMPTY) 1.2 BaseMapperPlus 若依继承了 mybatis-plus的BaseMapperT 接口 自定义了 BaseMapperPlusM, T, V Mapper接口com.ruoyi.common.core.mapper.BaseMapperPlus 提供泛型的转换提供BaseMapper原有接口的封装提供其他新增的查询方法 1.3分布式主键 雪花ID 1-yml中配置雪花
dbConfig:# 主键类型# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUIDidType: ASSIGN_ID 2-com.ruoyi.framework.config.MybatisPlusConfig 类中注入IdentifierGenerator 具体实现自行查看 /*** 使用网卡信息绑定雪花生成器* 防止集群雪花ID重复*/Beanpublic IdentifierGenerator idGenerator() {return new DefaultIdentifierGenerator(NetUtil.getLocalhost());} 1.4 wapper
关于条件构造器 wapper 学习文章可以参考
mybatis-plus中wrapper的用法详细_mybatisplus wrapper-CSDN博客https://blog.csdn.net/qq_39715000/article/details/120090033上文未提及一些常用函数
1-apply() 函数 将要添加到 SQL 语句中的 SQL 片段作为参数传递给它即可
//简单查询
QueryWrapperUser wrapper new QueryWrapper();
wrapper.apply(id 1 or name like %test%);
ListUser userList userMapper.selectList(wrapper);//日期
apply(date_format(dateColumn,%Y-%m-%d) {0}, 2020-10-08)apply(date_format(dateColumn,{0}) {1}, %Y-%m-%d, 2020-10-08)2-func 函数可以添加if 等判断 LambdaQueryWrapperSysOperLog lqw new LambdaQueryWrapperSysOperLog().like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()).eq(operLog.getBusinessType() ! null operLog.getBusinessType() 0,SysOperLog::getBusinessType, operLog.getBusinessType()).func(f - {if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));}})
3- nested 嵌套查询 nested函数中语句会加上作为整体提升优先级 public void complexQuery() { QueryWrapperUser queryWrapper new QueryWrapper(); queryWrapper.eq(status, 1) .nested(i - i.eq(name, John).or().like(email, example%)) .orderByAsc(id); ListUser userList userMapper.selectList(queryWrapper); }
SELECT * FROM user WHERE status 1 AND (name John OR email LIKE example%) ORDER BY id ASC
三、BeanCopyUtils
com.ruoyi.common.utils.BeanCopyUtils 包中 提供基于 cglib 性能优异 Bean to BeanBean to MapMap to BeanMap to MapList copy 四、Redis
1.1 Redisson 功能丰富Redisson提供了Redis各种数据结构的Java实现以及分布式锁、计数器等高级功能满足复杂场景需求。 易于集成友好的API和与多种Java框架的集成支持使得开发者能够轻松地将Redis集成到Java应用中。 高性能与可扩展基于Redis的内存存储和集群支持Redisson实现了高读写速度和水平扩展能力适用于高并发和大规模应用。 依赖 dependencygroupIdorg.redisson/groupIdartifactIdredisson-spring-boot-starter/artifactId/dependencydependencygroupIdorg.redisson/groupIdartifactIdredisson-spring-data-27/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIdlock4j-redisson-spring-boot-starter/artifactId/dependency
1.2 Redisson 配置文件和配置类 配置文件 yml中com.ruoyi.framework.config.properties.RedissonProperties 是其配置类。 下面分别是单机 和集群配置类。 /*** 单机服务配置*/
private SingleServerConfig singleServerConfig;/*** 集群服务配置*/
private ClusterServersConfig clusterServersConfig; redisson:# redis key前缀keyPrefix: ruoyi-vue-plus# 线程池数量threads: 4# Netty线程池数量nettyThreads: 8# 单节点配置singleServerConfig:# 客户端名称clientName: ${ruoyi.name}# 最小空闲连接数connectionMinimumIdleSize: 8# 连接池大小connectionPoolSize: 32# 连接空闲超时单位毫秒idleConnectionTimeout: 10000# 命令等待超时单位毫秒timeout: 3000# 发布和订阅连接池大小subscriptionConnectionPoolSize: 50 com.ruoyi.framework.config.RedisConfig 类是redisson的配置类。 Beanpublic RedissonAutoConfigurationCustomizer redissonCustomizer() {return config - {config.setThreads(redissonProperties.getThreads()).setNettyThreads(redissonProperties.getNettyThreads()).setCodec(new JsonJacksonCodec(objectMapper));RedissonProperties.SingleServerConfig singleServerConfig redissonProperties.getSingleServerConfig();if (ObjectUtil.isNotNull(singleServerConfig)) {// 使用单机模式config.useSingleServer()//设置redis key前缀.setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())).setTimeout(singleServerConfig.getTimeout()).setClientName(singleServerConfig.getClientName()).setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()).setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()).setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()).setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());}// 集群配置方式 参考下方注释RedissonProperties.ClusterServersConfig clusterServersConfig redissonProperties.getClusterServersConfig();if (ObjectUtil.isNotNull(clusterServersConfig)) {config.useClusterServers()//设置redis key前缀.setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())).setTimeout(clusterServersConfig.getTimeout()).setClientName(clusterServersConfig.getClientName()).setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()).setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()).setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()).setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()).setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()).setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()).setReadMode(clusterServersConfig.getReadMode()).setSubscriptionMode(clusterServersConfig.getSubscriptionMode());}log.info(初始化 redis 配置);};}
1.3 redis 和redisson集群配置文件
/*** redis集群配置 yml** --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉)* spring:* redis:* cluster:* nodes:* - 192.168.0.100:6379* - 192.168.0.101:6379* - 192.168.0.102:6379* # 密码* password:* # 连接超时时间* timeout: 10s* # 是否开启ssl* ssl: false** redisson:* # 线程池数量* threads: 16* # Netty线程池数量* nettyThreads: 32* # 集群配置* clusterServersConfig:* # 客户端名称* clientName: ${ruoyi.name}* # master最小空闲连接数* masterConnectionMinimumIdleSize: 32* # master连接池大小* masterConnectionPoolSize: 64* # slave最小空闲连接数* slaveConnectionMinimumIdleSize: 32* # slave连接池大小* slaveConnectionPoolSize: 64* # 连接空闲超时单位毫秒* idleConnectionTimeout: 10000* # 命令等待超时单位毫秒* timeout: 3000* # 发布和订阅连接池大小* subscriptionConnectionPoolSize: 50* # 读取模式* readMode: SLAVE* # 订阅模式* subscriptionMode: MASTER*/
1.4 RedisUtils 工具类 所在包 com.ruoyi.common.utils.redis.RedisUtils 1、 订阅发布测试类以及结果如下 Testvoid subPub(){String key key;//模拟订阅消息 启动后会一直监听消息RedisUtils.subscribe(key, String.class, consumer - {Console.log(key:{}, key);Console.log(consumer:{}, consumer);});//模拟发布RedisUtils.publish(key,发布一则消息1);RedisUtils.publish(key,发布一则消息2);RedisUtils.publish(key,ok, conumer-{Console.log(consumer3:{}, conumer);});} key:key consumer:发布一则消息1 key:key consumer:发布一则消息2 consumer3:ok key:key consumer:ok 2、设置缓存 Testvoid setCacheObject(){//ttl -1 ,永久有效印版不用RedisUtils.setCacheObject(java, helloWord);//ttl 自定义 60秒有效期RedisUtils.setCacheObject(java, helloWord, Duration.ofSeconds(60));//是否保留TTL有效期(例如: set之前ttl剩余60 set之后还是为60),false 表示永久RedisUtils.setCacheObject(java, helloWord, true);//果不存在则设置 并返回 true 如果存在则返回 falseboolean ifAbsent RedisUtils.setObjectIfAbsent(java, helloWord, Duration.ofSeconds(60));}
3、设置监听 redis中配置 key 监听器配置 notify-keyspace-event 如下接口中红线标注要包含的 字母,其他接口自行查看 # Redis服务器配置 # 绑定IP地址
#解除本地限制 注释bind 127.0.0.1
#bind 127.0.0.1 # 服务器端口号
port 6379 #配置密码不要可以删掉
#requirepass #key 监听器配置
notify-keyspace-events Exg# 服务器运行模式Redis以守护进程方式运行,默认为no改为yes意为以守护进程方式启动可后台运行除非kill进程改为yes会使配置文件方式启动redis失败如果后面redis启动失败就将这个注释掉
daemonize no#当Redis以守护进程方式运行时Redis默认会把pid写入/var/run/redis.pid文件可以通过pidfile指定(自定义)
#pidfile /data/dockerData/redis/run/redis6379.pid #默认为noredis持久化可以改为yes
appendonly yes 监听测试类
package com.ruoyi.demo.listener;import cn.hutool.core.lang.Console;
import com.ruoyi.common.utils.redis.RedisUtils;
import org.redisson.api.DeletedObjectListener;
import org.redisson.api.ExpiredObjectListener;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;/*** 简述* 详细描述** author syf* date 2024年03月18日 22:38*/
Component
public class ExpiredListener {PostConstructpublic void expireListener(){Console.log(启动监听器。。。。);//用于监听 Redisson 分布式缓存中对象的过期事件RedisUtils.addObjectListener(java, new ExpiredObjectListener() {Overridepublic void onExpired(String name) {Console.log(ExpiredObjectListener:{}, name);}});//监听删除RedisUtils.addObjectListener(java, new DeletedObjectListener() {Overridepublic void onDeleted(String name) {Console.log(DeletedObjectListener:{}, name);}});}
}结果监听到删除 4-对象操作
常用操作
Testvoid getObject(){RedisUtils.setCacheObject(java, helloWord);//6-校验对象是否存在RedisUtils.isExistsObject(java);//1-设置过期时间RedisUtils.expire(java, Duration.ofSeconds(10));//2-获取对象Object name RedisUtils.getCacheObject(name);Console.log(name:{}, name);//3-获取剩余存活时间long time RedisUtils.getTimeToLive(name);Console.log(time:{}, time);//4-删除RedisUtils.deleteObject(name);//5-删除集合ListString list new ArrayList();list.add(java1);list.add(java2);RedisUtils.setCacheObject(java1, helloWord1);RedisUtils.setCacheObject(java2, helloWord2);RedisUtils.deleteObject(list);}
5-数组操作 数组操作是拼接不会覆盖对象操作则是覆盖注意使用场景 提供集合的操作下: Testvoid saveList(){//这个实际保存是对象 覆盖之前 list1ListString list Arrays.asList(java1, java2);RedisUtils.setCacheObject(list1, list, Duration.ofSeconds(60));//保存是数组 (不会覆盖之前的数据 list2)RedisUtils.setCacheList(list2, list);//取ListString list2 RedisUtils.getCacheList(list2);//set集合 值不重复SetString set new HashSet();set.add(java1);set.add(java2);RedisUtils.setCacheSet(set, set);RedisUtils.getCacheSet(set);//MapMapString, Object map new HashMap();map.put(java1, String);map.put(java2, Integer);//存RedisUtils.setCacheMap(map, map);//取Object value RedisUtils.getCacheMapValue(map, java1);//修改map 里面值RedisUtils.setCacheMapValue(java1, map, null);//取map 里面值(自定义map 用得少)SetString objects new HashSet();objects.add(java1);objects.add(java2);MapString, Object map2 RedisUtils.getMultiCacheMapValue(map, objects);//取MapString, Object cacheMap RedisUtils.getCacheMap(map);//遍历keySetString map1 RedisUtils.getCacheMapKeySet(map);}
6-原子操作 原子操作创建后利用 增加 减少方法去修改 Testvoid steAtom(){//原子操作RedisUtils.setAtomicValue(count ,1);//增加RedisUtils.incrAtomicValue(count);//减少RedisUtils.decrAtomicValue(count);//获取long atomicValue RedisUtils.getAtomicValue(:count);}
7-根据前缀获取 Testvoid getKeys() {//getString prefix ruoyi-vue-plus:sys;CollectionString keys RedisUtils.keys(prefix *);ListString list new ArrayList(keys);for (String s : list) {Console.log(value:{}, s);}//删除String prefix1 list1;RedisUtils.deleteKeys(prefix1 *);}
结果 value:sys_config value:sys_oss_config value:sys_oss:default_config value:sys_dict 8-是否存在 Testvoid getExists() {//是否存在boolean hasKey RedisUtils.hasKey(list2);boolean existsObjectis RedisUtils.isExistsObject(list2);}