对应黑马苍穹教程使用寒夜外卖项目代码学习

一整个后端项目内包含三个模块,项目有父pom(统一管理依赖版本,聚合子pom),每个模块有单独子pom

 

common模块(放乱七八糟杂的)

constant目录

变量类(用于统一管理项目中的变量的固定值,避免硬编码,提高代码可维护性和可读性)

context目录(用于在同一个线程中共享数据,线程局部存储、获取、清除当前用户信息,确保在同一个请求链路中可以访问到用户信息的BasaContext类)

enumeration目录

枚举类(用于定义一组固定的业务状态或类型,提供类型安全的值集合,避免使用字符串或数字常量带来错误的OperationType类)

exception目录

异常类(处理业务异常的自定义异常类)

json目录(用于json数据序列化与反序列化的JacksonObjectMapper类)

log目录

日志类(用于敏感数据脱敏处理、控制日志输出的SensitiveDataConverter类)

properties目录(包含JWT 相关配置的JwtProperties类,包含微信支付或登录相关配置的WeChatProperties类)

配置类

result目录

封装类(封装响应数据格式如code、msg、data的result封装类,封装分页查询得到的数据的PageResult类)

utils目录

工具类(发送http各种方式请求的HttpClientUtil类,jwt令牌加密解密的JwtUtil类,微信支付下单退款的WeChatPayUtil类)

web.filter目录

请求ID过滤器(通过 @WebFilter 或配置类注册的过滤器,为每个HTTP请求生成唯一ID并添加到日志和响应头中的过滤器,用于请求追踪和问题排查的RequestIdFilter类)

 

pojo模块

dto目录

dto类(作为接收不同属性组合的构造器,通常用于Controller层接收参数,有些里面写着page字段和pageSize字段用于分页查询)

entity目录

存放实体类(对应数据库字段所写的后端属性的对象类)

vo目录

vo类(用于返回给前端的数据封装,当实体类属性不满足响应前端需求时,基于原本响应数据,扩展前端需要的额外属性用的,也可以直接封装dto或实体类再加上扩展属性,也可以封装多个实体类一起响应给前端,也可以只传实体类没有的计算总和的属性)

 

server(服务器)模块

controller接收请求层在

annotation目录

自定义注解类(用于标识某个方法需要进行功能字段自动填充处理的AutoFill类)

aspect目录

切面类(用来aop在方法前置通知中进行公共字段赋值的AutoFillAspect类)

config目录

配置类(用于配置Redis连接和序列化方式的RedisConfiguration类,配置Web MVC(拦截器和消息转换器)和用于配置WebSocket服务端点的WebMvcConfiguration类,用于配置WebSocket服务端点的WebSocketConfiguration类)

controller目录

表现层(用来确定后端请求接口,调用service层,响应前端数据的)

handler目录

全局异常处理器(所有报错都按这个格式打印的GlobalExceptionHandler类)

interceptor目录

拦截器(校验管理员jwt令牌的JwtTokenAdminInterceptor类,校验用户jwt令牌的JwtTokenUserInterceptor类)

mapper目录

数据访问层(用来给后端对数据库进行数据增删改查写sql语句的,这个目录放的是接口或静态sql,动态sql在resources目录的mapper目录里面)

service目录

业务层(用来处理业务逻辑,调用mapper层,管理事务的,直接目录下的是接口,serviceImpl里面的是实现类)

task目录

定时任务类(用来存放定时任务的OrderTask类)

 websocket目录

服务端组件(用于实现实时通信,让服务器能够主动推送消息给客户端,主要用于订单状态的实时更新的WebSocketServer类)

 

resources 目录,存放配置文件、静态资源和模板文件。
测试代码通常放在 src/test 目录下

 

还能优化,让项目结构更加完整:

 

从0开始的话,先搞数据库,再搞实体类

数据库一般用int不用integer

java后端实体类dto类vo类全用integer吧(包括页码和每页记录数)

数据库字段命名用下划线法

后端实体类变量命名用驼峰命名

配置文件写配置自动转换变量名

实体类里面(比如Order类)

  • ​​@Data​​:Lombok 注解,自动生成 gettersettertoStringequalshashCode 方法(​​不生成构造器​​)。
  • ​​@NoArgsConstructor​​:生成无参构造器。
  • ​​@AllArgsConstructor​​:生成全参构造器(所有字段作为参数)。
  • ​​@Builder​​:生成构建者模式(Builder 类),但需要依赖目标类的某个构造器来创建实例,需要构造不可变对象(final 字段)。

以下是 @Builder 带来的核心优势,结合实际场景说明:

1. ​​简化复杂对象的构造过程​​

传统方式构造一个多字段对象时,若存在大量可选参数(例如用户信息中的 nameageemailaddressphone 等,其中部分参数可能不需要每次都设置),通常有两种选择:

传统方式(无参构造 + setter):

User user = new User();
user.setName("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
// 其他字段(如 address、phone)保持默认 null
 

@Builder 方式:

User user = User.builder()
        .name("张三")
        .age(25)
        .email("zhangsan@example.com")// 无需设置的字段(如 address、phone)自动忽略
         .build();
 
 
还有
public class AddressBook implements Serializable  
其中implements Serializable 是 Java 中的一个标记接口(marker interface),就是给类一个"通行证",告诉 Java 这个类的对象可以被转换成字节流进行传输或存储。
 
还有
@Serial
private static final long serialVersionUID = 1L;
这样的声明表明这个类是可序列化的,并且当前版本号是 1。如果将来类的结构发生变化,但希望保持向后兼容性,可以保持这个值不变。

@Serial 注解:

这是 Java 14 引入的注解

用于标记与序列化相关的字段和方法

主要是为了代码的可读性和可维护性

编译器会检查被标记的字段或方法是否符合序列化规范

 

private BigDecimal amount; // 实收金额 中的 BigDecimal 是 ​​Java 中用于高精度十进制运算的类​​,属于 java.math 包。它主要用于处理需要精确计算的数值场景(如金融金额、货币计算等),避免基本数据类型(如 doublefloat)因浮点数精度丢失导致的问题。

 

  SetmealDishWithPic实体类

为什么不直接在数据库放图片而是多弄一个类

 

  1. DTO (Data Transfer Object) - 数据传输对象:

    • 主要用于接收前端传来的数据
    • 通常在Controller层接收请求参数
    • 包含前端提交的数据
    • 用于数据的输入
    • 例如:SetmealDTO、DishDTO、UserDTO
  2. VO (Value Object) - 值对象:

    • 主要用于将后端数据传递给前端
    • 通常在Controller层返回给前端
    • 包含需要展示给前端的数据
    • 用于数据的输出
    • 例如:SetmealVO、DishVO、OrderVO

dto目录的OrderPageDTO类

这是什么意思 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime beginTime; // 开始时间 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime endTime; // 结束时间

 

DishDTO类

private List<DishFlavor> flavors = new ArrayList<>();

 是一个用于存储菜品口味信息的列表字段。让我详细解释它的作用和使用场景:

1. 字段定义解析

private List<DishFlavor> flavors = new ArrayList<>();

  • private:访问修饰符,表示该字段仅在当前类中可访问
  • List<DishFlavor>:泛型列表,表示这是一个 

DishFlavor

 对象的集合

  • flavors:字段名,表示菜品口味
  • = new ArrayList<>():初始化一个空的 ArrayList,避免空指针异常

2. 业务含义

这个字段用于存储一个菜品可能具有的多种口味选项。例如:

  • 对于"麻辣香锅"这道菜:
    • 口味1:辣度 - 微辣/中辣/特辣
    • 口味2:配菜 - 加豆腐/加金针菇/加牛肉

 

vo目录的OrderVo类

@EqualsAndHashCode(callSuper = true)
public class OrderVO extends Order implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private String orderDishes; // 订单菜品信息(JSON字符串格式)
private List<OrderDetail> orderDetailList; // 订单详情列表
}

@EqualsAndHashCode(callSuper = true) 在 OrderVO 类中的详细解释

@EqualsAndHashCode(callSuper = true) 是 Lombok 提供的注解,用于​​自动生成 equals() 和 hashCode() 方法​​,并明确要求这两个方法在比较对象时​​包含父类的字段​​。结合 OrderVO 类,我们可以从以下几个角度理解其作用:

一、基础作用:生成 equals 和 hashCode 方法

@EqualsAndHashCode 注解的核心功能是为类自动生成 equals(Object o) 和 hashCode() 方法。这两个方法是 Java 中用于对象比较和哈希计算的核心方法,广泛用于集合(如 HashSetHashMap)、缓存、状态校验等场景。

二、callSuper = true 的特殊含义

默认情况下(不指定 callSuper 或设为 false),@EqualsAndHashCode 只会比较​​当前类​​中声明的字段。但如果父类(如 Order)包含关键业务字段(如订单ID、订单号),这些字段不会被自动包含在比较中,可能导致对象比较逻辑不完整。

callSuper = true 的作用是:​​生成的 equals() 和 hashCode() 方法会先调用父类的 equals() 和 hashCode() 方法​​,从而将父类的字段纳入比较范围。

 

 

 

登录逻辑的jwt令牌以及md5加密

posted @ 2025-06-19 18:08  BKYNEKO  阅读(40)  评论(0)    收藏  举报