当前位置: 首页 > web >正文

苍穹外卖项目笔记day03

公共字段的自动填充

在业务接口实现中,数据库中不断重复出现的字段被我们叫做公共字段,例如菜品种类表和员工表里面都有修改人/时间 以及 创建人/时间 四个公共的字段,而且代码也基本一致,都是给对象赋值然后传递到mapper层进行数据库操作,而大量相似的代码会造成代码的冗余.因此我们通过AOP切面编程,来实现其的自动填充

实现步骤:

1). 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

2). 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

package com.sky.aspect;import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect
@Slf4j
@Component
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("开始进行公共字段自动填充...");//获取当前被拦截到方法的数据库操作类型-->如是insert还是update insert四个公共字段,update则两个MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的注解对象OperationType operationType = autoFill.value();//获得数据库操作类型//获取到当前被拦截到方法的参数--实体对象-->获取第一个参数即可Object[] args = joinPoint.getArgs();if (args == null || args.length == 0) {return;}Object entity = args[0];//准备赋值数据 时间和idLocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();//根据当前不同的操作类型,为对应的属性通过反射来赋值if (operationType == OperationType.INSERT) {//为四个字段赋值try {//通过反射获取对应的方法Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射未对象属性赋值setCreateTime.invoke(entity, now);setCreateUser.invoke(entity, currentId);setUpdateTime.invoke(entity, now);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}} else if (operationType == OperationType.UPDATE) {try {//通过反射获取对应的方法Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射未对象属性赋值setUpdateTime.invoke(entity, now);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}}}
}

3). 在 Mapper 的方法上加入 AutoFill 注解 -->拦截我们这里采用的方法是自定义注解,自定义一个方法注解,被该注解标记的方法会被拦截器拦截

在上面的代码中,我们主要是对创建时间,修改时间,创建人,修改人这四个公共字段进行自动填充,实现原理:对使用了@AutoFill注解的mapper方法进行拦截,然后根据使用@Aspect注解的类中通知对这四个字段进行赋值,然后再进行被拦截的方法(由@before我们可知这是一个前置通知)

OSS文件上传接口实现文件上传服务,需要有存储的支持,那么我们的解决方案将以下几种:

  1. 直接将图片保存到服务的硬盘(springmvc中的文件上传)
    1. 优点:开发便捷,成本低
    2. 缺点:扩容困难
  2. 使用分布式文件系统进行存储
    1. 优点:容易实现扩容
    2. 缺点:开发复杂度稍大(有成熟的产品可以使用,比如:FastDFS,MinIO)
  3. 使用第三方的存储服务(例如OSS)
    1. 优点:开发简单,拥有强大功能,免维护
    2. 缺点:付费

显示思路:本项目利用阿里云OSS服务器,把图片上传到阿里云的OSS服务器后,利用后端接收OSS服务器返回的图片URL,然后再返回给前端,前端调用URL进行图片回显

配置类的设置:别把配置类写死,因为我们的项目会经历开发,测试,维护三个阶段,而这三个阶段可能使用的数据库等等配置类不一致,所以我们选择在另外书写一个配置类如:dev,让目标配置类引用开发配置类

接口实现的部分代码

  • 生成OSS工具类对象

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;/*** 文件上传** @param bytes* @param objectName* @return*/public String upload(byte[] bytes, String objectName) {// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {// 创建PutObject请求。ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}//文件访问路径规则 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);log.info("文件上传到:{}", stringBuilder.toString());return stringBuilder.toString();}
}
  • 通用接口
/*** 通用接口*/
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {@Autowiredprivate AliOssUtil aliOssUtil;/*** 文件上传* @param file* @return*/@PostMapping("/upload")@ApiOperation("文件上传")public Result<String> upload(MultipartFile file){log.info("文件上传:{}",file);try {//原始文件名String originalFilename = file.getOriginalFilename();//截取原始文件名的后缀   dfdfdf.pngString extension = originalFilename.substring(originalFilename.lastIndexOf("."));//构造新文件名称String objectName = UUID.randomUUID().toString() + extension;//文件的请求路径String filePath = aliOssUtil.upload(file.getBytes(), objectName);return Result.success(filePath);} catch (IOException e) {log.error("文件上传失败:{}", e);}return Result.error(MessageConstant.UPLOAD_FAILED);}
}
其中我们对两个AliOssUtil进行说明

它们的关系是:一个作为配置类(工厂),负责生产另一个(工具类实例)。

com.sky.config.OssConfiguration 中的 AliOssUtil

角色:这是一个 配置类 中的一个 Bean定义方法。
目的:它的作用不是定义一个类,而是告诉Spring如何创建一个 AliOssUtil 工具类的实例(Bean)。

执行时机:当Spring容器启动时,它会读取这个配置。因为方法上加了 @Bean 注解,Spring会调用这个 aliOssUtil() 方法。

工作流程:

方法接收一个已经配置好的 AliOssProperties 参数(这个参数的值通常来自 application.yml 配置文件)。

方法打印日志:“开始创建阿里云文件上传工具类对象…”。

方法 new 了一个 com.sky.utils.AliOssUtil 类的对象,并将 AliOssProperties 中的配置值(endpoint, accessKeyId等)作为构造参数传入。

最终,它将这个新创建的工具类对象返回给Spring容器管理。之后,在项目的任何地方,你都可以通过 @Autowired 注入这个 AliOssUtil Bean来使用文件上传功能。

@ConditionalOnMissingBean 注解的作用是:如果Spring容器中已经存在一个 AliOssUtil 类型的Bean了,则这个配置方法就不执行。这确保了只有一个工具类实例被创建。

com.sky.utils.AliOssUtil

角色:这是一个具体的工具类,包含了实际的业务逻辑。
目的:封装阿里云OSS SDK的调用细节,提供一个简单的 upload 方法供业务代码使用。

工作流程:

它本身是一个普通的Java类(使用了Lombok的 @Data 和 @AllArgsConstructor),定义了4个属性并通过构造方法初始化。

它提供了 upload(byte[] bytes, String objectName) 方法,该方法内部使用阿里云的 OSSClient 来执行文件上传操作。

它处理了上传过程中可能出现的异常。

它拼接并返回了上传成功的文件的访问URL

http://www.xdnf.cn/news/19904.html

相关文章:

  • 从0 死磕全栈第3天:React Router (Vite + React + TS 版):构建小时站实战指南
  • 机器学习-逻辑回归
  • raspberry Pi 4B(树莓派4B)开启VNC服务 主机用VNC连接
  • 14、Docker构建后端镜像并运行
  • 关于SPI串口spidev接收数据不完整的问题
  • Moonchain:「新加坡大华银行」加持下连接现实金融与链上经济的价值通道
  • 大数据毕业设计选题推荐-基于大数据的电信客户流失数据分析系统-Hadoop-Spark-数据可视化-BigData
  • 03、Maven下载与阿里云镜像加速
  • 电子电气架构 --- 新EEA架构下开发模式转变
  • Openmanus复现教程:打造自己的Agent助手
  • Python之split - 常遇见的bug
  • Redis突然挂了,数据丢了多少?就看你用RDB还是AOF
  • Git配置:禁用全局HTTPS验证
  • LangGraph 时间旅行深度解析:掌握状态、持久化与人机协同工作流
  • SecureCRT v9.5.2 Mac SSH终端操作工具
  • 3种通过USB从电脑传输文件到iPad的方法
  • 【Luogu】P2398 GCD SUM (容斥原理求gcd为k的数对个数)
  • Ubuntu查看开机以来修改的文件
  • k8s,v1.30.4,安装使用docker
  • 嵌入式解谜日志-网络编程(udp,tcp,(while循环原理))
  • [特殊字符] 预告!我正在开发一款让自动化操作变得「像呼吸一样自然」的AI神器
  • 从静态到智能:用函数式接口替代传统工具类
  • 命令行小工具
  • Controller返回CompletableFuture到底是怎么样的
  • Ubuntu系统镜像源配置
  • 数据结构——树(03二叉树,与路径有关的问题,代码练习)
  • SPI片选踩坑实录(硬件片选和软件片选)
  • Base64编码的作用与应用场景
  • 利用 Java 爬虫获取淘宝商品 SKU 详细信息实战指南
  • 美团龙猫(longcat.AI)编写的利用二分查找优化Excel的sheet.xml指定范围输出C程序