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

苍穹外卖项目笔记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://Kd7dj9Ny.qggxt.cn
http://yK1yWZYa.qggxt.cn
http://vFNLQsfY.qggxt.cn
http://0nFLlE8v.qggxt.cn
http://rJlJcAMG.qggxt.cn
http://LU3WA6cq.qggxt.cn
http://nWIUiVA0.qggxt.cn
http://kvr1jckv.qggxt.cn
http://QyQEamMz.qggxt.cn
http://HkHZ5VLL.qggxt.cn
http://De1pyQF7.qggxt.cn
http://sB3TWfG5.qggxt.cn
http://G775cgN1.qggxt.cn
http://CR5RGmli.qggxt.cn
http://WMajma3L.qggxt.cn
http://bFAroOOd.qggxt.cn
http://K1qlODkl.qggxt.cn
http://yDS2CRVH.qggxt.cn
http://IXBwXfuX.qggxt.cn
http://eOraLAY3.qggxt.cn
http://BJ5aXH5T.qggxt.cn
http://QPsopQIH.qggxt.cn
http://pS3lPPkW.qggxt.cn
http://M1BkoEVu.qggxt.cn
http://WQ8pguiB.qggxt.cn
http://LJmAb7cl.qggxt.cn
http://7Q4VvRjb.qggxt.cn
http://SLEseaZZ.qggxt.cn
http://2KT26Jd4.qggxt.cn
http://hbJnPvrg.qggxt.cn
http://www.dtcms.com/a/364297.html

相关文章:

  • 【ShiMetaPi M4-R1】上手:RK3568B2|开源鸿蒙(OpenHarmony) 应用开发快速上手
  • 开源检索增强生成(UltraRAG)框架
  • KafkaRocketMQ重平衡容灾机制
  • 腾讯开源混元多语言翻译模型—— Hunyuan-MT
  • 【算法--链表】142.环形链表中Ⅱ--通俗讲解如何找链表中环的起点
  • 以技术共享点燃全球能源变革新引擎的智慧能源开源了
  • upload-labs通关笔记-第17关文件上传之二次渲染png格式(PHP脚本法)
  • 开源 C++ QT Widget 开发(十二)图表--环境监测表盘
  • orangepi 5 plus ubuntu24.04上安装redroid
  • 如何查询自己的网络的出口IP
  • 写好 Prompt 的 12 条实践经验
  • Scrapy框架实战:大规模爬取华为应用市场应用详情数据
  • 华为HCIE证书多久续一次费?费用多少?
  • nano banana官方最强Prompt模板来了!六大场景模板详解
  • 如何将华为手机数据转移到OPPO手机
  • 《华为基本法》——企业文化的精髓,你学习了几条?
  • 车辆安全供电系统开发原则和实践
  • 利用 Java 爬虫获取淘宝商品详情 API 接口
  • 指针高级(1)
  • Meta-Learning入门:当AI学会“举一反三”——用MAML实现少样本图像分类 (Meta-Learning系列
  • Qt + windows + Linux+QtInstallerFramework打包教程
  • QNX pidin 命令中STATE 含义
  • vue2 + ts 实现透视卡片 + 瀑布上下移动效果
  • 计算机网络---CA证书体系(Certificate Authority)
  • FPGA离群值剔除算法
  • 【C++】在 Windows 系统调用第三方程序(创建进程)
  • 校园外卖点餐系统(代码+数据库+LW)
  • LeetCode 刷题【62. 不同路径】
  • 【Linux】Linux开发必备:Git版本控制与GDB调试全指南
  • ESXI8多网卡链路聚合