首页
碎碎念
技术分享
开发日志
学习日记
追剧
番
电视剧
电影
闲言碎语
精美壁纸
留言板
个人导航
关于我
归档
用户登录
用户名
密码
登录
注册
关键词搜索
搜索
标签搜索
java
追番~~
计网
c#
unity
脆皮大学生
spring AOP
博客更新
selenium
web测试
springboot
ES6
vue3
elementPlus
idea
近期浏览
热门文章
1
动漫分享---《想要成为影之实力者》
1.4k 阅读
2
在unity中使用c#语言实现人物的转身
1.4k 阅读
3
可恶的日本军国主义!我们一定不能遗忘这段历史,遗忘历史就意味着背叛!!!!
1.3k 阅读
4
Java与Selenium自动化测试全面指南
1.3k 阅读
5
Unity冲刺机制:如何实现角色冲刺
1.3k 阅读
6
SpringMVC 入门教程(基于Java配置类)
1.3k 阅读
7
子网划分与CIDR
1.2k 阅读
8
我的第一个blog
1.2k 阅读
9
分享键盘
1.1k 阅读
Charlotte
累计撰写
54
篇文章
累计添加
17
个标签
累计收到
50
条评论
首页
分类
碎碎念
技术分享
开发日志
学习日记
追剧
番
电视剧
电影
页面
闲言碎语
精美壁纸
留言板
个人导航
关于我
归档
用户登录
登录
注册
“开发日志” 共(9)篇
nacos实现配置的动态加载出现localhost报错
使用nacos实现配置的动态加载,启动项目时一直出现报错,一直是localhost再看一眼配置,没错,确实是服务器地址,但为什么一直报的是localhost:8848呢?其实还是配置文件写错了,正确的如下{collapse}{collapse-item label="补充知识点" open}Spring Cloud Nacos 配置中的 server-addr 与 config.server-addr 区别spring.cloud.nacos.config.server-addr作用用于配置 Nacos 配置中心的服务器地址。主要用于从 Nacos 配置中心获取配置信息,并且对应用程序中的配置信息进行集中管理和动态更新。场景说明在微服务架构中,我们通常需要一个集中的配置管理系统,以便管理不同微服务的配置参数。Nacos 的配置中心功能非常适合这一需求。spring.cloud.nacos.config.server-addr 指定的是 Nacos 配置中心的地址,它告诉 Spring 应用程序去哪个 Nacos 服务器拉取配置文件。spring: cloud: nacos: config: server-addr: 60.204.218.162:8848 prefix: ${spring.application.name} group: DEFAULT_GROUP file-extension: yaml在上面的例子中,server-addr 指定了 Nacos 配置中心的地址 60.204.218.162:8848,这意味着应用程序会去这个地址获取相应的配置数据,以实现动态配置的能力。spring.cloud.nacos.server-addr作用用于配置 Nacos 注册中心的服务器地址。主要用于服务的注册和发现,让微服务可以互相识别和通信。场景说明微服务架构中,不同的服务需要彼此通信,服务注册与发现是这个架构中的核心功能之一。Nacos 作为一个注册中心,可以让所有微服务在启动时将自身信息注册到 Nacos,其他服务则可以通过 Nacos 找到它们。spring.cloud.nacos.server-addr 指定的是 Nacos 注册中心的地址,它告诉应用程序去哪个 Nacos 实例注册自己,或者从哪个 Nacos 实例中发现其他服务。spring: cloud: nacos: server-addr: 60.204.218.162:8848在这个例子中,server-addr 的地址是 60.204.218.162:8848,这意味着应用程序会将自己注册到这个 Nacos 注册中心,以便其他微服务可以找到它。两者的区别功能不同:spring.cloud.nacos.config.server-addr 用于配置中心,帮助应用程序获取集中配置的数据。spring.cloud.nacos.server-addr 用于服务注册与发现,帮助微服务进行相互通信。使用场景不同:config.server-addr 主要用于配置文件的管理,包括动态加载和热更新配置。server-addr 则用于将服务信息注册到 Nacos,并发现其他服务。可以相同,也可以不同:如果你的 Nacos 同时用作配置中心和注册中心,那么这两个地址可以相同。但是如果你有多套 Nacos 环境来分别处理配置和服务注册,那么这两个地址就会不同。典型配置示例在一个典型的 Spring Cloud 项目中,如果你使用 Nacos 作为服务注册中心和配置中心,那么配置文件可能会如下所示:spring: application: name: my-microservice cloud: nacos: server-addr: 60.204.218.162:8848 config: server-addr: 60.204.218.162:8848 prefix: ${spring.application.name} group: DEFAULT_GROUP file-extension: yaml在这个配置中,server-addr 和 config.server-addr 的值相同,表示 Nacos 同时作为注册中心和配置中心使用。总结spring.cloud.nacos.config.server-addr 用于配置中心,帮助应用程序获取和管理配置。spring.cloud.nacos.server-addr 用于服务注册与发现,帮助微服务进行相互识别和通信。两者可以指向同一个 Nacos 地址,但它们负责的功能是不同的。{/collapse-item}{/collapse}
5个月前
286
0
1
Jenkins构建Springboot项目显示Lombok依赖不起作用
Jenkins构建Springboot项目显示Lombok依赖不存在,报错如下:检查代码和pom文件后发现都没有问题,那么可能是maven的问题,因为我的maven是从windows传进来的,没有改仓库路径,所以修改一下仓库路径就可以了,路径是maven/conf/setting.xml再次构建就成功了
5个月前
226
1
0
Spring Boot 中定制 ObjectMapper 的全局 JSON 序列化配置
在开发 Web API 时,处理 JSON 数据的序列化和反序列化是非常常见的需求。Spring Boot 默认使用 Jackson 来进行 JSON 的处理,但有时候我们需要对 Jackson 的 ObjectMapper 进行自定义配置,以满足特定的业务需求。1. 全局配置 ObjectMapper在 Spring Boot 中,我们可以通过自定义 HttpMessageConverter 来实现全局的 JSON 序列化配置。具体实现如下:package com.jingdianjichi.subject.application.config; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Configuration public class GlobalConfig extends WebMvcConfigurationSupport { @Override protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(mappingJackson2HttpMessageConverter()); } private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { ObjectMapper objectMapper = new ObjectMapper(); // 1. 允许空对象序列化 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // 2. 忽略空值字段 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return new MappingJackson2HttpMessageConverter(objectMapper); } }在这个类中,我们继承了 WebMvcConfigurationSupport 并覆盖了 configureMessageConverters 方法,通过添加自定义的 MappingJackson2HttpMessageConverter 实现了对全局 JSON 处理的自定义。2. 配置详解接下来,我们详细解读两行关键代码,它们分别实现了忽略空字段和允许空对象序列化的功能。2.1 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);这行代码的作用是控制 Jackson 是否允许序列化空对象。SerializationFeature.FAIL_ON_EMPTY_BEANS: 默认情况下,Jackson 在遇到没有任何字段的空对象时会抛出异常。例如,当你有一个类的所有字段值都为 null 或没有任何字段时,Jackson 会认为这个对象无法序列化,并抛出错误。false: 通过将这个配置项设置为 false,即使对象为空,Jackson 仍然会将其序列化为 {},而不会抛出异常。这对于一些复杂对象结构或需要返回空对象的场景非常有用。示例:如果我们有一个类 User,但所有字段都是空的,默认情况下序列化会失败,而通过这行配置后,可以安全地将其序列化为 {}。2.2 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);这行代码用于设置对象序列化时的字段包含规则,具体是忽略 null 值的字段。JsonInclude.Include.NON_NULL: 该配置告诉 Jackson 在序列化时,忽略所有值为 null 的字段。也就是说,如果对象的某个字段值为 null,那么这个字段不会出现在最终的 JSON 结果中。示例:假设我们有如下 Java 对象:User user = new User(); user.setName(null); user.setAge(25);通过配置 NON_NULL,序列化后的 JSON 将会是:{ "age": 25 }而不会包含 null 值的 name 字段。这样可以减少 API 响应的大小,同时提高数据的简洁性。
5个月前
177
0
1
SpringBoot基于工厂+策略模式的题目处理思路详解
在软件开发中,常常会遇到需要根据不同类型执行不同处理逻辑的场景。如果直接使用大量的 if-else 或 switch-case,代码会变得冗长且难以维护。为了解决这个问题,我们可以采用策略模式和工厂模式,使代码结构更加清晰,且方便扩展。下面,我将结合代码,详细讲解这种设计思路,并说明实现后数据的流向。特别是,对于工厂类的设计,我们将进行详细的拆分和讲解。一、设计思路1. 问题背景有一个试题需求,需要处理多种类型的题目:单选题(RADIO)多选题(MULTIPLE)判断题(JUDGE)简答题(BRIEF)每种题型的处理逻辑不同,如果直接在代码中大量使用条件判断,不利于代码的维护和扩展。2. 设计目标解耦不同题型的处理逻辑:每种题型的处理逻辑独立,互不影响。提高代码的可扩展性:新增题型时,尽量不修改原有代码。简化业务层的代码:业务层不需要关注具体的处理逻辑。3. 采用的设计模式策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,使它们可以互相替换,且算法的变化不会影响到使用算法的客户。工厂模式(Factory Pattern):定义一个创建对象的接口,让子类决定实例化哪个类。4. 设计步骤定义策略接口:抽象出题目处理的通用接口。实现具体策略类:为每种题型创建一个处理器,实现策略接口。创建工厂类:根据题目类型,返回对应的处理器。业务层使用工厂获取处理器:业务层调用处理器的方法,完成题目的处理。二、代码实现1. 定义策略接口 SubjectTypeHandlerpublic interface SubjectTypeHandler { SubjectInfoTypeEnum getHandlerType(); void add(SubjectInfoBO subjectInfoBO); }getHandlerType():返回处理器对应的题目类型枚举。add(SubjectInfoBO subjectInfoBO):处理添加题目的方法。2. 实现具体策略类(1)单选题处理器 RadioTypeHandlerpublic class RadioTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.RADIO; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现单选题的添加逻辑 System.out.println("添加单选题:" + subjectInfoBO); } }(2)多选题处理器 MultipleTypeHandlerpublic class MultipleTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.MULTIPLE; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现多选题的添加逻辑 System.out.println("添加多选题:" + subjectInfoBO); } }(3)判断题处理器 JudgeTypeHandlerpublic class JudgeTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.JUDGE; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现判断题的添加逻辑 System.out.println("添加判断题:" + subjectInfoBO); } }(4)简答题处理器 BriefTypeHandlerpublic class BriefTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.BRIEF; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现简答题的添加逻辑 System.out.println("添加简答题:" + subjectInfoBO); } }3. 创建工厂类 SubjectTypeHandlerFactory下面,我们对工厂类的设计进行详细的拆分和讲解。(1)工厂类的定义@Component public class SubjectTypeHandlerFactory implements InitializingBean { // 注入所有实现了 SubjectTypeHandler 接口的处理器 @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>(); public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); } @Override public void afterPropertiesSet() { // 将处理器按题目类型存入 Map for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } } }一定要注意添加@Component注解,表示将代码交给springboot托管,否则代码不会生效,这样在springboot在启动完成之后,我们的Handler就被装配进了spring容器了。(2)成员变量和注入// 注入所有实现了 SubjectTypeHandler 接口的处理器 @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();subjectTypeHandlerList:通过 @Resource 注解,Spring 会自动注入容器中所有实现了 SubjectTypeHandler 接口的 Bean。handlerMap:用于存储题目类型与对应处理器的映射关系。(3)初始化方法 afterPropertiesSet()@Override public void afterPropertiesSet() { // 将处理器按题目类型存入 Map for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } }作用:在 Bean 初始化完成后,Spring 会调用 afterPropertiesSet() 方法。逻辑:遍历 subjectTypeHandlerList,获取每个处理器。调用处理器的 getHandlerType() 方法,获取对应的题目类型。将题目类型和处理器存入 handlerMap,建立映射关系。目的:将所有的处理器按照题目类型注册到工厂中,方便后续根据题目类型获取对应的处理器。(4)获取处理器方法 getHandler(int subjectType)public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }参数:subjectType,题目类型的整数表示。逻辑:调用 SubjectInfoTypeEnum.getByCode(subjectType),将整数类型转换为对应的枚举类型 SubjectInfoTypeEnum。从 handlerMap 中获取对应的处理器。返回值:SubjectTypeHandler,对应题目类型的处理器。(5)类注解 @Component@Component public class SubjectTypeHandlerFactory implements InitializingBean { ... }@Component:将工厂类声明为一个 Spring Bean,交由 Spring 容器管理。implements InitializingBean:实现 InitializingBean 接口,目的是在 Bean 初始化后执行 afterPropertiesSet() 方法。4. 业务层调用@Service public class SubjectService { @Autowired private SubjectTypeHandlerFactory handlerFactory; public void addSubject(SubjectInfoBO subjectInfoBO) { // 获取对应的处理器 SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType()); if (handler != null) { // 调用处理器的添加方法 handler.add(subjectInfoBO); } else { throw new IllegalArgumentException("未知的题目类型"); } } }注入工厂类:@Autowired 将 SubjectTypeHandlerFactory 注入到业务层。添加题目方法:根据 subjectInfoBO.getType() 获取题目类型。调用工厂的 getHandler() 方法获取对应的处理器。调用处理器的 add() 方法,处理题目添加逻辑。三、实现后的数据流向1. 数据流整体概述当需要添加一个新题目时,数据流向如下:接收请求:SubjectService.addSubject() 接收 SubjectInfoBO 对象,包含题目的详细信息。获取处理器:SubjectTypeHandlerFactory.getHandler() 根据题目类型返回对应的处理器。处理题目:调用处理器的 add() 方法,执行具体的处理逻辑。完成添加:处理器完成题目的添加操作。2. 数据流详细步骤(1)接收题目信息SubjectInfoBO subjectInfoBO = new SubjectInfoBO(); subjectInfoBO.setType(1); // 假设 1 代表单选题 subjectInfoBO.setContent("题目内容"); // ... 设置其他属性 subjectService.addSubject(subjectInfoBO);创建题目对象:实例化 SubjectInfoBO,设置题目类型和内容等属性。调用业务方法:调用 SubjectService.addSubject() 方法,传入题目对象。(2)业务层获取处理器public void addSubject(SubjectInfoBO subjectInfoBO) { // 获取处理器 SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType()); // ... }获取题目类型:从 subjectInfoBO 中获取题目类型。调用工厂方法:使用工厂的 getHandler() 方法获取对应的处理器。(3)工厂返回处理器public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }类型转换:将整数类型的题目类型转换为枚举类型。获取处理器:从 handlerMap 中根据枚举类型获取处理器。(4)处理器处理题目if (handler != null) { handler.add(subjectInfoBO); } else { throw new IllegalArgumentException("未知的题目类型"); }调用处理方法:如果获取到了处理器,调用其 add() 方法。异常处理:如果没有对应的处理器,抛出异常。处理器的 add() 方法,例如单选题处理器:public class RadioTypeHandler implements SubjectTypeHandler { @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现单选题的添加逻辑 System.out.println("添加单选题:" + subjectInfoBO); // 例如,将题目信息保存到数据库 } }具体处理逻辑:处理器执行特定题型的添加逻辑,例如数据校验、数据库操作等。3. 数据流示意图用户请求 --> SubjectService.addSubject() --> SubjectTypeHandlerFactory.getHandler() --> 返回对应处理器 | v 调用处理器的 add() 方法 --> 处理器执行添加逻辑 --> 完成题目添加四、工厂类设计的详细讲解1. 工厂类的职责SubjectTypeHandlerFactory 的主要职责是根据题目类型返回对应的处理器。这一过程包含:初始化处理器映射关系:在工厂类初始化时,将所有的处理器注册到一个映射中。提供获取处理器的方法:根据题目类型,返回相应的处理器实例。2. 工厂类的实现细节(1)注入所有处理器@Resource private List<SubjectTypeHandler> subjectTypeHandlerList;@Resource 注解:由 Spring 自动注入容器中所有实现了 SubjectTypeHandler 接口的 Bean。目的:获取所有的处理器实例,方便后续的映射注册。(2)定义处理器映射private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();handlerMap:用于存储题目类型和处理器实例的对应关系。类型安全:使用 SubjectInfoTypeEnum 作为键,确保类型的一致性。(3)初始化处理器映射@Override public void afterPropertiesSet() { for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } }afterPropertiesSet() 方法:由 InitializingBean 接口提供,在 Bean 的属性设置完成后由 Spring 自动调用。处理逻辑:遍历 subjectTypeHandlerList 中的所有处理器。调用每个处理器的 getHandlerType() 方法,获取其支持的题目类型。将题目类型和处理器实例存入 handlerMap。(4)获取处理器的方法public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }参数说明:subjectType,题目类型的整数表示。步骤解析:类型转换:调用 SubjectInfoTypeEnum.getByCode(subjectType) 方法,将整数类型转换为枚举类型。SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);获取处理器:从 handlerMap 中根据枚举类型获取对应的处理器实例。return handlerMap.get(typeEnum);返回值:对应题目类型的处理器,如果不存在则返回 null。(5)异常处理(可选)在实际应用中,可能需要对获取不到处理器的情况进行处理,可以在 getHandler() 方法中添加异常处理:public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); SubjectTypeHandler handler = handlerMap.get(typeEnum); if (handler == null) { throw new IllegalArgumentException("未知的题目类型:" + subjectType); } return handler; }目的:避免业务层需要处理 null 值,将异常抛出,提高代码的健壮性。(6)工厂类的优势集中管理:所有处理器的实例化和获取都由工厂类负责,方便管理。解耦业务层和处理器:业务层无需关心处理器的实现细节,只需通过工厂获取即可。易于扩展:新增题型处理器时,只需实现 SubjectTypeHandler 接口,并将其注册到 Spring 容器中,无需修改工厂类的代码。3. 工厂类的完整代码@Component public class SubjectTypeHandlerFactory implements InitializingBean { @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>(); public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); SubjectTypeHandler handler = handlerMap.get(typeEnum); if (handler == null) { throw new IllegalArgumentException("未知的题目类型:" + subjectType); } return handler; } @Override public void afterPropertiesSet() { for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } } }
5个月前
179
0
0
Java 枚举中的参数化常量与遍历查找逻辑
在 Java 开发中,枚举(enum)不仅仅是用来定义一组常量。通过参数化枚举常量和实现特定的逻辑,枚举可以变得功能强大且灵活。本文将针对以下两段代码进行详细解析:枚举常量的参数化定义FAIL(500, "失败")枚举值的遍历与查找逻辑for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) { if (resultCodeEnum.code == codeVal) { return resultCodeEnum; } }枚举常量的参数化定义基本概念在 Java 中,枚举(enum)用于定义一组固定的常量。通常,我们会看到类似以下的简单枚举:public enum Status { ACTIVE, INACTIVE, PENDING }然而,Java 枚举的强大之处在于它允许为每个枚举常量定义参数,从而为每个常量关联特定的数据。这种方式使得枚举不仅仅是简单的常量集合,而是可以携带更多信息的对象。参数化枚举常量的定义以您的代码为例:FAIL(500, "失败")这里,FAIL 是枚举 ResultCodeEnum 的一个常量,它被参数化为两个值:状态码(code):500描述信息(desc):"失败"这种参数化的定义方式使得每个枚举常量不仅有名称(如 FAIL),还携带了额外的属性信息。构造方法与字段为了支持参数化的枚举常量,需要在枚举中定义相应的字段和构造方法。例如:@Getter public enum ResultCodeEnum { SUCCESS(200, "成功"), FAIL(500, "失败"); // 状态码 private final int code; // 描述 private final String desc; ResultCodeEnum(int code, String desc) { this.code = code; this.desc = desc; } }解析:字段定义:private final int code; 和 private final String desc; 分别用于存储状态码和描述信息。使用 final 修饰确保这些字段的不可变性。构造方法:ResultCodeEnum(int code, String desc) 是一个私有构造方法,用于初始化每个枚举常量的 code 和 desc 字段。Lombok 的 @Getter 注解:自动为所有字段生成 getter 方法,简化代码编写。优点清晰的关联关系:每个枚举常量与其对应的状态码和描述信息紧密关联,提升代码的可读性和维护性。类型安全:避免了使用魔法数字或字符串,减少了出错的可能性。封装性:通过 private final 字段和 getter 方法,确保了数据的封装与不可变性。枚举值的遍历与查找逻辑背景在实际应用中,常常需要根据某个值(如状态码)来查找对应的枚举常量。例如,当接收到一个状态码 500 时,需要找到对应的 ResultCodeEnum.FAIL 枚举实例。遍历查找的实现以下是您提供的遍历查找逻辑:public static ResultCodeEnum getByCode(int codeVal) { for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) { if (resultCodeEnum.code == codeVal) { return resultCodeEnum; } } return null; }解析:ResultCodeEnum.values() 方法:这是一个由 Java 自动为枚举类型生成的静态方法,返回包含所有枚举常量的数组。在本例中,ResultCodeEnum.values() 返回 [SUCCESS, FAIL]。增强型 for 循环:for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) 遍历所有枚举常量。每次循环中,resultCodeEnum 分别代表 SUCCESS 和 FAIL。条件判断:if (resultCodeEnum.code == codeVal) 检查当前枚举常量的 code 是否与传入的 codeVal 相等。如果相等,返回该枚举常量。返回 null:如果遍历完所有枚举常量后仍未找到匹配的 codeVal,则返回 null。优点与缺点优点:简单直观:逻辑清晰,易于理解和实现。通用性:适用于枚举常量数量较少的情况。缺点:性能问题:随着枚举常量数量的增加,遍历查找的效率会下降(时间复杂度为 O(n))。空指针风险:方法返回 null 可能导致调用者在未进行 null 检查时发生 NullPointerException。优化建议为了提升查找效率和代码的健壮性,可以考虑以下优化措施:使用静态缓存(Map):通过一个静态的 Map 来缓存 code 与枚举实例的映射关系,将查找时间复杂度降低到 O(1)。private static final Map<Integer, ResultCodeEnum> CODE_MAP = new HashMap<>(); static { for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) { CODE_MAP.put(resultCodeEnum.getCode(), resultCodeEnum); } } public static ResultCodeEnum getByCode(int codeVal) { return CODE_MAP.get(codeVal); }使用 Optional 避免返回 null:返回 Optional<ResultCodeEnum>,强制调用者处理可能的空值,减少 NullPointerException 风险。public static Optional<ResultCodeEnum> getByCode(int codeVal) { return Optional.ofNullable(CODE_MAP.get(codeVal)); }抛出自定义异常:在未找到匹配枚举时,抛出自定义异常,明确告知调用者错误情况。public static ResultCodeEnum getByCode(int codeVal) { ResultCodeEnum result = CODE_MAP.get(codeVal); if (result == null) { throw new IllegalArgumentException("无效的状态码: " + codeVal); } return result; }综合应用示例结合上述两部分的解析,以下是一个完整的 ResultCodeEnum 实现示例:package com.jingdianjichi.subject.common.enums; import lombok.Getter; import java.util.HashMap; import java.util.Map; import java.util.Optional; @Getter public enum ResultCodeEnum { SUCCESS(200, "成功"), FAIL(500, "失败"); // 状态码 private final int code; // 描述 private final String desc; // 静态缓存 Map,用于快速查找 private static final Map<Integer, ResultCodeEnum> CODE_MAP = new HashMap<>(); // 静态代码块,初始化缓存 Map static { for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) { CODE_MAP.put(resultCodeEnum.getCode(), resultCodeEnum); } } // 构造方法 ResultCodeEnum(int code, String desc) { this.code = code; this.desc = desc; } public static Optional<ResultCodeEnum> getByCode(int codeVal) { return Optional.ofNullable(CODE_MAP.get(codeVal)); } }使用示例以下是如何在实际项目中使用 ResultCodeEnum 的示例:public class ApiResponse { private int code; private String message; private Object data; // 构造方法 public ApiResponse(int code, String message, Object data) { this.code = code; this.message = message; this.data = data; } // 静态方法:成功响应 public static ApiResponse success(Object data) { return new ApiResponse(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getDesc(), data); } // 静态方法:失败响应 public static ApiResponse fail(ResultCodeEnum resultCodeEnum) { return new ApiResponse(resultCodeEnum.getCode(), resultCodeEnum.getDesc(), null); } // Getter 和 Setter 略 }调用示例:@RestController @RequestMapping("/api") public class UserController { @GetMapping("/user/{id}") public ResponseEntity<ApiResponse> getUser(@PathVariable Long id) { Optional<User> userOpt = userService.findById(id); if (userOpt.isPresent()) { return ResponseEntity.ok(ApiResponse.success(userOpt.get())); } else { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(ApiResponse.fail(ResultCodeEnum.FAIL)); } } }
5个月前
164
0
1
使用 Guava 的 Preconditions 和 Apache Commons Lang3 的 StringUtils 进行参数校验
在软件开发中,参数校验是确保应用程序健壮性和可靠性的关键环节。合理的参数校验不仅可以防止潜在的错误,还能提供清晰的错误信息,便于调试和维护。本文将介绍如何结合使用 Google 的 Guava 库中的 Preconditions 类与 Apache Commons Lang3 的 StringUtils 类进行高效的参数校验。Guava 的 Preconditions 概述Guava 是 Google 开发的一个开源 Java 基础库,提供了许多实用的工具类和方法。其中,Preconditions 类专门用于参数校验,确保方法的输入参数满足预期条件。常用的方法包括:checkNotNull(T reference, String errorMessage): 检查引用是否为 null。checkArgument(boolean expression, String errorMessage): 检查布尔表达式是否为 true。checkState(boolean expression, String errorMessage): 检查对象状态是否符合预期。优点:简洁性:减少了繁琐的 if 语句。一致性:提供统一的参数校验方式。明确的错误信息:通过自定义错误信息,便于调试。Apache Commons Lang3 的 StringUtils 概述Apache Commons Lang 是 Apache 提供的一个常用的 Java 工具库,StringUtils 类是其中的一个核心组件,提供了丰富的字符串处理方法。常用的方法包括:isEmpty(String str): 检查字符串是否为空 (null 或 "")。isBlank(String str): 检查字符串是否为空 (null、"" 或仅包含空白字符)。isNotEmpty(String str): 检查字符串是否不为空。isNotBlank(String str): 检查字符串是否不为空且不全为空白字符。优点:丰富的功能:提供了多种字符串处理方法,覆盖大多数常见需求。提高代码可读性:方法命名清晰,意图明确。减少重复代码:避免了开发者编写重复的字符串处理逻辑。结合使用 Preconditions 和 StringUtils 进行参数校验将 Guava 的 Preconditions 与 Apache Commons Lang3 的 StringUtils 结合使用,可以实现高效且简洁的参数校验。例如:import com.google.common.base.Preconditions; import org.apache.commons.lang3.StringUtils; public class SubjectCategoryService { public void createCategory(SubjectCategoryDTO subjectCategoryDTO) { Preconditions.checkNotNull(subjectCategoryDTO.getCategoryType(), "分类类型不能为空"); Preconditions.checkArgument(!StringUtils.isBlank(subjectCategoryDTO.getCategoryName()), "分类的名称不能为空"); Preconditions.checkNotNull(subjectCategoryDTO.getParentId(), "分类的父级id不能为空"); // 业务逻辑处理 } }在上述代码中,Preconditions 用于检查对象是否为 null 或布尔表达式是否为 true,而 StringUtils.isBlank 用于判断字符串是否为空或仅包含空白字符。这种组合使用方式使得参数校验简洁明了,代码可读性和维护性显著提高。代码示例解析让我们详细解析上述代码示例中的各个部分。1. 检查分类类型是否为空Preconditions.checkNotNull(subjectCategoryDTO.getCategoryType(), "分类类型不能为空");功能:确保 categoryType 不为 null。方法:checkNotNull,如果 categoryType 为 null,则抛出 NullPointerException,并附带错误信息 "分类类型不能为空"。优点:避免了后续业务逻辑中因 null 导致的潜在 NullPointerException。2. 检查分类名称是否为空或仅包含空白字符Preconditions.checkArgument(!StringUtils.isBlank(subjectCategoryDTO.getCategoryName()), "分类的名称不能为空");功能:确保 categoryName 不为空,且不全为空白字符。方法:StringUtils.isBlank(subjectCategoryDTO.getCategoryName()):判断 categoryName 是否为 null、"" 或仅包含空白字符。checkArgument:如果表达式 !StringUtils.isBlank(...) 为 false,则抛出 IllegalArgumentException,并附带错误信息 "分类的名称不能为空"。优点:确保分类名称有效,防止用户输入无效数据。3. 检查分类的父级 ID 是否为空Preconditions.checkNotNull(subjectCategoryDTO.getParentId(), "分类的父级id不能为空");功能:确保 parentId 不为 null。方法:同上,使用 checkNotNull。优点:确保分类有一个有效的父级 ID,维护分类层级关系。最佳实践在实际开发中,结合使用 Preconditions 和 StringUtils 进行参数校验时,以下最佳实践值得遵循:1. 明确错误信息提供清晰、简洁且具描述性的错误信息,便于快速定位问题。例如:Preconditions.checkNotNull(user.getEmail(), "用户邮箱不能为空");2. 避免过度校验仅在必要的地方进行参数校验,避免冗余的检查。例如,如果某个参数在调用前已经被校验,可以考虑不再重复校验。3. 使用适当的校验方法根据具体需求选择合适的 Preconditions 方法:使用 checkNotNull 检查引用是否为 null。使用 checkArgument 检查方法参数是否符合预期条件。使用 checkState 检查对象的内部状态。参考资料Guava Documentation - PreconditionsApache Commons Lang - StringUtilsEffective Java - Joshua Bloch(推荐阅读,深入理解参数校验和其他最佳实践)
5个月前
173
0
2
CentOS 7.9云服务器配置问答社区服务中间件
Docker安装# 查看系统版本 uname -r # 安装docker前的强制依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 # 配置镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 该命令就是用来自动化地安装 Docker 并配置好必要的运行环境,以便在 CentOS 系统上顺利运行 Docker 容器 yum install docker-ce docker-ce-cli containerd.io -y # 启动docker systemctl start docker # 用于设置 Docker 服务在系统启动时自动启动 systemctl enable docker # 查看docker版本 docker version # 查看本地存储的docker镜像 docker imagesDocker安装mysql# 拉取mysql5.7镜像 docker pull mysql:5.7 # 查看docker镜像列表 docker images # 创建mysql的data文件夹 mkdir -p /home/service/mysql/data # 创建mysql的配置文件夹 mkdir -p /home/service/mysql/conf # 进入配置文件夹 cd /home/service/mysql/conf # 创建配置文件,使用vim命令编辑 touch my.cnf -------------配置文件------------ [mysqld] user=mysql character-set-server=utf8 default_authentication_plugin=mysql_native_password default-time_zone = '+8:00' [client] default-character-set=utf8 [mysql] default-character-set=utf8 ------------------------------- # 挂载目录。实现容器数据的持久化与共享,mysql密码123456 docker run -p 3306:3306 --name mysql -v /home/service/mysql/logs:/logs -v /home/service/mysql/data:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 ## 如果发现已存在同名容器,docker报错: Error response from daemon: Conflict. The container name "/mysql" is already in use by container"....."。可使用以下命令删除现有的同名容器 docker rm -f /mysql # 启动mysql服务 docker exec -it mysql bash # 登录mysql mysql -uroot -p # 在mysql下相关命令 ## 1.创建admin用户,密码123456,这里的 'admin' 是用户名,'%' 表示允许从任何主机登录。 CREATE USER 'admin'@'%' IDENTIFIED BY '123456'; ## 2.分配权限,GRANT: 授予特定权限给用户。ALL: 表示授予所有权限。ON *.*: 表示对所有数据库和所有表授予权限。TO 'admin'@'%': 表示将权限授予给前面创建的 'admin' 用户,并允许从任何主机登录。 GRANT ALL ON *.* TO 'admin'@'%'; ## 3.重现加载授权表,确保权限为最新 flush privileges; # 查看启动状态 docker ps navicat直接连接即可,云服务器需要开启防火墙,需要检查服务器安全组是否开启对应端口,具体教程可参考https://cloud.tencent.com/developer/article/1988335
11个月前
339
1
1
Vue 3 和 Element Plus 实现商品管理系统 - 表单校验部分解析
介绍在本博客中,我们将深入探讨如何使用 Vue 3 和 Element Plus 构建一个简单的商品管理系统,并重点关注表单校验的部分。这个系统允许用户添加、编辑和删除商品,以及对商品进行搜索。技术栈在这个项目中,我们使用了以下技术:Vue 3:一个流行的 JavaScript 框架,用于构建用户界面。Element Plus:一套基于 Vue 3 的组件库,用于创建漂亮的用户界面。Axios:一个用于处理 HTTP 请求的 JavaScript 库。表单校验在这个项目中,我们使用 Element Plus 的表单组件来实现商品信息的输入和校验。以下是与表单校验相关的关键知识点和注意事项:1. 引入 Element Plus在项目中首先要确保已正确引入 Element Plus,以便使用它的表单组件和验证规则。import { ref, reactive } from "vue"; import { ElForm, ElFormItem, ElInput, ElSelect, ElOption } from "element-plus";2. 创建表单数据和校验规则我们使用 ref 来创建表单数据,并使用 ref 来创建校验规则。校验规则通常包括字段的必填性、数据类型和自定义校验方法。const insertForm = ref({ sellerID: "", name: "", description: "", price: "", category: "", condition: "", quantity: "", // status: "", }); const insertFormRules = ref({ name: [ { required: true, message: "商品名称不能为空", trigger: "blur", }, ], description: [ { required: true, message: "商品描述不能为空", trigger: "blur", }, ], price: [ { required: true, validator: validatePrice, trigger: "blur", }, ], category: [ { required: true, message: "请选择商品类别", trigger: "change", }, ], condition: [ { required: true, message: "请选择商品成色", trigger: "change", }, ], quantity: [ { required: true, message: "商品数量不能为空", trigger: "blur", }, { type: "number", message: "商品数量必须为数字值", }, ], });3. 表单校验在提交表单之前,我们使用 el-form 的 validate 方法来进行表单校验。校验成功后才允许提交数据。<el-dialog v-model="dialogInsertFormVisible" title="上架商品"> <el-form ref="insertFormRulesRef" :model="insertForm" :rules="insertFormRules" > <el-form-item label="商品名称" label-width="80px" prop="name"> <el-input v-model="insertForm.name" autocomplete="off" /> </el-form-item> <el-form-item label="描述" label-width="80px" prop="description"> <el-input v-model="insertForm.description" autocomplete="off" /> </el-form-item> <el-form-item label="价格" label-width="80px" prop="price"> <el-input v-model="insertForm.price" autocomplete="off" /> </el-form-item> <el-form-item label="类别" label-width="80px" prop="category"> <el-select v-model="insertForm.category" placeholder="请选择类别"> <el-option label="服饰鞋帽" value="服饰鞋帽" /> <el-option label="家居用品" value="家居用品" /> <el-option label="电子数码" value="电子数码" /> <el-option label="美妆护肤" value="美妆护肤" /> <el-option label="食品生鲜" value="食品生鲜" /> <el-option label="图书音像" value="图书音像" /> <el-option label="儿童玩具" value="儿童玩具" /> <el-option label="运动户外" value="运动户外" /> <el-option label="汽车用品" value="汽车用品" /> <el-option label="医疗保健" value="医疗保健" /> <el-option label="工艺礼品" value="工艺礼品" /> <el-option label="虚拟物品" value="虚拟物品" /> </el-select> </el-form-item> <el-form-item label="成色" label-width="80px" prop="condition"> <el-select v-model="insertForm.condition" placeholder="请选择成色"> <el-option label="全新" value="全新" /> <el-option label="99新" value="99新" /> <el-option label="95新" value="95新" /> <el-option label="9成新" value="9成新" /> <el-option label="8成新" value="8成新" /> <el-option label="6成新" value="6成新" /> </el-select> </el-form-item> <el-form-item label="数量" label-width="80px" prop="quantity"> <el-input v-model.number="insertForm.quantity" autocomplete="off" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogInsertFormVisible = false">取消</el-button> <el-button type="primary" @click="submitItemInform(insertFormRulesRef)" > 提交 </el-button> <el-button type="primary" @click="test"> 提交 </el-button> </span> </template> </el-dialog>ref[0].validate(async (valid) => { if (valid) { // 表单校验通过,可以提交数据 try { const res = await axios.post( "http://localhost:8080/userInsertItem", insertForm.value ); // 处理提交结果... } catch (err) { // 处理请求错误... } } else { // 表单校验不通过,不执行提交操作 console.log("表单校验不通过!"); } });4. 自定义校验规则在校验规则中,我们可以使用自定义校验方法来实现特定的验证逻辑。例如,我们可以编写一个验证价格是否为数字的自定义校验方法:const validatePrice = (rule, value, callback) => { if (!value) return callback(new Error("请输入金额")); if (!Number(value)) return callback(new Error("请输入数字值")); let reg = /((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/; if (!reg.test(value)) return callback(new Error("请输入正确价格")); callback(); };然后,在校验规则中应用该自定义校验方法:price: [ { required: true, validator: validatePrice, trigger: "blur", }, ],5. 提示用户在校验不通过时,使用 Element Plus 的消息提示功能来通知用户错误信息:if (!valid) { // 表单校验不通过,显示错误消息 this.$message.error("表单校验不通过,请检查输入!"); }6. 表单重置在提交成功后,你可以选择重置表单,以便用户继续添加新的商品信息:ref[0].resetFields(); // 重置表单总结在这篇博客中,我们深入探讨了如何使用 Vue 3 和 Element Plus 构建商品管理系统的表单校验部分。我们学习了如何创建表单数据、定义校验规则、进行表单校验以及处理校验结果。此外,我们还介绍了如何使用自定义校验方法和提示用户错误信息的方法。这个项目只是一个简单的示例,你可以根据实际需求扩展和定制更多功能,以满足你的项目要求。希望这篇博客对你有所帮助,如果有任何问题或建议,请随时留言。
1年前
638
1
1
博客加入评论ip属地显示功能
更新了评论去用户ip归属地显示功能,详情和教程如下。效果图实现这样的功能有两种方式,一种是自己编写方法引用,另一种是插件管理,我使用的是第二种。{lamp/}第一种本获取不支持IPV6地址只支持IPV4 调用纯真本地数据库 需要定时更新要不然 获取可能不准确{cloud title="获取代码资源" type="lz" url="https://suxiaoq.lanzoul.com/irWB6056johc" password=""/}首先找到主题的function.php文件这里我以Joe主题为例 各个主题的不相同 请自行判断Joe主题的function.php文件在/Joe/core/function.php将下载的压缩包解压到core目录下 然后编辑function.php文件然后在第2行引用这个文件代码require 'ipdata.class.php';然后新建一个方法 function convertip($ip){ echo convertips($ip); }写完保存这个文件 再找到评论模板的文件 一般都为comment.phpJoe主题的comment.php文件在/Joe/public/comment.php,然后插入以下代码即可显示,<?php echo convertip($comments->ip); ?>joe主题一般在class="agent"的div中插入<div class="agent"><?php XQLocation_Plugin::render($comments->ip); ?> · <?php _getAgentOS($comments->agent); ?> · <?php _getAgentBrowser($comments->agent); ?></div>此方法来自于 晓晴博客{dotted startColor="#ff6bc1" endColor="#18d6fb"/}第二种插件支持IPV6和IPV4归属地获取并且 为了避免卡顿或者获取失败 数据库都是本地 不调用任何第三方API接口{cloud title="获取代码资源" type="lz" url="https://suxiaoq.lanzoul.com/ipUtV10whrwf" password=""/}解压后修改文件夹名为 XQLocation,将插件上传至网站目录的 /usr/plugins 下在 Typecho 后台「插件管理」处启用插件Joe主题的comment.php文件在/Joe/public/comment.php,class="agent"的div中插入<div class="agent"><?php XQLocation_Plugin::render($comments->ip); ?> · <?php _getAgentOS($comments->agent); ?> · <?php _getAgentBrowser($comments->agent); ?></div>插入代码<?php XQLocation_Plugin::render($comments->ip); ?>(此项也适用于后台)此方法来自于 晓晴博客
1年前
654
0
1
Charlotte
54
文章数
17
标签数
50
评论量
子网划分与CIDR
在unity中使用c#语言实现人物的转身
SpringMVC 入门教程(基于Java配置类)
人生倒计时
热门文章
1
动漫分享---《想要成为影之实力者》
1418 阅读 - 10/11
2
在unity中使用c#语言实现人物的转身
1396 阅读 - 10/13
3
可恶的日本军国主义!我们一定不能遗忘这段历史,遗忘历史就意味着背叛!!!!
1331 阅读 - 10/17
标签云
java
追番~~
计网
c#
unity
脆皮大学生
spring AOP
博客更新
selenium
web测试
springboot
ES6
vue3
elementPlus
idea
舔狗日记