GithubHelp home page GithubHelp logo

wxiaoqi / ace-merge Goto Github PK

View Code? Open in Web Editor NEW
37.0 5.0 29.0 72 KB

Spring Cloud 跨服务数据聚合小框架,解决服务拆分的静态数据聚合之痛。举个栗子:两个服务,A服务的某张表用到了B服务的某张表的值,我们在对A服务那张表查询的时候,把B服务某张表的值聚合在A服务的那次查询过程中。

License: Apache License 2.0

Java 100.00%

ace-merge's Introduction

AG-Merge

Spring Cloud 跨服务数据聚合框架

解决问题

解决Spring Cloud服务拆分后分页数据的属性或单个对象的属性拆分之痛, 支持对静态数据属性(数据字典)、动态主键数据进行自动注入和转化, 其中聚合的静态数据会进行一级混存(guava).

示例

具体示例代码可以看ace-merge-demo模块

|------- ace-eureka  注册中心
|------- ace-data-merge-demo  查询数据,此处聚合示例
|------- ace-data-provider 数据提供者

Maven添加依赖

<dependency>
    <groupId>com.github.wxiaoqi</groupId>
    <artifactId>ace-merge-core</artifactId>
    <version>2.0-SNAPSHOT</version>
</dependency>

启动类加注解

@EnableAceMerge

application.yml配置

# 跨服务数据合并
merge:
  enabled: true
  guavaCacheNumMaxSize: 1000
  guavaCacheRefreshWriteTime: 10 # min
  guavaCacheRefreshThreadPoolSize: 10
  aop: # 启动注解的方式,自动聚合
    enabled: true

代码示例(@MergeField标志对象的数据需要聚合)

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
public @interface MergeField {
    /**
     * 查询值
     * @return
     */
    String key() default "";

    /**
     * 目标类
     * @return
     */
    Class<? extends Object> feign() default Object.class;

    /**
     * 调用方法
     * @return
     */
    String method() default "";

    /**
     * 是否以属性值合并作为查询值
     * @return
     */
    boolean isValueNeedMerge() default false;
}
  • 聚合对象
public class User {
    private String name;
    // 需要聚合的属性
    @MergeField(key="test", feign = IService2.class,method = "writeLog")
    private String sex;
    // 需要聚合的属性
    @MergeField(feign = IService2.class,method = "getCitys",isValueNeedMerge = true)
    private String city;

    public User(String name, String sex, String city) {
        this.name = name;
        this.sex = sex;
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public User(String name) {
        this.name = name;
    }

    public User(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}
  • 聚合数据来源方法(示例为通过FeignClient,也可以是本地的spring bean对象)

特别要求:入参必须为一个String,返回值必须为Map<String,String>. 其中返回值的构成,就是聚合对象属性的key和对应的value.

@FeignClient("test")
public interface IService2 {
    @RequestMapping("car/do")
    public Map<String, String> writeLog(String test);

    @RequestMapping("car/city")
    public Map<String, String> getCitys(String ids);
}

对应的远程服务接口

/**
 * @author ace
 * @create 2017/11/20.
 */
@RestController
@RequestMapping("car")
public class Service2Rest {
    private Logger logger = LoggerFactory.getLogger(Service2Rest.class);

    @RequestMapping("do")
    public Map<String,String> writeLog(String test){
        logger.info("service 2 is writing log!");
        Map<String,String> map = new HashMap<String, String>();
        map.put("man","男");
        map.put("woman","女");
        return map;
    }

    @RequestMapping("city")
    public Map<String,String> getCity(String ids){
        logger.info("service 2 is writing log!"+ids);
        Map<String,String> map = new HashMap<String, String>();
        map.put("1","广州");
        map.put("2","武汉");
        return map;
    }
}
  • 聚合对象的Biz类(下面的方式是采用aop扫描注解的方式)
@Service
@Slf4j
public class UserBiz {
    @Autowired
    private MergeCore mergeCore;
    /**
     *     aop注解的聚合方式
     *     其中聚合的方法返回值必须为list,
     *     如果为复杂对象,则需要自定义自己的聚合解析器(实现接口IMergeResultParser)
     */
    @MergeResult(resultParser = TestMergeResultParser.class)
    public List<User> getAopUser() {
        ArrayList<User> users = new ArrayList<User>();
        for (int i = 1000; i > 0; i--) {
            users.add(new User("zhangsan" + i, "man", "1"));
            users.add(new User("lisi" + i, "woman", "2"));
            users.add(new User("wangwu" + i, "unkonwn", "2"));
        }
        return users;
    }

    /**
     * 手动聚合方式
     * @return
     */
    public List<User> getUser(){
        ArrayList<User> users = new ArrayList<User>();
        for (int i = 1000; i > 0; i--) {
            users.add(new User("zhangsan" + i, "man", "1"));
            users.add(new User("lisi" + i, "woman", "2"));
            users.add(new User("wangwu" + i, "unkonwn", "2"));
        }
        try {
            // list 聚合
            mergeCore.mergeResult(User.class,users);
            // 单个对象聚合
//            mergeCore.mergeOne(User.class,users.get(0));
        } catch (Exception e) {
            log.error("数据聚合失败",e);
        }finally {
            return users;
        }
    }
}

ace-merge's People

Contributors

wxiaoqi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ace-merge's Issues

数据中要合并的值全为空,报StringIndexOutOfBoundsException异常

result.stream().forEach((obj) -> {
field.setAccessible(true);
Object o = null;

                    try {
                        o = field.get(obj);
                        if (o != null && !ids.contains(o)) {
                            ids.add(o.toString());
                            sb.append(o.toString()).append(",");
                        }

                    } catch (IllegalAccessException var6) {
                        log.error("数据属性加工失败:" + field, var6);
                        throw new RuntimeException("数据属性加工失败:" + field, var6);
                    }
                });
                args = sb.substring(0, sb.length() - 1);

如果sb为空,报如下异常StringIndexOutOfBoundsException: String index out of range: -1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.