对于给实体类传参的一些思考:链式编程和实体类注入的玩法

在开发过程中,我们一定会遇到这样一个场景:数据库创建一个表,再创建对应的实体类,最后再给实体类的每个字段赋值。

例如为实体类Aliyun 赋值

@Data
public class Aliyun {
    public String appKey;

    public String appSecret;

    public String bucket;

    public String endPoint;
}

方法一:手动set

public static void main(String[] args) {
        Aliyun aliyun = new Aliyun();
        aliyun.setAppKey("yourAppKey");
        aliyun.setAppSecret("yourAppSecret");
        aliyun.setBucket("yourBucket");
        aliyun.setEndPoint("yourEndPoint");
    }

方法二:copyProperties

    public static void main(String[] args) {

        // queryMap模拟前端传参
        Map<String,Object> queryMap = new HashMap<>(16);
        queryMap.put("appKey", "yourAppKey");
        queryMap.put("appSecret", "yourAppSecret");
        queryMap.put("bucket", "yourBucket");
        queryMap.put("endPoint", "yourEndPoint");
        Aliyun aliyun2 = new Aliyun();
        BeanUtils.copyProperties(queryMap, aliyun2);
    }
有的公司不建议使用这种写法,因为调试的时候比较棘手,例如appKey字段的值不对,我直接根据setAppKey就清楚知道哪里操作了该字段,你使用copyProperties,排查效率太低。

方法三: 链式编程

目标效果:

Aliyun aliyunInstance = Aliyun.options()
                .setAppKey("yourAppKey")
                .setAppSecret("yourAppSecret")
                .setBucket("yourBucket")
                .setEndPoint("yourEndPoint")
                .build();

这样代码就干净很多,也很省事。这种风格就是链式编程,如何实现这种效果呢?

1. 创建实体类

/*
   演示一个方法链编程风格
 */

public class Aliyun {
    private String appKey;

    private String appSecret;

    private String bucket;

    private String endPoint;

    public static class Builder{
        private String appKey;

        private String appSecret;

        private String bucket;

        private String endPoint;

        public Builder setAppKey(String appKey){
            this.appKey = appKey;
            return this;
        }

        public Builder setAppSecret(String appSecret){
            this.appSecret = appSecret;
            return this;
        }

        public Builder setBucket(String bucket){
            this.bucket = bucket;
            return this;
        }

        public Builder setEndPoint(String endPoint){
            this.endPoint = endPoint;
            return this;
        }

        public Aliyun build(){
            return new Aliyun(this);
        }

    }

    /**
     * 调用Builder类
     */
    public static Builder options(){
/*
          创建对象
          Aliyun.Builder demo = new Builder();
          return demo;
          简化为一句
*/
        return new Aliyun.Builder();


    }

    /**
     * 有参构造方法
     */
    private Aliyun(Builder builder){
        this.appKey = builder.appKey;
        this.appSecret = builder.appSecret;
        this.bucket = builder.bucket;
        this.endPoint = builder.endPoint;
    }

    public String getAppKey() {
        return appKey;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public String getBucket() {
        return bucket;
    }

    public String getEndPoint() {
        return endPoint;
    }

    @Override
    public String toString() {
        return "Aliyun{" +
                "appKey='" + appKey + '\'' +
                ", appSecret='" + appSecret + '\'' +
                ", bucket='" + bucket + '\'' +
                ", endPoint='" + endPoint + '\'' +
                '}';
    }
}

单元测试

public static void main(String[] args) {
        // 这种写法无法修改设置的参数
        Aliyun aliyunInstance = Aliyun.options()
                .setAppKey("yourAppKey")
                .setAppSecret("yourAppSecret")
                .setBucket("yourBucket")
                .setEndPoint("yourEndPoint")
                .build();
        }

这种写法有个局限性,就是一旦set值后,无法再修改该实例的字段值 。这种局限性有利有弊。

先说弊端,肯定是拓展性太差,日常业务避免不了修改此实例的字段值。

优化:可以对同一实例再次set字段值

		 // 可以修改参数的写法
        Aliyun.Builder builder = Aliyun.options()
                .setAppKey("yourAppKey")
                .setAppSecret("yourAppSecret")
                .setBucket("yourBucket")
                .setEndPoint("yourEndPoint");

        Aliyun aliyunInstance2 = builder.setAppKey("myAppKey").build();

Bean的玩法

再来说说好处

例如我们有一个配置文件,配置文件有4个参数,我们需要读取配置文件的四个参数,赋值给该类。并将这个类声明为一个bean,以后哪里需要配置文件的参数值,直接注入这个bean,使用起来相当方便

例如一个application.properties配置文件

appKey=1
appSecret=1
bucket=lynn
endPoint=https://www.aliyun.com

第一步:创建Aliyun实体类,同上
第二步:读取配置参数,写入实体类,声明为Bean

/**
 * 读取配置信息,将参数写入到类中,并将该类声明为一个Bean托管
 */
@SpringBootConfiguration
public class statementBean {

    @Value("${appKey}")
    private String appKey;
    @Value("${appSecret}")
    private String appSecret;
    @Value("${bucket}")
    private String bucket;
    @Value("${endPoint}")
    private String endPoint;

    @Bean
    public Aliyun aliyun(){
        return Aliyun.options()
                .setAppKey(appKey)
                .setAppSecret(appSecret)
                .setBucket(bucket)
                .setEndPoint(endPoint)
                .build();
    }
}

第三步:注入Bean,使用参数

/**
 * 获取Bean并使用
 */
@Service
public class userBean {
    @Autowired
    private Aliyun aliyun;

    public void printStr(){
        System.out.println(aliyun.getAppKey());
        System.out.println(aliyun.getBucket());
        System.out.println(aliyun.getAppSecret());
        System.out.println(aliyun.getAppSecret());
    }


}

这时有人会质疑,直接 @Value(“${appKey}”)取出来后用就行了,多搞一个Bean出来,岂不是多此一举。

针对这个问题,现在只是取出来配置文件的个别参数,实际项目中会有上百个参数等待使用,那么你用时得取一次,他用时得取一次,且不方便管理。现在我只需要创建一个配置类的包,里面创建一些配置类,这些配置类中存放着配置文件的值。谁要用直接注入对应的Bean即可。这多方便处理。

此外,这种链式风格的写法,还起到了限制作用。一旦配置文件的值被存入aliyunInstance 这个实例,那么该实例的值就无法被修改。我们在配置文件的值当然不允许被修改了。

以前用全局变量声明public static final String appkey2 = "yourAppKey";,为了方便管理,于是在配置文件application.properties中定义

 // 这种写法无法修改设置的参数
        Aliyun aliyunInstance = Aliyun.options()
                .setAppKey("yourAppKey")
                .setAppSecret("yourAppSecret")
                .setBucket("yourBucket")
                .setEndPoint("yourEndPoint")
                .build();
        }

当然,这只是一代码建议,多试试不同的写法就当锻炼代码能力

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在层,通常需要使用到实体类,可以使用Spring的依赖注入功能来注入实体类。一般情况下,我们会在Service层定义一个与实体类对应的DTO(Data Transfer Object)类,用于接收前端传递过来的数据并进行校验,然后再将DTO转换为实体类进行持久化操作。 以下是一个简单的示例,展示了如何在Service层注入实体类: ```java @Service public class OrderService { @Autowired private OrderRepository orderRepository; public Order createOrder(OrderDto orderDto) { Order order = new Order(); BeanUtils.copyProperties(orderDto, order); // 校验订单信息 if (!validateOrder(order)) { throw new IllegalArgumentException("Invalid order information."); } // 检查订单号是否唯一 if (orderRepository.existsByOrderNo(order.getOrderNo())) { throw new IllegalArgumentException("Order number already exists."); } // 保存订单信息 order.setCreateTime(new Date()); order.setStatus(OrderStatus.CREATED); return orderRepository.save(order); } private boolean validateOrder(Order order) { // TODO: 校验订单信息是否合法 return true; } } ``` 在上述示例,我们注入了一个名为`orderRepository`的实体类,用于进行订单的持久化操作。在`createOrder()`方法,我们通过DTO类`OrderDto`接收前端传递过来的订单信息,然后使用`BeanUtils.copyProperties()`方法将DTO转换为实体类`Order`进行持久化操作。 此外,为了更好地区分实体类和DTO类,我们通常会将实体类放在`domain`或`entity`包,DTO类放在`dto`包实体类与DTO类的属性通常是一一对应的,但是为了安全考虑,在DTO类可以添加一些校验注解,如`@NotBlank`、`@NotNull`、`@Min`、`@Max`等,用于对前端传递的数据进行校验。 希望这些信息能够对您有所帮助,如果您有任何问题或需要更详细的信息,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值