0


Java项目——苍穹外卖(一)

Entity、DTO、VO

Entity(实体)

  • Entity 是表示数据库表的对象,通常对应数据库中的一行数据。它通常包含与数据库表对应的字段,并可能包含一些业务逻辑。

DTO(数据传输对象)

  • 作用:DTO 是用于在不同层之间传输数据的对象,通常用于网络传输或服务间调用。DTO 主要用于减少网络请求的次数,携带数据而不包含业务逻辑。
  • 特点:DTO类通常只包含数据字段和相应的getter和setter方法,不包含任何业务逻辑。它们可能包含与Entity类相似的字段,但也可能根据需要进行裁剪或扩展。

VO(视图对象)

  • 位置:虽然VO这个术语不如DTO和Entity那样普遍,但在一些项目中,你可能会看到vo包用于存放视图对象。
  • 作用:VO主要用于封装返回给前端的数据。它们可以被视为DTO的一种特殊形式,专门用于视图层的数据展示。VO可以根据前端的需求进行定制,包含前端需要展示的所有数据,以及可能的前端逻辑(如格式化数据)。
  • 特点:VO类与DTO类似,主要关注数据的封装和传输,但更侧重于前端展示的需求。它们可能包含与Entity或DTO不同的字段,或者对字段进行不同的封装和格式化。

举例

对于数据库中的employee表:

  1. @Data
  2. @Builder//构建器注解,此类的对象可以使用builder方法进行构建
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class Employee implements Serializable {
  6. private static final long serialVersionUID = 1L;
  7. private Long id;
  8. private String username;
  9. private String name;
  10. private String password;
  11. private String phone;
  12. private String sex;
  13. private String idNumber;
  14. private Integer status;
  15. //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  16. private LocalDateTime createTime;
  17. //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  18. private LocalDateTime updateTime;
  19. private Long createUser;
  20. private Long updateUser;
  21. }
  1. @Data
  2. public class EmployeeDTO implements Serializable {
  3. private Long id;
  4. private String username;
  5. private String name;
  6. private String phone;
  7. private String sex;
  8. private String idNumber;
  9. }

总结

Entity:

  • 与数据库表对应,包含数据的持久化逻辑。
  • 主要用于数据库操作,在数据访问层与数据库交互时使用。
  • 封装数据库操作的细节
  • 属性通常与数据库表字段一一对应

DTO:

  • 用于层与层之间的数据传输,不包含业务逻辑。
  • 用于系统内部数据传输,在服务层调用中传递数据。
  • 封装业务逻辑的细节
  • 可以包含额外的或部分的属性

VO:

  • 用于封装返回给前端的数据,可能包含前端展示所需的特定逻辑。
  • 在展示层向用户展示数据时使用
  • 封装展示逻辑的细节
  • 可以包含额外的或部分的属性

公共字段填充(AOP)

问题分析

在增加或查询操作中,设置下列字段时代码冗余,不便于后期维护

实现思路

技术点:枚举、注解、AOP、反射

一、创建枚举类

  1. /**
  2. * 数据库操作类型
  3. * 枚举类
  4. */
  5. public enum OperationType {
  6. /**
  7. * 更新操作
  8. */
  9. UPDATE,
  10. /**
  11. * 插入操作
  12. */
  13. INSERT
  14. }

二、创建自定义注解类

  1. /**
  2. * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
  3. * 这个类可以作为一个注解进行使用
  4. */
  5. @Target(ElementType.METHOD)//指定当前的自定义注解只能加在方法上
  6. @Retention(RetentionPolicy.RUNTIME)//固定写法
  7. public @interface AutoFill {
  8. //数据库操作类型:UPDATE INSERT(只有增加和修改操作涉及公共字段填充)
  9. OperationType value();
  10. }

三、在切入点方法上加入自定义注解,并指定其属性(更新操作/插入操作)

四、创建切面类,在切面类中实现通知逻辑

  1. /**
  2. * 自定义切面类,实现公共字段自动填充处理逻辑
  3. */
  4. @Aspect//设置当前类为切面类,告诉spring这个类是用来做AOP的
  5. @Component//通知类(切面类)必须配置成Spring管理的bean
  6. @Slf4j
  7. public class AutoFillAspect {
  8. //此切入点表达式前半部分锁定mapper包下所有类所有方法,后半部分锁定方法中加入了AutoFill注解的方法
  9. @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
  10. public void autoFillPointCut(){}
  11. /**
  12. * 前置通知,在通知中进行公共字段的赋值
  13. */
  14. @Before("autoFillPointCut()")
  15. public void autoFill(JoinPoint joinPoint){
  16. log.info("开始进行公共字段自动填充");
  17. //1.获取当前被拦截的方法上的数据库操作类型
  18. MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获得方法签名对象,并向下转型为MethodSignature
  19. AutoFill antoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
  20. OperationType operationType = antoFill.value();//获得数据库操作类型
  21. //这三行的代码最终作用是获得注解中的数据库操作类型,也就是 @AutoFill(value = OperationType.UPDATE)中的value
  22. //2.获取当前被拦截的方法的参数--实体对象
  23. Object[] args = joinPoint.getArgs();//获取通知点方法的参数
  24. if(args == null || args.length == 0){//如果没有参数则直接返回
  25. return;
  26. }
  27. Object entity = args[0];
  28. //3.准备赋值的数据
  29. LocalDateTime now = LocalDateTime.now();//update_time的值
  30. Long currentId = BaseContext.getCurrentId();//update_user的值
  31. //4.根据当前不同的操作类型,为对应的属性通过反射来赋值
  32. if(operationType == operationType.INSERT){
  33. //新增操作为4个公共字段赋值
  34. try {
  35. //4.1通过反射获取这四个方法
  36. //使用常量类AutoFillConstant中的常量代替方法名,防止自己写写错
  37. Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
  38. Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
  39. Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
  40. Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
  41. //4.2通过反射调用获取到的四个方法为对象属性赋值
  42. setCreateTime.invoke(entity,now);//entity中存的是Employee
  43. //这行代码:使用entity对象调用setCreateTime方法,给方法传递参数now
  44. setCreateUser.invoke(entity,currentId);
  45. setUpdateTime.invoke(entity,now);
  46. setUpdateUser.invoke(entity,currentId);
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. }
  50. }else if(operationType == operationType.UPDATE){
  51. //修改操作为2个公共字段赋值
  52. try {
  53. Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
  54. Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
  55. setUpdateTime.invoke(entity,now);
  56. setUpdateUser.invoke(entity,currentId);
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. }
  62. }

总结

1、创建枚举类,其中有插入、修改操作变量

2、创建自定义注解类,其中属性引用枚举类的变量

  • @Target(ElementType.METHOD)//指定当前的自定义注解只能加在方法
  • @Retention(RetentionPolicy.RUNTIME)//固定写法3、

3、在mapper层中的插入、修改方法上加入自定义注解,并通过属性指定其操作类型(插入或修改)

4、创建切面类,进行切入点表达式和通知的实现

  • @Aspect//设置当前类为切面类,告诉spring这个类是用来做AOP的
  • @Component//通知类(切面类)必须配置成Spring管理的bean

文件上传

利用阿里云实现文件上传功能,将文件上传并存储到阿里云存储空间,并返回文件的访问地址,以便在前端可以回显文件

一、在sky-common中的properties包下创建AliOssProperties类

  1. @Component
  2. @ConfigurationProperties(prefix = "sky.alioss")//将配置文件中sky.alioss的相关属性值赋给此类中的成员
  3. @Data
  4. public class AliOssProperties {
  5. private String endpoint;
  6. private String accessKeyId;
  7. private String accessKeySecret;
  8. private String bucketName;//Bucket名称
  9. }

二、在sky-common中的utils包下创建AliOssUtil类

此类实现upload方法,实现文件上传功能,此方法返回文件的访问路径

  1. @Data
  2. @AllArgsConstructor
  3. @Slf4j
  4. public class AliOssUtil {
  5. private String endpoint;
  6. private String accessKeyId;
  7. private String accessKeySecret;
  8. private String bucketName;
  9. /**
  10. * 文件上传
  11. *
  12. * @param bytes
  13. * @param objectName
  14. * @return
  15. */
  16. //将文件上传到阿里云并返回文件的请求路径
  17. //第一个参数:文件的字节数组,第二个参数:拼接uuid后的新文件名
  18. public String upload(byte[] bytes, String objectName) {
  19. // 创建OSSClient实例。
  20. OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
  21. try {
  22. // 创建PutObject请求。
  23. ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
  24. } catch (OSSException oe) {
  25. System.out.println("Caught an OSSException, which means your request made it to OSS, "
  26. + "but was rejected with an error response for some reason.");
  27. System.out.println("Error Message:" + oe.getErrorMessage());
  28. System.out.println("Error Code:" + oe.getErrorCode());
  29. System.out.println("Request ID:" + oe.getRequestId());
  30. System.out.println("Host ID:" + oe.getHostId());
  31. } catch (ClientException ce) {
  32. System.out.println("Caught an ClientException, which means the client encountered "
  33. + "a serious internal problem while trying to communicate with OSS, "
  34. + "such as not being able to access the network.");
  35. System.out.println("Error Message:" + ce.getMessage());
  36. } finally {
  37. if (ossClient != null) {
  38. ossClient.shutdown();
  39. }
  40. }
  41. //文件访问路径规则 https://BucketName.Endpoint/ObjectName
  42. StringBuilder stringBuilder = new StringBuilder("https://");
  43. stringBuilder
  44. .append(bucketName)
  45. .append(".")
  46. .append(endpoint)
  47. .append("/")
  48. .append(objectName);
  49. log.info("文件上传到:{}", stringBuilder.toString());
  50. return stringBuilder.toString();
  51. }
  52. }

三、在sky-server模块下的config包中创建OssConfiguration类

  1. 此配置类用于创建AliossUtil对象:实现aliOssUtil方法,此方法将AliOssProperties对象作为参数传入,方法内读取AliOssProperties中的四个属性,将其包装为AliossUtil对象返回,并将这个AliossUtil交给ioc容器管理,需要时可以直接依赖注入(注入的AliossUtil对象的四个属性已经赋过值)
  1. 此类相当于一个中间媒介,关联AliOssProperties类和AliOssUtil,接收一个AliOssProperties并将其转换为一个AliOssUtil后返回,本质就是将AliOssProperties中从.yml中读取到的四个属性值赋给AliOssUtil中相应的四个属性

这四个属性的的去向总结为:

.yml(人为预先定义好四个属性的值)--->AliOssProperties类(利用注解从.yml中读取四个属性)-->OssConfiguration类(从类中方法接收的参数AliOssProperties对象中读取四个属性,并封装为AliOssUtil对象)-->AliOssUtil对象(OssConfiguration类中方法的返回值)

  1. @Configuration
  2. @Slf4j
  3. public class OssConfiguration {
  4. @Bean
  5. @ConditionalOnMissingBean//保证整个容器中只有一个AliOssUtil对象
  6. public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
  7. log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
  8. return new AliOssUtil(aliOssProperties.getEndpoint(),
  9. aliOssProperties.getAccessKeyId(),
  10. aliOssProperties.getAccessKeySecret(),
  11. aliOssProperties.getBucketName());
  12. }
  13. }

四、在controller层中创建CommonController类

此类用来对前端文件上传的请求进行响应,前端传来一个文件参数

  1. 在此类中构造新的文件名称(uuid拼接原始文件名后缀)
  2. 调用AliOssUtil中的upload方法进行文件上传(方法参数为文件的字节数组和新文件名字符串)
  3. 上传方法返回值为文件的访问路径,将其封装为Result类型响应给前端
  1. @RestController
  2. @RequestMapping("/admin/common")
  3. @Api(tags = "通用接口")
  4. @Slf4j
  5. public class CommonController {
  6. @Autowired
  7. private AliOssUtil aliOssUtil;
  8. /**
  9. * 文件上传
  10. * @param file
  11. * @return
  12. */
  13. @PostMapping("/upload")
  14. @ApiOperation("文件上传")
  15. public Result<String> upload(MultipartFile file){
  16. log.info("文件上传:{}",file);
  17. try {
  18. //获取原始文件名
  19. String originalFilename = file.getOriginalFilename();
  20. //将原始文件名的后缀截取出来
  21. String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
  22. //构造新文件名称(uuid拼接原始文件名后缀)
  23. String objectName = UUID.randomUUID().toString() + extension;
  24. //获取文件的请求路径
  25. String filePath = aliOssUtil.upload(file.getBytes(), objectName);
  26. return Result.success(filePath);
  27. } catch (IOException e) {
  28. log.error("文件上传失败:{}",e);
  29. }
  30. return null;
  31. }
  32. }

总结

文件上传功能的核心为CommonController类和AliOssUtil类

  • CommonController类用来对前端请求进行响应,调用依赖注入的AliOssUtil对象的upload方法进行文件上传,并返回文件的请求路径
  • AliOssUtil类用来实现upload方法进行文件上传功能,实现的前提是已获取到四个属性的值
  • 剩下的AliOssProperties类和OssConfiguration类是用来创建AliOssUtil对象(将其四个属性赋值)并将其交给ioc容器(以便在CommonController中可以直接依赖注入)
标签: 数据库 java spring

本文转载自: https://blog.csdn.net/2301_79368422/article/details/141999223
版权归原作者 懒阳羊 所有, 如有侵权,请联系我们删除。

“Java项目——苍穹外卖(一)”的评论:

还没有评论