苍穹外卖项目说明
1 资料
瑞吉 https://pan.baidu.com/s/1bxEy2bHiCYQtouifUppsTA&pwd=1234
苍穹 https://pan.baidu.com/s/1MNDzXyVlr3mtmLgBjcPJVw&pwd=6633
- 本地位置
C:\Users\20881\IdeaProjects\CangQiongWaiMai\sky-take-out
2 前端
"D:\BaiduNetdiskDownload\java\CangQiongWaiMai\nginx-1.20.2\nginx.exe"
// 端口号 : 80
3 流程


4 DTO
- 前端提交的数据和实体对象差异较大时 使用dto
5 常见问题和解决方法
操作逻辑异常
业务逻辑不允许的操作
-
用户删除分类时, 如果分类下有菜品则不能删除, 使用异常来处理 , 对每个异常都要在全局异常处理器中设置对应的 handler吗?
-
使用继承思想,抛出子异常, 在全局异常处理器中 用父异常接收并处理;
-
父异常
/** * 业务异常 */ public class BaseException extends RuntimeException { public BaseException() { } public BaseException(String msg) { super(msg); } } -
子异常
public class DeletionNotAllowedException extends BaseException { public DeletionNotAllowedException(String msg) { super(msg); } } -
全局异常处理
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 捕获业务异常 * @param ex * @return */ @ExceptionHandler public Result exceptionHandler(BaseException ex){ log.error("异常信息:{}", ex.getMessage()); return Result.error(ex.getMessage()); }
插入异常
表中unique字段如果重复就会有异常
```
2025-01-08 16:47:56.236 ERROR 4276 — [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException:
```
用 GlobalExceptionHandler 接受异常, 返回 Result ;
拦截器token传递
使用 ThreadLocal 对线程设置变量;
日期显示问题
- 日期显示问题:

公共字段

-
这些字段自动填充即可, 如果在每个函数中都手动设置过于冗余且不易维护
-
这些aop一般用在mapper层
-
使用反射
- 编写Log类
- 实现aop方法
- 添加log
-
编写log类
package com.sky.annotation; import com.sky.enumeration.OperationType; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) // @interface 表示注解 public @interface AutoFill { //UPDATE INSERT // 注解中会出现 @AutoFill(value = ) 等于的值为 OperationType中指定的 OperationType value(); } -
实现aop方法
@Slf4j
@Component
@Aspect
public class AutoFillAspect {
/**
* 切入点
*/
@Pointcut("@annotation(com.sky.annotation.AutoFill)")
public void pt(){};
@Before("@annotation(autoFill)" )
public void AutoFill(JoinPoint joinPoint,AutoFill autoFill) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
log.info("开始执行公共字段填充");
//拦截mapper方法 update操作 只用 updateTime updateUser 赋值即可
// 获取方法的参数实体对象
OperationType operationType = autoFill.value();
log.info("获取到传入value:{}",operationType);
Object[] args = joinPoint.getArgs();
if(args.length==0||args==null){
return;
}
Object obj = args[0];
//公共属性赋值
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
if(operationType==OperationType.INSERT){
//四个公共字段赋值
Method setCreateTime = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreateUser = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateTime = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
setCreateTime.invoke(obj,now);
setCreateUser.invoke(obj,currentId);
setUpdateTime.invoke(obj,now);
setUpdateUser.invoke(obj,currentId);
}else{
// 主需要传 update字段
Method setUpdateTime = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = obj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
setUpdateTime.invoke(obj,now);
setUpdateUser.invoke(obj,currentId);
}
}
}
两个表操作
- 开启事务, 在服务实现类方法上添加
@Transactional
先删除后插入
- 更新菜品口味, 口味可能删除了, 因此直接 update业务错误, 要先删后插
- 多对多的关系表可以先删除后插入
少量数据
- 店铺营业状态, 存表不合适
- 使用
redis
冗余字段
只存 id 不存其他的字段, 回显时还要进行多表查询, 因此为了避免进行多表查询, 设置冗余字段.
sql语句返回
- 可能是
null可以额外加个判断
逻辑删除
- 例如订单表, 用户删除不是真正的删除
- 可以在订单表中添加字段表示是否被删除, 在逻辑上增加判断是否已经被删除
规范
配置
application.yml
sky:
jwt:
# 设置jwt签名加密时使用的秘钥
admin-secret-key: itcast
# 设置jwt过期时间
#TODO 设置正确的时间
admin-ttl: 720000000
# 设置前端传递过来的令牌名称
admin-token-name: token
alioss:
access-key-id: ${sky.alioss.access-key-id}
access-key-secret: ${sky.alioss.access-key-secret}
endpoint: ${sky.alioss.endpoint}
bucket-name: ${sky.alioss.bucket-name}
application-dev.yml
sky:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
host: localhost
port: 3306
database: sky_take_out
username: root
password: 1234
alioss:
access-key-id:
access-key-secret:
endpoint: oss-cn-beijing.aliyuncs.com
bucket-name: hzl-demo
结构
common
- java代码中的字符串类型全部提取为常量->
constant context使用ThreadLocal一般使用类包装一下- 异常通过设置父类和子类和全局异常处理器分别处理
- properties 自动加载
result类utils第三方的集成工具:aliyunOss, Jwt
pojo
dto是接收从web传过来的参数的实体entity是实际存在的实体vo是返回前端的实体
service
annotation自定义注解aspect自定义aop切片configWebMvcConfiguration.java设置拦截器消息转换器handler全局异常处理器interceptor登录验证拦截器
名字
/admin/employee路径->controller.admin.employeeController/admin/category/page->controller.admin.categoryController/admin/common/upload->controller.admin.commonController