苍穹外卖项目学习笔记
DAY 1(2026.1.15)
一个request对应一个THREAD,所以参考threadLocal,可以用一个工具类用于维护该请求,并写方法。 @Builder注解详解
public class BaseContext {
public 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(); }
}学习jwt相关实现逻辑,需要JWTutil工具类的parse JWT方法和 注解:@Component :可被当成springbean @Slf4j:日志可扫描 学习了Swagger的配置(可以用Knife4j依赖整合):
@Configuration@Slf4jpublic class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
/** * 注册自定义拦截器 * * @param registry */ protected void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器..."); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/employee/login"); }
/** * 通过knife4j生成接口文档 * @return */ @Bean public Docket docket() { ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; }
/** * 设置静态资源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); }}DAY 2
注解:@jsonformat注解用于实体类和前端json的转换; 序列化:java->json 反序列化:json->java 需要在web配置类新增拦截器
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); }}pagehelper用于辅助分页,先用pageStarpage方法,返回Page类型
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) { PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize()); Page<Employee> page= employeeMapper.pageQuery(employeePageQueryDTO); long total = page.getTotal(); List<Employee> result = page.getResult();
return new PageResult( total, result );}学习了markdown语法—https://blog.csdn.net/u014061630/article/details/81359144 学习了mysql基础语法—https://blog.csdn.net/qq_45173404/article/details/115712758 pathVariable注解
DAY 3(学习时长3小时)
热部署devtools # HTTP协议中的各种请求头、请求类型的作用以及用途 servlet视频 servletCSDN 工作原理 Servlet接口定义了Servlet与servlet容器之间的契约。这个契约是:Servlet容器将Servlet类载入内存,并产生Servlet实例和调用它具体的方法。但是要注意的是,在一个应用程序中,每种Servlet类型只能有一个实例。
public interface Servlet { void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; String getServletInfo(); void destroy();}BeanUtils的copyProperties方法记得在DTO与Entity之间复用 完成了分类管理和员工管理CRUD;
DAY 4
学习了如何对公共字段进行复用处理SpringAOP
需要一个切入类,内有两个方法:定义切入点,定义切入逻辑方法(参数为调用切入点的方法) 自定义注解 @Target指定对什么方法可以用该注解 @Retention指定什么时候执行注解 @Aspect( Pointcut 和 Advice 组成) @Pointcut execution包含’切点表达式’(“*返回 包的对应类.方法.(参数) &&@anotation(注解路径)”) @Joinpoint注解 结合aspect使用 反射
public class Text04 { public static void main(String[] args) throws ClassNotFoundException { Class clz = Class.forName("java.util.HashMap");
//获取类名 System.out.println("完全限定名:"+clz.getName()); System.out.println("简单的类名:"+clz.getSimpleName());
//获取包名 System.out.println("package"+clz.getPackage().getName()); System.out.println();
//获取成员变量 Field[] fieldArray =clz.getDeclaredFields(); System.out.println("成员变量(字段)"); for(Field field:fieldArray) { System.out.println(field); } System.out.println();
//获取成员方法 Method[] methodArray = clz.getDeclaredMethods(); System.out.println("成员方法"); for(Method method:methodArray) { System.out.println(method); } }}切面类实现逻辑
public class AutoFillAspect { @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut(){ } @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) { log.info("开始进行公共字段数据填充"); // 判断当前数据对象是插入还是更新操作 MethodSignature signature = (MethodSignature)joinPoint.getSignature(); AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); OperationType value = autoFill.value(); // 获取方法参数 Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } Object entity = args[0]; LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); if (value == OperationType.INSERT) { try { entity.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class).invoke(entity, now); entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class).invoke(entity, now); entity.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class).invoke(entity, currentId); entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class).invoke(entity, currentId); } catch (Exception e) { e.printStackTrace(); } } else if (value == OperationType.UPDATE) {try { entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class).invoke(entity, now); entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class).invoke(entity, currentId); } catch (Exception e) { e.printStackTrace(); } } // 根据操作类型,为对应的属性赋值 log.info("结束进行数据填充"); }}DAY 5 1.20
Mybatis简单复习MYBATIS: 视频:Mybatis $#区分 xml全限定名对应,id为对应方法,resultType为返回类型的全限定类名。 typeAliases: 在mapper.xml中需要使用parameterType和resultType属性来配置SQL语句的输入参数类型和输出参数类型,类必须要写上全限定名,比如一个SQL的返回值映射为Student类,则resultType属性要写com.yogurt.po.Student,这太长了,所以可以用别名来简化书写,比如
<typeAliases> <typeAlias type="com.yogurt.po.Student" alias="student"/></typeAliases>在xml写id<时,需要进行转义字符,或CDATA(纯文本)
条件查询实例:
<select id="pageQuery" resultType="com.sky.entity.Employee"> select * from employee <where> <if test="name != null and name !=''"> and name like concat('%',#{name},'%') </if> </where> order by create_time desc</select>Classpath:maven工程中,类路径指的是 src/main/java,或者是 src/main/resource 下的路径就是类路径。
DAY 6
StringBuffer与StringBuilder的区别 # 配置文件详解 半小时入门MINIO
DAY 7(2026.1.24找寒假工休息几天)
DAY8 (1.28 下班9.30点-)
minio启动:.\minio.exe server D:\minio\data —console-address “127.0.0.1:9000” —address “127.0.0.1:9005”
resultmap用于替换resulttype,以便处理实体类属性和数据库字段不对应名字。适用于驼峰命名以外情况# resultMap 用法
三种mybatis查询方式:1、传参配合@Param绑定字段,2、传入实体类对象,3、传入map类对象键值对;
标签:choose 配合多选一的条件,与标签when 配合,作用与switch case
insert into db(xxx) values/value (xxx/x) 标签属性useGeneratedkeys true KeyProperty用于返回插入后的主键ID值。
update DB set xx=? where xx=? 配合IF标签写动态Sql
delete from db where xx in (???) foreach标签:collection对应数组,item数组元素类型,separator分隔符。open close对应始终(open close非必选,若用(内使用foreach,不写) 多个传参到mybatis本质是传送MAP集合,键为argX和paramX
DAY 9 1.29 19.43
todo复习Pagehelper
:PageHelper拦截的是org.apache.ibatis.executor.Executor的query方法,其传参的核心原理是通过ThreadLocal进行的。当我们需要对某个查询进行分页查询时,我们可以在调用Mapper 进行查询前调用一次PageHelper.startPage(..),这样PageHelper会把分页信息存入一个ThreadLocal变量中。在拦截到Executor的query方法执行时会从对应的ThreadLocal中获取分页信息,获取到了,则进行分页处理,处理完了后又会把ThreadLocal中的分页信息清理掉,以便不影响下一次的查询操作。所以当我们使用了PageHelper.startPage(..)后,每次将对最近一次的查询进行分页查询,如果下一次查询还需要进行分页查询,需要重新进行一次PageHelper.startPage(..)。这样就做到了在引入了分页后可以对原来的查询代码没有任何的侵入性。此外,在进行分页查询时,我们的返回结果一般是一个java.util.List,PageHelper分页查询后的结果会变成com.github.pagehelper.Page类型,其继承了java.util.ArrayList,所以不会对我们的方法声明造成影响。com.github.pagehelper.Page中包含有返回结果的分页信息,包括总记录数,总的分页数等信息,所以一般我们需要把返回结果强转为com.github.pagehelper.Page类型。以下是一个简单的使用PageHelper进行分页查询的示例代码。
https://blog.csdn.net/itcats_cn/article/details/81586724
@EnableTransactionManagement事务管理器
完成菜品管理
泛型
撤销推送
DAY 10 1.30 22:00
git回滚 git git之push -force # DTO、VO、Entity的区别 完成菜品管理 @RequestBody是用于处理json传参过来的,而分页查询DTO是通过使用url传参
DAY11 2.1 22:10
# 抽象类和接口区别 抽象类是属于类,接口是所有抽象方法的集合 # PageHelper使用与原理介绍 # ThreadLocal 线程安全
DAY 12 3.15
Redis命令五大数据类型: hash :hset 操作field list :lpush set :sadd 有序set:zadd 操作对象 string:set key value 学习了docket配置,学习redistemplate操作redis,写营业状态接口。 # HttpClient的介绍与使用 get:gethttpclient
public void test() throws IOException { //创建httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建httpget对象与 url HttpGet getstatus = new HttpGet("http://localhost:8080/user/shop/status"); //发送请求 CloseableHttpResponse response = httpClient.execute(getstatus); System.out.println(response.getStatusLine().getStatusCode()); System.out.println(EntityUtils.toString(response.getEntity())); //关闭资源 response.close(); httpClient.close();}post(以login为例)
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!