1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/fast-product-fast-dao

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Java 极·简ORM框架

Github: https://github.com/kaixinzyw/fast-dao

Gitee: https://gitee.com/fast-product/fast-dao

Автор: Чжан Явэй

Электронная почта: 398850094@qq.com


  • Сводит к минимуму операции SQL
  • Поддерживает цепную синтаксическую операцию
  • Полностью автоматическое сопоставление объектов
  • Поддержка многотабличных запросов
  • Поддержка распределенного кэширования и кэширования в памяти
  • Поддержка пользовательских SQL-запросов
  • Поддержка логического удаления
  • Поддержка аспектов
  • Переключение источника данных
  • Поддержка ручного управления транзакциями

Пример

User user = UserFastDao.create().dao().insert(user); // вставка, после успешного добавления основной ключ будет установлен в объекте
Integer delCount = UserFastDao.create().dao().delete(); // удаление, можно выбрать логическое удаление и физическое удаление
Integer updateCount = UserFastDao.create().dao().update(user); // обновление, операция проста, условия богаты
PageInfo<User> page = UserFastDao.create().dao().findPage(1, 10); // поиск, постраничный поиск

Быстрое начало работы

Тестовая таблица

create table user
(
    id          bigint auto_increment comment '主键' primary key,
    type_id     bigint null comment '用户类型',
    user_name   varchar(255) null comment '用户名',
    age         int(10) null comment '年龄',
    create_time datetime null comment '创建时间',
    update_time datetime null comment '更新时间',
    deleted     bit null comment '是否删除'
) comment 'Пользователь';


create table user_log
(
    id          bigint auto_increment comment '主键' primary key,
    user_id     bigint null comment 'ID пользователя',
    log_info    varchar(255) null comment 'Содержание журнала',
    create_time datetime null comment 'Создание времени',
    update_time datetime null comment 'Обновление времени',
    deleted     bit null comment 'Удаление'
) comment 'Журнал пользователей';

create table user_type
(
    id          bigint auto_increment comment '主键' primary key,
    type_name   varchar(255) null comment 'Тип пользователя',
    create_time datetime null comment 'Время создания',
    update_time datetime null comment 'Время обновления',
    deleted     bit null comment 'Удаление'
) comment 'Типы пользователей';

INSERT INTO user
(`id`, `type_id`, `user_name`, `age`, `create_time`, `update_time`, `deleted`)
VALUES (1, 1, 'User1', 1, '2021-09-14 16:46:11', '2021-09-14 16:46:11', false),
       (2, 1, 'User2', 2, '2021-09-14 16:46:11', '2021-09-14 16:46:11', false),
       (3, 2, 'User3', 3, '2021-09-14 16:46:11', '2021-09-14 16:46:11', false);

INSERT INTO user_type
    (`id`, `type_name`, `create_time`, `update_time`, `deleted`)
VALUES (1, 'Type1', '2021-09-14 16:46:11', '2021-09-14 16:46:11', false),
       (2, 'Type2', '2021-09-14 16:46:11', '2021-09-14 16:46:11', false);

INSERT INTO user_log
    (`id`, `user_id`, `log_info`, `create_time`, `update_time`, `deleted`)
VALUES (1, 1, 'Log1', '2021-09-14 16:46:11', '2021-09-14 16:46:11', false),
       (2, 1, 'Log2', '2021-09-14 16:46:11', '2021-09-14 16:46:11', false);

Установка Maven

<dependency>
    <groupId>com.fast-dao</groupId>
    <artifactId>fast-dao</artifactId>
    <version>9.9.4</version>
</dependency>

Создание файлов

public static void main(String[] args) {
    //Соединение с базой данных -- измените на собственное соединение с базой данных
    String mysqlUrl ="jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=utf-8";
    //Имя пользователя базы данных -- измените на свое имя пользователя базы данных
    String userName = "root";
    //Пароль базы данных - измените на свой пароль базы данных
    String password = "kaixinzyw";
    //Драйвер базы данных -- замените на собственный драйвер базы данных
    String drive = "com.mysql.cj.jdbc.Driver";
    //Путь пакета файлов -- замените на путь собственного проекта
    String packagePath = "com.fast.test";
    //Имя таблицы для генерации -- замените на собственные необходимые таблицы
    String[] tableNames = {"user","user_log","user_type"};

    FileCreateConfig config = new FileCreateConfig();
    //Подключение к базе данных
    config.setDBInfo(mysqlUrl,userName,password,drive);
    //Путь к пакету файлов
    config.setBasePackage(packagePath);
    //Выбор создаваемых файлов
    config.setNeedModules(FileCreateConfig.CodeCreateModule.Base);
    //Необходимые имена таблиц
    config.setCreateTables(tableNames);
    //Генерация кода
    TableFileCreateUtils.create(config);
}

Другие настройки

Генерация DTO

//Генерация DTO
config.setNeedModules(FileCreateConfig.CodeCreateModule.DTO);
//Унаследовать ли DTO от POJO
config.setDtoExtendsPOJO(true);

Настройка префикса таблицы

//Использовать ли префикс при генерации таблиц
config.setPrefix(false,false,null);

Использование аннотаций Lombok

//Использовать ли аннотации Lombok, по умолчанию false
config.setUseLombok(true);

Применение аннотаций Swagger2

//Применять ли аннотации Swagger2 к DTO, по умолчанию false
config.setUseDTOSwagger2(true);
//Применять ли аннотации Swagger2 к POJO, по умолчанию false
config.setUsePOJOSwagger2(true);

Конфигурация фреймворка

Среда Spring

В среде Spring не требуется никакой дополнительной конфигурации, фреймворк автоматически распознает информацию о источнике данных Spring.

Не-Spring среда

public static ```
{
    "age": 1,
    "createTime": 1631609171000,
    "id": 1,
    "typeId": 1,
    "typeName": "Type1",
    "updateTime": 1631609171000,
    "userLogList": [
        {
            "createTime": 1631609171000,
            "deleted": false,
            "id": 1,
            "logInfo": "Log1",
            "updateTime": 1631609171000,
            "userId": 1
        },
        {
            "createTime": 1631609171000,
            "deleted": false,
            "id": 2,
            "logInfo": "Log2",
            "updateTime": 1631609171000,
            "userId": 1
        }
    ],
    "userName": "User1",
    "userType": {
        "createTime": 1631609171000,
        "deleted": false,
        "id": 1,
        "typeName": "Type1",
        "updateTime": 1631609171000
    }
}
``` **findCount()**|запрос количества пользователей<br>
`Integer count = UserFastDao.create().dao().findCount()`|  

**Разбиение на страницы**|PageInfo findPage(int pageNum, int pageSize)|разбиение по страницам и сортировка по возрасту<br>
`PageInfo<User> page = UserFastDao.create().age().orderByDesc().findPage(1, 10)`|

**Обновление данных по первичному ключу**, свойства объекта с пустыми значениями не обновляются|Integer updateByPrimaryKey(Pojo pojo)|обновление данных по первичному ключу<br>
`Integer count = UserFastDao.create().dao().updateByPrimaryKey(user)`|

**Обновление данных по первичному ключу**, свойства объекта с пустыми значениями также обновляются|Integer updateByPrimaryKeyOverwrite(Pojo pojo)|обновление данных по первичному ключу<br>
`Integer count = UserFastDao.create().dao().updateByPrimaryKeyOverwrite(user)`|

**Обновление данных**, свойства объекта с пустыми значениями не обновляются|Integer update(Pojo pojo)|обновляются данные для пользователей с именами «Чжан Сан» и «Ли Сы»<br>
`Integer count = UserFastDao.create().userName().in("Чжан Сан","Ли Сы").dao().update(user)`|

**Обновление данных**, свойства объекта с пустыми значениями также обновляются|Integer updateOverwrite(Pojo pojo)|обновляются пользователи младше 30 лет с фамилией «Чжан»<br>
`UserFastDao fastDao = UserFastDao.create();`
`fastDao.age().less(30);`
`fastDao.userName().like("Чжан");`
`Integer count = fastDao.updateOverwrite(user)`|

**Удаление данных по первичному ключу**|Integer deleteByPrimaryKey(параметр)|удаление пользователя с ID=1<br>
`Integer count = UserFastDao.create().deleteByPrimaryKey(1)`|

**Физическое удаление данных при условии**: если активирована функция логического удаления, эта операция изменит метку удаления без фактического удаления данных, если только не отключена защита логического удаления. Конфигурация логического удаления: FastDaoConfig.openLogicDelete("deleted",true); способ отключения защиты логического удаления см. в условиях настройки. Важно! Если настройка не выполнена, будет использоваться физическое удаление|Integer delete()|удаление пользователей старше 80 лет или с пустым значением возраста<br>
`Integer count = UserFastDao.create().age().greater(80).or().isNull().delete()`|

# Функциональное описание
```Создание примера объекта```
```java
UserFastDao fastDao = UserFastDAO.create();

Условия настройки

Объектные условия

В качестве условий запроса используются непустые поля объекта

//Синтаксис
fastDao.equalObject(объект);

Пример

//Настройка условий объекта
User query = new User();
query.setUserName("User1");
//Выполнение запроса
User user = UserFastDAO.create().equalObject(query).dao().findOne();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` = 'User1'
LIMIT 1

Условия равенства

fastDao.имяПоля(параметр);
или
fastDao.имяПоля().valEqual(параметр);

Пример

User user = UserFastDAO.create().userName("User1").dao().findOne();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` = 'Чжан Сан'
LIMIT 1

Условия неравенства

fastDao.имяПоля().notValEqual(параметр);

Пример

User user = UserFastDAO.create().userName().notValEqual("Чжан Сан").dao().findOne();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` != 'Чжан Сан'
LIMIT 1

Условие неточного соответствия

	двухстороннее неточное соответствие
fastDao.имяПоля().like(параметр);
	неточное соответствие слева
fastDao.имяПоля().likeLeft(параметр);
	неточное соответствие справа
fastDao.имяПоля().likeRight(параметр);

Пример

User user = UserFastDAO.create().userName().like("Чжан Сан").dao().findOne();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` LIKE '%Чжан Сан%'
LIMIT 1

Условие точного соответствия

	двухстороннее точное соответствие
fastDao.имяПоля().notLike(параметр);
	точное соответствие слева
fastDao.имяПоля().notLikeLeft(параметр);
	точное соответствие справа
fastDao.имяПоля().notLikeRight(параметр);

Пример

User user = UserFastDAO.create().userName().notLike("Чжан Сан").dao().findOne();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` NOT LIKE '%Чжан Сан%'
LIMIT 1

Условие включения

fastDao.имяПоля().in(параметр1, параметр2);
или
fastDao.имяПоля().in(коллекция);

Пример

List<User> userList = UserFastDAO.create().userName().in("Чжан Сан", "Ли Сы").dao().findAll();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` IN ('Чжан Сан','Ли Сы')

Условие исключения

fastDao.имяПоля().notIn(параметр1, параметр2);
или
fastDao.имяПоля().notIn(коллекция);

Пример

List<User> userList = UserFastDAO.create().userName().notIn("Чжан Сан", "Ли Сы").dao().findAll();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` NOT IN ('Чжан Сан','Ли Сы')

Условие диапазона

fastDao.имяПоля().between(начальное значение, конечное значение);

Пример

List<User> userList = UserFastDAO.create().age().between(2, 5).dao().findAll();

SQL-вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM
``` **user**

WHERE `age` BETWEEN 2 AND 5

范围排除条件

fastDao.字段名().notBetween(起始值,结束值);

示例

List<User> userList = UserFastDAO.create().age().notBetween(2, 5).dao().findAll();

SQL输出

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `age` NOT BETWEEN 2 AND 5

больше условия

fastDao.字段名().greater(параметр);

пример

List<User> userList = UserFastDAO.create().age().greater(2).dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `age` > 2

Больше или равно условию

fastDao.字段名().greaterOrEqual(параметр);

пример

List<User> userList = UserFastDAO.create().age().greaterOrEqual(2).dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `age` >= 2

меньше условия

fastDao.字段名().less(параметр);

пример

List<User> userList = UserFastDAO.create().age().less(5).dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `age` < 5

Меньше или равно условию

fastDao.字段名().lessOrEqual(параметр);

пример

List<User> userList = UserFastDAO.create().age().lessOrEqual(5).dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `age` <= 5

IsNull условие

fastDao.字段名().isNull();

пример

List<User> userList = UserFastDAO.create().typeId().isNull().dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `type_id` IS NULL

NotNull условие

fastDao.字段名().notNull();

пример

List<User> userList = UserFastDAO.create().typeId().notNull().dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `type_id` IS NOT NULL

Сортировка

//по возрастанию
fastDao.字段名().orderByAsc();
//по убыванию
fastDao.字段名().orderByDesc();

пример

List<User> userList = UserFastDAO.create().createTime().orderByDesc().dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
ORDER BY `create_time` DESC

Фильтрация полей

//при запросе показывать только указанное поле
fastDao.字段名().showField();
//при запросе не показывать указанное поле
fastDao.字段名().hideField();

пример

List<User> userList = UserFastDAO.create().userName().showField().dao().findAll();

SQL вывод

SELECT `user_name` FROM user

Удаление дубликатов полей

fastDao.字段名().distinctField();

пример

List<User> userList = UserFastDAO.create().userName().distinctField().dao().findAll();

SQL вывод

SELECT DISTINCT `user_name` FROM user

Агрегатные функции

//сумма
fastDao.字段名().sumField();
//среднее значение
fastDao.字段名().avgField();
//минимальное значение
fastDao.字段名().minField();
//максимальное значение
fastDao.字段名().maxField();

пример

User user = UserFastDAO.create().age().maxField().dao().findOne();

SQL вывод

SELECT MAX(`age`) `age` FROM user LIMIT 1

Пользовательские условия

//будет добавлено в WHERE после соединения с пользовательским SQL-запросом. Если есть заполнитель параметра, используйте ${параметр} для объявления. Передайте параметры в MAP-коллекцию put (имя параметра, значение параметра)
fastDao.andSql(SQL-запрос, параметр) //соединяем AND
fastDao.orSql(SQL-запрос, параметр) //соединяем OR
fastDao.sql(SQL-запрос, параметр) //нужно самостоятельно соединить условия

пример

Map<String,Object> paramMap = new HashMap<>();
paramMap.put("age",20);
List<User> userList = UserFastDAO.create().userName().likeRight("张").andSql("age > ${age}", paramMap).dao().findAll();

SQL вывод

SELECT `id`,`type_id`,`user_name`,`age`,`create_time`,`update_time`,`deleted`
FROM user
WHERE `user_name` LIKE '张%'
AND age > 20

Пользовательское обновление

//(поле = поле + значение) сложение
fastDao.поле.customizeUpdateValue().thisAdd(параметр);
//(поле = поле - значение) вычитание
fastDao.поле.customizeUpdateValue().thisSbu(параметр);
//(поле = поле * значение) умножение
fastDao.поле.customizeUpdateValue().thisMul(параметр);
//(поле = поле / значение) деление
fastDao.поле.customizeUpdateValue().thisDiv(параметр);
``` **fastDao.字段名.customizeUpdateValue().thisDiv(参数);**

// (字段 = поле % значение) операция взятия по модулю, можно использовать SQL-заполнитель, (${параметр}, Map<параметр, данные>)
**fastDao.полеИмя.customizeUpdateValue().thisModulo(параметр);**

// Операция с полем по умолчанию, можно использовать SQL-заполнитель, (${параметр}, Map<параметр, данные>), например: customize("user_age + 1") тогда tableColumnName = user_age + 1
**fastDao.полеИмя.customizeUpdateValue().customize(SQL, параметр);**

Пример:

UserFastDAO.create().typeId(1L).age().customizeUpdateValue().thisAdd(1).dao().update(null);

Вывод SQL:

UPDATE user SET age = age + 1 WHERE type_id = 1;

Закрыть логическую защиту от удаления

// Если включена функция логического удаления, можно отключить логическое удаление с помощью этой настройки
**fastDao.closeLogicDeleteProtect();**

Пример:

List<User> userList = UserFastDAO.create()
    .userName().likeRight("张")
    .age().or().greater(10)
    .dao().findAll();

OR условие

**fastDao.полеИмя().or();**

Пример:

List<User> userList = UserFastDAO.create()
    .userName().likeRight("张")
    .age().or().greater(10)
    .dao().findAll();

Вывод SQL:

SELECT `id`, `type_id`, `user_name`, `age`, `create_time`, `update_time`, `deleted` FROM user WHERE `user_name` LIKE '张%' OR `age` > 10;

Добавить скобки

// AND левая скобка
**fastDao.andLeftBracket();**
// OR левая скобка
**fastDao.orLeftBracket();**
// Правая скобка
**fastDao.rightBracket();**

Пример:

List<User> userList = UserFastDAO.create().typeId().notNull()
        .orLeftBracket()
        .userName().likeRight("张").age().or().greater(10)
        .rightBracket()
        .dao().findAll();

Вывод SQL:

SELECT id, type_id, user_name, age, create_time, update_time, deleted FROM user WHERE type_id IS NOT NULL OR (`user_name` LIKE '张%' OR age > 10);

Пользовательский SQL

Для сложных операций с несколькими таблицами и других сложных SQL-операций можно использовать пользовательский SQL-исполнитель. Фреймворк автоматически выполняет сопоставление объектов и таблиц.

Если есть параметры, которые необходимо использовать, используйте ${имя параметра} для объявления. Передайте параметры в коллекцию MAP, используя put(имя параметра, значение параметра).

FastCustomSqlDao.create(класс, оператор SQL, параметры)

Пример:

String sql = "SELECT * FROM user WHERE user_name LIKE ${userName}";
HashMap<String, Object> params = new HashMap<>();
params.put("userName", "%张亚伟%");
List<User> all = FastCustomSqlDao.create(User.class, sql, params).findAll();

Использование кэша

После включения функции кэширования можно включить кэширование с помощью аннотации Bean.

@FastRedisCache

  1. Кэширование Redis. Когда выполняются операции добавления, обновления или удаления с использованием этого шаблона, данные в кэше Redis будут автоматически обновляться.
  2. Параметры кэширования по умолчанию — это время и тип кэширования, установленные фреймворком.
  3. Необязательные параметры кэширования:
    • FastRedisCache(Long секунд), например, @FastRedisCache (60L) кэширует 60 секунд.
    • FastRedisCache(cacheTime = время, cacheTimeType = TimeUnit), например, @FastRedisCache (cacheTime = 1L, cacheTimeType = TimeUnit.HOURS) кэшируется в течение 1 часа.

@FastStatisCache

  1. Статическое кэширование. Когда объект данных настроен с помощью этой аннотации, данные, полученные из запроса, будут кэшироваться локально.
  2. Когда операции добавления, обновления и удаления выполняются с использованием этого шаблона, статический кэш будет автоматически обновлён.
  3. Параметры кэширования по умолчанию — это время и тип кэширования, установленные фреймворком.
  4. Необязательные параметры кэширования:
    • FastStatisCache(Long секунд), например, @FastStatisCache (60L) кэширует 60 секунд.
    • FastStatisCache(cacheTime = время, cacheTimeType = TimeUnit), например, @FastStatisCache (cacheTime = 1L, cacheTimeType = TimeUnit.HOURS) кэшируется в течение 1 часа.

Переключение источника данных

В любое время во время выполнения можно переключать источник данных. Переключение источника данных влияет только на текущий поток.

Пример:

FastDaoConfig.dataSource(getDataSource()); // Переключаем глобальный источник данных
FastDaoConfig.dataSourceThreadLocal(getDataSource()); // Переключаем источник данных текущего потока

private static DataSource getDataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    return dataSource;
}

Аспект

Аспекты могут использоваться для реализации множества пользовательских функций, таких как разделение чтения и записи, добавление параметров при выполнении CRUD и проверка разрешений.

Реализация интерфейса FastDaoExpander

public class DemoExpander implements FastDaoExpander {

    /**
     * @param param содержит все параметры выполнения DAO
     * @return выполнять ли
     */
    @Override
    public boolean before(FastDaoParam param) {
        System.out.println("Выполнение DAO перед");
        return true;
    }

    /**
     * @param param содержит все параметры выполнения DAO
     */
    @Override
    public void after(FastDaoParam param) {
        System.out.println("Выполнение DAO после");
    }

    @Override
    public List<ExpanderOccasion> occasion() {
        // Конфигурируем время выполнения аспекта DAO
        List<ExpanderOccasion> list = new ArrayList<>();
        list.add(ExpanderOccasion.SELECT);
        list.add(ExpanderOccasion.UPDATE);
        return list;
    }

}

Настройка реализации аспекта, можно добавить несколько аспектов

FastDaoConfig.addFastDaoExpander(DemoExpander.class);
``` ```
FastTransaction.commit(); //提交
FastTransaction.rollback(); //откат

//Пример
FastTransaction.open(); //открыть транзакцию
FastUserTestFastDao.create().dao().insert(user); //вставить данные
FastTransaction.commit(); //зафиксировать транзакцию

Спасибо за использование, надеюсь, вы сможете предложить ценные идеи, я буду постоянно улучшать и обновлять.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Быстрый фреймворк для разработки ORM. Расширить Свернуть
GPL-3.0
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://gitlife.ru/oschina-mirror/fast-product-fast-dao.git
git@gitlife.ru:oschina-mirror/fast-product-fast-dao.git
oschina-mirror
fast-product-fast-dao
fast-product-fast-dao
master