苍穹外卖零碎知识点学习记录
Swagger
swagger可以自动根据代码接口生成接口文档,还可以在里面测试接口
**思考:**通过 Swagger 就可以生成接口文档,那么我们就不需要 Yapi 了?
1、Yapi 是设计阶段使用的工具,管理和维护接口
2、Swagger 在开发阶段使用的框架,帮助后端开发人员做后端的接口测试
通过以下注解,会影响最终的接口文档。在编写代码的过程中,随手加上这些注解,增加文档的可读性
写在xml里的sql
所实现的功能不止是对员工启用或禁用,而是可以对员工信息的多个字段进行动态更新。
为什么能适用多个功能呢?
因为<set>
标签里使用了多个 <if>
标签来进行条件判断。对于每个字段,只有当传入的 Employee
对象中对应的属性不为 null
时,才会将该字段的更新语句添加到 SET
子句中
<update id="update" parameterType="com.sky.entity.Employee">
update employee
<set>
<if test="name != null">name = #{name},</if>
<if test="username != null">username = #{username},</if>
<if test="password != null">password = #{password},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="sex != null">sex = #{sex},</if>
<if test="idNumber != null">id_Number = #{idNumber},</if>
<if test="updateTime != null">update_Time = #{updateTime},</if>
<if test="updateUser != null">update_User = #{updateUser},</if>
<if test="status != null">status = #{status},</if>
</set>
where id = #{id}
</update>
前端调试技巧
在这里可以看到请求URL等
关于DTO的编程规范
像这样,虽然传进来的是DTO,但用mapper访问数据层的时候,最好还是用原来的实体去访问
关于static关键字在线程中的应用
static的作用
这个 BaseContext
类的作用是 使用 ThreadLocal
在当前线程内存储和获取 id
,通常用于存储当前登录用户的 ID,确保在同一请求线程内可以随时访问该 ID,而不会被其他线程干扰。
代码解析
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
public static Long getCurrentId() {
return threadLocal.get();
}
public static void removeCurrentId() {
threadLocal.remove();
}
}
BaseContext.setCurrentId(1001L); // 线程 A 存储 ID 1001 BaseContext.setCurrentId(1002L); // 线程 B 存储 ID 1002 System.out.println(BaseContext.getCurrentId());
- 线程 A 获取的是 1001
- 线程 B 获取的是 1002
- 互不影响
static
的作用
在 BaseContext
这个类里,static
主要有两个作用:
-
保证
threadLocal
变量在整个类中共享public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
static
使得threadLocal
属于类级别的变量,所有方法都能访问它。- 但每个线程有自己的
ThreadLocal
副本,不会影响其他线程。
-
setCurrentId()
、getCurrentId()
这些方法是静态方法public static void setCurrentId(Long id) { threadLocal.set(id); }
- 这些方法不需要创建
BaseContext
对象,可以直接BaseContext.setCurrentId(id)
调用。 - 方便全局使用,尤其是在拦截器、过滤器等地方。
- 这些方法不需要创建
总结
ThreadLocal
让每个线程有自己独立的id
,避免线程安全问题。static
让threadLocal
变量和方法可以直接使用,不需要创建对象。- 常用于存储当前用户 ID,便于在同一线程内访问(如在拦截器中存 ID,在后续业务逻辑中获取 ID)。
Serializable 序列化
Serializable
是什么?
Serializable
是 Java 序列化接口,用于 将对象转换为字节流,以便存储或传输。
在 EmployeePageQueryDTO
类中,它的作用是 让该类的对象支持序列化,方便网络传输、文件存储、缓存等操作。
为什么需要 Serializable
?
Java 的对象通常是存储在内存中的,但有时需要:
- 将对象保存到文件(持久化存储)。
- 在网络中传输对象(如远程调用 RMI、RPC、Web API)。
- 存入 Redis、数据库(如 MyBatis、JPA)。
- 跨 JVM 传输数据(分布式系统中)。
Java 无法直接存储对象,必须转换成 字节流,这就是序列化的作用。
消息转换器
/**
* 扩展Spring MVC框架的消息转化器
* @param converters
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建一个消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转化器加入容器中
converters.add(0,converter);
}
Spring MVC 消息转换器(MessageConverter)
在 Spring MVC 中,消息转换器(HttpMessageConverter
)用于将 Java 对象转换为 HTTP 响应体(比如 JSON)或者从 HTTP 请求体解析 Java 对象。
Spring 默认提供了一些消息转换器,如:
MappingJackson2HttpMessageConverter
(用于 JSON 转换)StringHttpMessageConverter
(用于String
类型)ByteArrayHttpMessageConverter
(用于byte[]
)
为什么要自定义 ObjectMapper
?
Spring 默认的 Jackson 配置可能不符合业务需求,所以可以自定义 ObjectMapper
,比如:
- 统一时间格式
yyyy-MM-dd HH:mm:ss
- 忽略
null
值字段 - 处理
BigDecimal
精度问题
以下是JacksonObjectMapper
代码
package com.sky.json;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
总结
✅ extendMessageConverters
作用: 自定义消息转换器,优先使用自定义 JSON 处理规则
✅ MappingJackson2HttpMessageConverter
: 基于 Jackson 进行 JSON 转换
✅ 自定义 JacksonObjectMapper
作用: 统一 JSON 处理规则,例如时间格式、忽略 null
值
✅ 修改默认 converters
列表: converters.add(0, converter)
确保 Spring MVC 优先使用 该转换器