前段时间,领导分配一个统计销售区域汇总的数据,解决方案使用到了反射获取注解,通过注解获取属性或者设置字段属性。

问题描述

查询公司列表,分别是公司id、区域id、区域名称:

公司id 区域id 区域名称
1 1 华南
2 2 华北
3 2 华北
4 3 华东
5 3 华东

创建公司类Company

public class Company {

    public Company(Integer id,  Integer areaId, String areaName) {
        this.id = id;
        this.areaId = areaId;
        this.areaName = areaName;
    }

    /**
     * 公司id
     */
    private Integer id;

    /**
     * 区域id
     */
    private Integer areaId;

    /**
     * 区域名称
     */
    private String areaName;
     
    // 省略get/set方法 

}

最终解决

要求汇总各个区域公司数量,得到如下汇总:

区域id 区域名称 公司总数
1 华南 1
2 华北 2
3 华东 2

最终区域实体AreaStatistic:

public class AreaStatistic {

    @ColumnProperty("华东大区")
    private Integer eastChina = 0;

    @ColumnProperty("华东id")
    private Integer eastChinaId;

    @ColumnProperty("华南大区")
    private Integer southChina = 0;

    @ColumnProperty("华南id")
    private Integer southChinaId;

    @ColumnProperty("华北大区")
    private Integer northChina = 0;

    @ColumnProperty("华北id")
    private Integer northChinaId;

    @Override
    public String toString() {
        return "AreaStatistic{\n"  
                "华东Id="   eastChinaId  
                ",华东="   eastChina  
                ", \n华南Id="   southChinaId  
                ", 华南="   southChina  
                ", \n华北Id="   northChinaId  
                ", 华北="   northChina  
                '}';
    }
    // 省略get/set方法
}

if/else 普通解法

AreaStatistic areaStatistic = new AreaStatistic();
for (Company company:companyList) {
    String areaName = company.getAreaName();
    if ("华南".equals(areaName)) {
        areaStatistic.setSouthChina(areaStatistic.getSouthChina() 1);
        areaStatistic.setSouthChinaId(company.getAreaId());
    } else if ("华北".equals(areaName)) {
        areaStatistic.setNorthChina(areaStatistic.getNorthChina() 1);
        areaStatistic.setNorthChinaId(company.getAreaId());
    } else if ("华东".equals(areaName)) {
        areaStatistic.setEastChina(areaStatistic.getEastChina() 1);
        areaStatistic.setEastChinaId(company.getAreaId());
    }
}

输出:

华东Id=3,华东=2, 
华南Id=1, 华南=1, 
华北Id=2, 华北=2

这种做法的缺点:

  • 要写大量的条件判断语句,非常的繁琐。
  • 增加和减少统计区域,都要修改代码。

针对上面的缺点,使用反射获取注解,通过注解获取属性赋值。

通过反射注解赋值属性

解题思路

1.遍历公司列表,获取到区域id和区域名称。

2.创建自定义注解@ColumnProperty:

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnProperty {

    String value() default "";

}

3.通过反射获取属性,然后遍历字段属性获取注解。

AreaStatistic字段属性上添加注解:

@ColumnProperty("华东大区")
private Integer eastChina = 0;

@ColumnProperty("华东id")
private Integer eastChinaId;

@ColumnProperty("华南大区")
private Integer southChina = 0;

@ColumnProperty("华南id")
private Integer southChinaId;

@ColumnProperty("华北大区")
private Integer northChina = 0;

@ColumnProperty("华北id")
private Integer northChinaId;

4.通过反射获取属性,然后遍历字段属性获取注解。

Class staticClass = areaStatistic.getClass();
Field[] fields = staticClass.getDeclaredFields();
for (Field field : fields) {
    ColumnProperty property = field.getAnnotation(ColumnProperty.class);
    String value = property.value();
}

5.匹配区域名称和字段属性,比如遍历公司区域是华东,就遍历到华东大区注解对应的字段,并赋值或者获取字段值。

if (value != null) {
    int indexOf = value.indexOf("大区");
    if (indexOf != -1 && value.length() == 4) {
        if (areaName.equals(value.substring(0,2))) {
            field.setAccessible(true);
            field.set(areaStatistic,(Integer) field.get(areaStatistic)   1);  
        }
     }
}

6.区域id赋值也是相同的解题思路。

根据上面的思路,有如下代码汇总:

// 遍历公司
for (Company company:companyList) {
  setAreaProperty(areaStatistic2,company.getAreaName(),company.getAreaId());
}

private void setAreaProperty(AreaStatistic areaStatistic,String areaName,Integer areaId) throws IllegalAccessException {
    // 反射获取注解 
    Class staticClass = areaStatistic.getClass();
    Field[] fields = staticClass.getDeclaredFields();
    for (Field field : fields) {
        ColumnProperty property = field.getAnnotation(ColumnProperty.class);
        String value = property.value();
        if (value != null) {
            int indexOf = value.indexOf("大区");
            if (indexOf != -1 && value.length() == 4) {
                // 匹配到注解属性并赋值 
                if (areaName.equals(value.substring(0,2))) {
                    field.setAccessible(true);
                    field.set(areaStatistic,(Integer) field.get(areaStatistic)   1);
                    for (Field idField : fields) {
                        ColumnProperty idProperty = idField.getAnnotation(ColumnProperty.class);
                        String idValue = idProperty.value();
                        if (idValue.equals(areaName "id")) {
                            idField.setAccessible(true);
                            idField.set(areaStatistic,areaId);
                            break;
                        }
                    }
                    break;
                }
            }
        }
    }
}

输出:

华东Id=3,华东=2, 
华南Id=1, 华南=1, 
华北Id=2, 华北=2

汇总某些字段的和

上面算出各个区域的汇总之后,还要算出全部区域的总和,这里还是使用到注解,把属性字段包含大区都累加起来:

AreaStatistic statistic = new AreaStatistic();
statistic.setEastChina(2);
statistic.setNorthChina(3);
statistic.setSouthChina(1);
int sum = 0;
Class staticClass = statistic.getClass();
Field[] fields = staticClass.getDeclaredFields();
for (Field field : fields) {
    ColumnProperty property = field.getAnnotation(ColumnProperty.class);
    String value = property.value();
    if (value.indexOf("大区") != -1) {
        field.setAccessible(true);
        sum  = field.get(statistic) == null ? 0 : (Integer) field.get(statistic);
    }
}
System.out.println(sum);

输出结果:

6

总结

1.自定义注解,通过反射获取注解

2.通过匹配注解值,获取或者复制对应的字段属性。

赋值主要代码为:

field.setAccessible(true);
field.set(Model,value);

源码

package reflect;

import org.junit.Test;
import reflect.annotation.ColumnProperty;
import reflect.model.AreaStatistic;
import reflect.model.Company;

import javax.print.DocFlavor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: laizc
 * @Date: created in 2022-07-21
 * @desc: 通过注解设值
 */
public class SetValueByAnnotation {

    /**
     * 通过属性赋值
     */
    @Test
    public void test() throws IllegalAccessException {
        // 添加数据
        Company company5 = new Company(1,1,"华南");
        Company company1 = new Company(2,2,"华北");
        Company company2 = new Company(3,2,"华北");
        Company company3 = new Company(4,3,"华东");
        Company company4 = new Company(5,3,"华东");
        List<Company> companyList = new ArrayList<>();
        companyList.add(company5);
        companyList.add(company1);
        companyList.add(company2);
        companyList.add(company3);
        companyList.add(company4);

        // 解法1
        AreaStatistic areaStatistic = new AreaStatistic();
        for (Company company:companyList) {
            String areaName = company.getAreaName();
            if ("华南".equals(areaName)) {
                areaStatistic.setSouthChina(areaStatistic.getSouthChina() 1);
                areaStatistic.setSouthChinaId(company.getAreaId());
            } else if ("华北".equals(areaName)) {
                areaStatistic.setNorthChina(areaStatistic.getNorthChina() 1);
                areaStatistic.setNorthChinaId(company.getAreaId());
            } else if ("华东".equals(areaName)) {
                areaStatistic.setEastChina(areaStatistic.getEastChina() 1);
                areaStatistic.setEastChinaId(company.getAreaId());
            }
        }
        System.out.println(areaStatistic);
        // 解法二
        AreaStatistic areaStatistic2 = new AreaStatistic();
        for (Company company:companyList) {
            setAreaProperty(areaStatistic2,company.getAreaName(),company.getAreaId());
        }
        System.out.println(areaStatistic2);

    }

    private void setAreaProperty(AreaStatistic areaStatistic,String areaName,Integer areaId) throws IllegalAccessException {
        Class staticClass = areaStatistic.getClass();
        Field[] fields = staticClass.getDeclaredFields();
        for (Field field : fields) {
            ColumnProperty property = field.getAnnotation(ColumnProperty.class);
            String value = property.value();
            if (value != null) {
                int indexOf = value.indexOf("大区");
                if (indexOf != -1 && value.length() == 4) {
                    if (areaName.equals(value.substring(0,2))) {
                        field.setAccessible(true);
                        field.set(areaStatistic,(Integer) field.get(areaStatistic)   1);
                        for (Field idField : fields) {
                            ColumnProperty idProperty = idField.getAnnotation(ColumnProperty.class);
                            String idValue = idProperty.value();
                            if (idValue.equals(areaName "id")) {
                                idField.setAccessible(true);
                                idField.set(areaStatistic,areaId);
                                break;
                            }
                        }
                        break;
                    }
                }
            }
        }
    }

    /**
     * 根据注解累加字段值
     */
    @Test
    public void accumulate() throws IllegalAccessException {
        AreaStatistic statistic = new AreaStatistic();
        statistic.setEastChina(2);
        statistic.setNorthChina(3);
        statistic.setSouthChina(1);
        int sum = 0;
        Class staticClass = statistic.getClass();
        Field[] fields = staticClass.getDeclaredFields();
        for (Field field : fields) {
            ColumnProperty property = field.getAnnotation(ColumnProperty.class);
            String value = property.value();
            if (value.indexOf("大区") != -1) {
                field.setAccessible(true);
                sum  = field.get(statistic) == null ? 0 : (Integer) field.get(statistic);
            }
        }
        System.out.println(sum);
    }

}

到此这篇关于Java通过反射注解赋值的方法详解的文章就介绍到这了,更多相关Java反射注解赋值内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java通过反射注解赋值的方法详解的更多相关文章

  1. iOS &gt;&gt;块&gt;&gt;更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  2. 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 05 Strings and Characters

    Swift所代表的字符串是字符串类型,进而代表字符类型的值的集合//Swift的String和Character类型提供了一个快速的,兼容Unicode的方式来处理代码中的文本信息。每一个字符值代表一个Unicode字符,我们可以利用for-in循环来遍历字符串中的每一个字符println}//定义一个字符常量letyenSign:Character="$"printlncharacters")//使用"countElements()"函数来获取字符串的长度//8.ConcatenatingStrings

  3. swift 部分运算符

    下面的语句是无效的:ifx=y{println("这一特征可以防止使用相等的运算符(==)时,不小心使用赋值运算符(=)。通过使ifx=y无效,Swift可以帮助你避免代码中出现这些类型的错误")}2.swift中字符串的追加可以使用加法运算leth="hello,"letw="world"println(h+w)//输出hello,world3.范围运算符:闭区间运算符:表示[a,b]例如:forindexin1...5{println//输出1,2,3,4,5}半开区间运算符:表示[a,b)例如for

  4. 二 Swift学习之基本运算符

    二Swift学习之基本运算符————–借鉴老码团队翻译组-Tyrion1.1术语运算符有一元、二元和三元运算符。三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a?这不同于上面提到的自增和自减运算符。无疑空合运算符(??由于userDefinedColorName是一个可选类型,我们可以使用空合运算符去判断其值。

  5. Swift算术运算符

    ==,返回值为true和false逻辑运算符:!,&,&&,|,||(短路或)位运算符:~,^,>>,

  6. Swift语法基础:11 - Swift的运算术语, 赋值运算, 数值运算, 复合赋值

    在Swift当中当然是有与或非这三个逻辑运算符,并且兼容大部分C类运算符,比如“”,“=”,“==”,“=”,“+”,“-“,“*”,“/”,这些等等都支持,但这里有一点要注意一下,赋值符号“=”不返回值,以防止把“==”写成“=”导致程序出错.区别于C,Swfit还提供对浮点数类型进行取余预算“%”,还提供了C没有提供的区间,“0..

  7. Swift可选类型和可选链

    ),允许接受nil控制则是正常类型强制拆封如果我们能确定可选类型一定有值,那么在读取它的时候,可以在可选类型的后面加一个感叹号(!)println对result1中的语句进行了强制拆封前问号,后感叹号,强制拆封隐式拆封为了能够方便的访问可选类型,可以将可选类型后面的问号改成感叹号(!问号表示引用的时候,如果某个环节为nil,她不会出现错误,而是把nil返回给引用者,这种使用问号引用可选类型的方式叫做可选链三、使用问号?

  8. swift开发基础之变量和常量

    swift开发基础之变量和常量今天学习了一下swift语言感觉IOS又迈出了自己的一步代码上面简化了很多,并可以使用playground一个实时预览的效果注意:常量直接用let就行了如果对上面的常量重新赋值会出现错误不需要制定类型变量直接用var就行了可以多次赋值可以制定类型也可以不制定类型感觉很智能化可以多次重新赋值最后是一个变量叠加的问题只需要加一个\然后将数字括起来就行了playground

  9. Swift教程04-定义声明变量重要原则

    和很多其他语言一样,要使用Swift的变量,首先需要声明,定义1.声明变量的原则[最重要]:2.导入对应的框架,使用import3.定义变量示例/*定义变量说明:定义的变量名,即标识符必须以Unicode字符开头,可以使用汉字,$,下划线开头变量与常量:变量使用var,常量使用let定义定义变量形式:varxx:类型=xxx常量类似分号的省略:每行之后的分号可以省略掉,但是如果你在一个一行写多个语

  10. Swift教程07-基本数据类型(三)元组类型tuple

    元组乃何方神圣?

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部