java注解 好像和C# 特性 差不多
@Data @Builder @NoArgsConstructor @AllArgsConstructor
在Java中,@Data
、@Builder
、@NoArgsConstructor
和@AllArgsConstructor
是Lombok库提供的注解,它们用于简化Java对象的创建和处理。Lombok是一个流行的Java库,旨在减少样板代码的编写,让开发者能够更专注于业务逻辑。下面是这些注解的简要说明:
-
@Data
:- 这是一个聚合注解,它自动为类生成getter和setter方法、
toString()
、equals()
和hashCode()
方法。它还包含了@ToString
、@EqualsAndHashCode
、@Getter
、@Setter
和@RequiredArgsConstructor
的功能。
- 这是一个聚合注解,它自动为类生成getter和setter方法、
-
@Builder
:- 这个注解用于在类上创建一个builder模式的构建器,允许通过链式调用来设置对象的属性。使用
@Builder
注解可以很容易地创建对象,特别是当对象有很多属性时。
- 这个注解用于在类上创建一个builder模式的构建器,允许通过链式调用来设置对象的属性。使用
-
@NoArgsConstructor
:- 这个注解让Lombok为类生成一个无参的构造函数。这对于创建没有初始值的对象实例很有用。
-
@AllArgsConstructor
:- 这个注解让Lombok为类生成一个包含所有属性的构造函数。这对于创建完全初始化的对象实例很有用。
这些注解通常用于模型类或DTO(数据传输对象),以减少手动编写常见方法的时间。例如,一个使用这些注解的简单类可能看起来像这样:
java">import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {private String name;private int age;private String email;
}
在这个例子中,Person
类将自动拥有以下功能:
- Getter和Setter方法
toString()
、equals()
和hashCode()
方法- 一个无参构造函数
- 一个包含所有属性的构造函数
- 一个builder模式的构建器
使用这些注解,你可以这样创建Person
对象:
java">Person person = new Person();
Person personWithAllArgsConstructor = new Person("John Doe", 30, "john.doe@example.com");
Person personWithBuilder = Person.builder().name("Jane Doe").age(25).email("jane.doe@example.com").build();
请注意,要使用Lombok注解,你需要在项目中添加Lombok依赖,并在IDE中安装相应的插件,以便正确地识别和处理这些注解。
java String 变LocalDateTime
//2024-09-29 12:30 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime.parse(createReqVO.getSolDeliveryDate(), formatter); order.setSolDeliveryDate(dateTime);
JAVA 集合
List<Map<String, Object>> listMch = new ArrayList<>();
Map<String, Object> mch1 = new HashMap<>();
java">List<Map<String, Object>> listMch = new ArrayList<>();Map<String, Object> mch1 = new HashMap<>();mch1.put("mchName", "海口");mch1.put("userId", 0);mch1.put("mchId", 4);mch1.put("warehouseId", 0);listMch.add(mch1);
您提供的代码是Java语言的一段示例,它创建了一个列表 listMch
,该列表存储了一个映射(Map
)的集合,每个映射代表一个商户(mch
)的信息。然后,代码创建了一个 HashMap
实例 mch1
,并向其中添加了几个键值对来存储特定商户的信息,最后将这个映射添加到了列表 listMch
中。
这里是代码的详细解释:
-
List<Map<String, Object>> listMch = new ArrayList<>();
:- 这行代码创建了一个
ArrayList
,它的泛型参数是Map<String, Object>
。这意味着listMch
可以存储Map
对象的列表,其中每个Map
的键是String
类型,值是Object
类型。
- 这行代码创建了一个
-
Map<String, Object> mch1 = new HashMap<>();
:- 这行代码创建了一个
HashMap
实例mch1
,它也是键值对的集合,键是String
类型,值是Object
类型。
- 这行代码创建了一个
-
mch1.put("mchName", "海口");
:- 这行代码向
mch1
映射中添加了一个键值对,键是"mchName"
,值是字符串"海口"
。
- 这行代码向
-
mch1.put("userId", 0);
:- 向
mch1
映射中添加了另一个键值对,键是"userId"
,值是整数0
。
- 向
-
mch1.put("mchId", 4);
:- 再次向
mch1
映射中添加键值对,键是"mchId"
,值是整数4
。
- 再次向
-
mch1.put("warehouseId", 0);
:- 向
mch1
映射中添加最后一个键值对,键是"warehouseId"
,值是整数0
。
- 向
-
listMch.add(mch1);
:- 最后,这行代码将填充好的
mch1
映射添加到listMch
列表中。
- 最后,这行代码将填充好的
这段代码通常用于初始化数据,可能用于测试、数据模型的演示或者在应用程序中创建一个包含商户信息的列表。每个映射可以看作是数据库中的一行记录或者是一个JSON对象。在实际的应用程序中,这些数据可能会被用来填充用户界面、进行业务逻辑处理或者通过网络发送到其他服务。
JAVA 集合 再包一层集合
Map<String, List<Map<String, Object>>> result = new HashMap<>();
result.put("listMch", listMch);
在您提供的代码片段中,您创建了一个类型为 Map<String, List<Map<String, Object>>>
的 result
变量,并将其实例化为一个 HashMap
。然后,您将之前创建的 listMch
(它是一个 List<Map<String, Object>>
类型的变量)添加到 result
映射中,键为 "listMch"
。
这里是代码的详细解释:
-
Map<String, List<Map<String, Object>>> result = new HashMap<>();
:- 这行代码创建了一个
HashMap
实例result
。这个映射的键是String
类型,值是List<Map<String, Object>>
类型。这意味着result
可以存储一个或多个键值对,其中每个键都映射到一个列表,列表中的每个元素都是一个映射(Map
),映射的键和值都是Object
类型。
- 这行代码创建了一个
-
result.put("listMch", listMch);
:- 这行代码调用
result
映射的put
方法,将键"listMch"
和值listMch
添加到映射中。这里的listMch
是一个之前定义的List<Map<String, Object>>
类型的变量,它包含了商户信息的列表。
- 这行代码调用
这段代码通常用于将数据组织成层次结构,以便于后续处理或传输。例如,您可能需要将这些数据发送到前端应用程序,或者在内部逻辑中使用这些数据。
在实际应用中,result
映射可以被序列化为JSON格式,以便于通过网络发送,或者在不同的系统和组件之间进行数据交换。例如,如果您使用Jackson或Gson这样的JSON库,您可以轻松地将 result
转换为JSON字符串:
java">import com.fasterxml.jackson.databind.ObjectMapper;// ...ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(result);
System.out.println(jsonString);
多维数据 属性规格
java">/** * 属性数组,JSON 格式 */@TableField(typeHandler = JacksonTypeHandler.class)
private List<Property> properties;/*** 商品属性*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Property {/*** 属性编号* 关联 {@link ProductPropertyDO#getId()}*/private Long propertyId;/*** 属性名字* 冗余 {@link ProductPropertyDO#getName()}** 注意:每次属性名字发生变化时,需要更新该冗余*/private String propertyName;/*** 属性值编号* 关联 {@link ProductPropertyValueDO#getId()}*/private Long valueId;/*** 属性值名字* 冗余 {@link ProductPropertyValueDO#getName()}** 注意:每次属性值名字发生变化时,需要更新该冗余*/private String valueName;}
在Java中,如果你想要循环遍历一个List<ProductPropertyValueDetailRespDTO>
列表,并查找其中skuId
属性值不一样的对象,你可以使用一个简单的for
循环或者forEach
循环来实现。以下是两种常见的方法:
JAVA forEach循环list对象 set 更新list某属性值
java">import java.util.List;// 假设你有一个List<ProductPropertyValueDetailRespDTO>类型的列表
List<ProductPropertyValueDetailRespDTO> list = ...;// 使用forEach循环遍历列表
list.forEach((dto, index) -> {if (index > 0 && !dto.getSkuId().equals(list.get(index - 1).getSkuId())) {// 找到skuId属性值不一样的对象System.out.println("找到skuId属性值不一样的对象: " + dto);}
});
if(sku.getProperties()!=null) {sku.getProperties().forEach(t->t.setSkuId(id)); }
在这个例子中,forEach
循环提供了当前遍历到的对象dto
和它的索引index
。通过比较当前对象的skuId
与前一个对象的skuId
(通过索引index - 1
获取),可以找到skuId
属性值不一样的对象。
JAVA For
使用传统的for
循环list对象
java">import java.util.List;// 假设你有一个List<ProductPropertyValueDetailRespDTO>类型的列表
List<ProductPropertyValueDetailRespDTO> list = ...;// 假设你有一个引用,用于保存上一个遍历到的对象
ProductPropertyValueDetailRespDTO previousDto = null;for (ProductPropertyValueDetailRespDTO dto : list) {if (previousDto != null && !dto.getSkuId().equals(previousDto.getSkuId())) {// 找到skuId属性值不一样的对象System.out.println("找到skuId属性值不一样的对象: " + dto);}previousDto = dto;
}
if(sku.getProperties()!=null) {List<CartDO> cartList = cartMapper.selectListByUserIdAndSpuId(userId,cart.getSpuId());for (CartDO dto : cartList) {if (!cart.getSkuId().equals(dto.getSkuId())) {throw exception(CARD_ITEM_NOTDOUBLE_FOUND);}} }
在这个例子中,previousDto
用于保存上一个遍历到的ProductPropertyValueDetailRespDTO
对象。在每次循环中,都会检查当前对象的skuId
是否与上一个对象的skuId
不同。如果不同,就表示找到了一个skuId
属性值不一样的对象。
疑问:为什么 Controller 分成 Admin 和 App 两种?
提供给 Admin 和 App 的 RESTful API 接口是不同的,拆分后更加清晰。
疑问:为什么 VO 分成 Admin 和 App 两种?
相同功能的 RESTful API 接口,对于 Admin 和 App 传入的参数、返回的结果都可能是不同的。例如说,Admin 查询某个用户的基本信息时,可以返回全部字段;而 App 查询时,不会返回 mobile 手机等敏感字段。
疑问:为什么 DO 不作为 Controller 的出入参?
- 明确每个 RESTful API 接口的出入参。例如说,创建部门时,只需要传入 name、parentId 字段,使用 DO 接参就会导致 type、createTime、creator 等字段可以被传入,导致前端同学一脸懵逼。
- 每个 RESTful API 有自己独立的 VO,可以更好的设置 Swagger 注解、Validator 校验规则,而让 DO 保持整洁,专注映射好数据库表。
当前时间
LocalDateTime.now()
项目备注 当前登入人
getLoginUserId()
插件设置
代码热加载
在日常开发中,我们需要经常修改 Java 代码,手动重启项目,查看修改后的效果。如果在项目小时,重启速度比较快,等待的时间是较短的。但是随着项目逐渐变大,重启的速度变慢,等待时间 1-2 min 是比较常见的。
这样就导致我们开发效率降低,影响我们的下班时间,哈哈哈~
那么是否有方式能够实现,在我们修改完 Java 代码之后,能够不重启项目呢?答案是有的,通过 代码热加载 的方式。实现方案有三种:
- spring-boot-devtools【不推荐】
- IDEA 自带 HowSwap 功能【推荐】
- JRebel 插件【最推荐】
1. spring-boot-devtools
spring-boot-devtools (opens new window)是 Spring Boot 提供的开发者工具,它会监控当前应用所在的 classpath 下的文件发生变化,进行自动重启。
devtools 存在重启速度较慢的问题,所以不推荐!
#2. IDEA 自带 HowSwap 功能
该功能是 IDEA Ultimate 旗舰版的专属功能,不支持 IDEA Community 社区版。
#2.1 如何使用
① 设置 Spring Boot 启动类,开启 HotSwap 功能。如下图所示:
② Debug 运行该启动类,等待项目启动完成。
③ 每次修改 Java 代码后,点击左下角的「热加载」按钮,即可实现代码热加载。如下图所示:
#2.2 存在问题
IDEA 自带 HowSwap 功能,支持比较有限,很多修改都不支持。例如说:
- 只能增加方法或字段但不可以减少方法或字段
- 只能增加可见性不能减少
- 只能维持已有方法的签名而不能修改等等。
你可以认为,只支持方法内的代码修改热加载。
如果想要相对完美的方案,建议使用 JRebel 插件。
#3. JRebel 插件【最推荐】
JRebel 插件是目前最好用的热加载插件,它支持 IDEA Ultimate 旗舰版、Community 社区版。