日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

使用過(guò)Spring Data操作ES的小伙伴應(yīng)該有所了解,它只能實(shí)現(xiàn)一些非常基本的數(shù)據(jù)管理工作,一旦遇到稍微復(fù)雜點(diǎn)的查詢,基本都要依賴ES官方提供的RestHighLevelClient,Spring Data只是在其基礎(chǔ)上進(jìn)行了簡(jiǎn)單的封裝。最近發(fā)現(xiàn)一款更優(yōu)雅的ES ORM框架Easy-Es,使用它能像MyBatis-Plus一樣操作ES,今天就以mall項(xiàng)目中的商品搜索功能為例,來(lái)聊聊它的使用!

Easy-Es簡(jiǎn)介

Easy-Es(簡(jiǎn)稱EE)是一款基于Elasticsearch(簡(jiǎn)稱ES)官方提供的RestHighLevelClient打造的ORM開發(fā)框架,在RestHighLevelClient的基礎(chǔ)上,只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生。EE和Mybatis-Plus(簡(jiǎn)稱MP)的用法非常相似,如果你之前使用過(guò)MP的話,應(yīng)該能很快上手EE。EE的理念是:把簡(jiǎn)單、易用、方便留給用戶,把復(fù)雜留給框架。

EE的主要特性如下:

  • 全自動(dòng)索引托管:開發(fā)者無(wú)需關(guān)心索引的創(chuàng)建、更新及數(shù)據(jù)遷移等繁瑣步驟,框架能自動(dòng)完成。
  • 屏蔽語(yǔ)言差異:開發(fā)者只需要會(huì)MySQL的語(yǔ)法即可使用ES。
  • 代碼量極少:與直接使用官方提供的RestHighLevelClient相比,相同的查詢平均可以節(jié)省3-5倍的代碼量。
  • 零魔法值:字段名稱直接從實(shí)體中獲取,無(wú)需手寫。
  • 零額外學(xué)習(xí)成本: 開發(fā)者只要會(huì)國(guó)內(nèi)最受歡迎的Mybatis-Plus用法,即可無(wú)縫遷移至EE。

MySQL與Easy-Es語(yǔ)法對(duì)比

首先我們來(lái)對(duì)MySQL、Easy-Es和RestHighLevelClient的語(yǔ)法做過(guò)對(duì)比,來(lái)快速學(xué)習(xí)下Easy-Es的語(yǔ)法。

MySQLEasy-Eses-DSL/es JAVA apiandandmustororshould=eqterm!=neboolQueryBuilder.mustNot(queryBuilder)>gtQueryBuilders.rangeQuery('es field').gt()>=ge.rangeQuery('es field').gte()<lt.rangeQuery('es field').lt()<=le.rangeQuery('es field').lte()like '%field%'likeQueryBuilders.wildcardQuery(field,value)not like '%field%'notLikemust not wildcardQuery(field,value)like '%field'likeLeftQueryBuilders.wildcardQuery(field,*value)like 'field%'likeRightQueryBuilders.wildcardQuery(field,value*)betweenbetweenQueryBuilders.rangeQuery('es field').from(xx).to(xx)notBetweennotBetweenmust not QueryBuilders.rangeQuery('es field').from(xx).to(xx)is nullisNullmust not QueryBuilders.existsQuery(field)is notNullisNotNullQueryBuilders.existsQuery(field)ininQueryBuilders.termsQuery(" xx es field", xx)not innotInmust not QueryBuilders.termsQuery(" xx es field", xx)group bygroupByAggregationBuilders.terms()order byorderByfieldSortBuilder.order(ASC/DESC)minminAggregationBuilders.minmaxmaxAggregationBuilders.maxavgavgAggregationBuilders.avgsumsumAggregationBuilders.sumorder by xxx ascorderByAscfieldSortBuilder.order(SortOrder.ASC)order by xxx descorderByDescfieldSortBuilder.order(SortOrder.DESC)-matchmatchQuery-matchPhraseQueryBuilders.matchPhraseQuery-matchPrefixQueryBuilders.matchPhrasePrefixQuery-queryStringQueryQueryBuilders.queryStringQueryselect *matchAllQueryQueryBuilders.matchAllQuery()-highLightHighlightBuilder.Field.........

集成及配置

接下來(lái)把Easy-Es集成到項(xiàng)目中配置下就可以使用了。

  • 首先需要在pom.xml中添加Easy-Es的相關(guān)依賴;
<dependency>
    <groupId>cn.easy-es</groupId>
    <artifactId>easy-es-boot-starter</artifactId>
    <version>1.0.2</version>
</dependency>
  • 由于底層使用了ES官方提供的RestHighLevelClient,這里ES的相關(guān)依賴版本需要統(tǒng)一下,這里使用的ES客戶端版本為7.14.0,ES版本為7.17.3;
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.14.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>
  • 再修改配置文件Application.yml對(duì)Easy-Es進(jìn)行配置。
easy-es:
  # 是否開啟EE自動(dòng)配置
  enable: true
  # ES連接地址+端口
  address: localhost:9200
  # 關(guān)閉自帶banner
  banner: false
  • 添加Easy-Es的Java配置,使用@EsMapperScan配置好Easy-Es的Mapper接口和文檔對(duì)象路徑,如果你使用了MyBatis-Plus的話,需要和它的掃描路徑區(qū)分開來(lái)。
/**
 * EasyEs配置類
 * Created by macro on 2022/9/16.
 */
@Configuration
@EsMapperScan("com.macro.mall.tiny.easyes")
public class EasyEsConfig {
}

使用

Easy-Es集成和配置完成后,就可以開始使用了。這里還是以mall項(xiàng)目的商品搜索功能為例,聊聊Easy-Es的使用,Spring Data的實(shí)現(xiàn)方式可以參考Elasticsearch項(xiàng)目實(shí)戰(zhàn),商品搜索功能設(shè)計(jì)與實(shí)現(xiàn)! 。

注解的使用

下面我們來(lái)學(xué)習(xí)下Easy-Es中注解的使用。

  • 首先我們需要?jiǎng)?chuàng)建文檔對(duì)象EsProduct,然后給類和字段添加上Easy-Es的注解;
/**
 * 搜索商品的信息
 * Created by macro on 2018/6/19.
 */
@Data
@EqualsAndHashCode
@IndexName(value = "pms", shardsNum = 1, replicasNum = 0)
public class EsProduct implements Serializable {
    private static final long serialVersionUID = -1L;
    @IndexId(type = IdType.CUSTOMIZE)
    private Long id;
    @IndexField(fieldType = FieldType.KEYword)
    private String productSn;
    private Long brandId;
    @IndexField(fieldType = FieldType.KEYWORD)
    private String brandName;
    private Long productCategoryId;
    @IndexField(fieldType = FieldType.KEYWORD)
    private String productCategoryName;
    private String pic;
    @IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
    private String name;
    @IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
    private String subTitle;
    @IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
    private String keywords;
    private BigDecimal price;
    private Integer sale;
    private Integer newStatus;
    private Integer recommandStatus;
    private Integer stock;
    private Integer promotionType;
    private Integer sort;
    @IndexField(fieldType = FieldType.NESTED, nestedClass = EsProductAttributeValue.class)
    private List<EsProductAttributeValue> attrValueList;
    @Score
    private Float score;
}
  • EsProduct中的注解具體說(shuō)明如下:

注解名稱用途參數(shù)@IndexName索引名注解value:指定索引名;shardsNum:分片數(shù);replicasNum:副本數(shù)@IndexIdES主鍵注解type:指定注解類型,CUSTOMIZE表示自定義@IndexFieldES字段注解fieldType:字段在索引中的類型;analyzer:索引文檔時(shí)用的分詞器;nestedClass:嵌套類@Score得分注解decimalPlaces:得分保留小數(shù)位,實(shí)體類中被作為ES查詢得分返回的字段使用

  • EsProduct中嵌套類型EsProductAttributeValue的代碼如下。
/**
 * 搜索商品的屬性信息
 * Created by macro on 2018/6/27.
 */
@Data
@EqualsAndHashCode
public class EsProductAttributeValue implements Serializable {
    private static final long serialVersionUID = 1L;
    @IndexField(fieldType = FieldType.LONG)
    private Long id;
    @IndexField(fieldType = FieldType.KEYWORD)
    private Long productAttributeId;
    //屬性值
    @IndexField(fieldType = FieldType.KEYWORD)
    private String value;
    //屬性參數(shù):0->規(guī)格;1->參數(shù)
    @IndexField(fieldType = FieldType.INTEGER)
    private Integer type;
    //屬性名稱
    @IndexField(fieldType=FieldType.KEYWORD)
    private String name;
}

商品信息維護(hù)

下面我們來(lái)實(shí)現(xiàn)幾個(gè)簡(jiǎn)單的商品信息維護(hù)接口,包括商品信息的導(dǎo)入、創(chuàng)建和刪除。

  • 首先我們需要定義一個(gè)Mapper,繼承BaseEsMapper;
/**
 * 商品ES操作類
 * Created by macro on 2018/6/19.
 */
public interface EsProductMapper extends BaseEsMapper<EsProduct> {

}
  • 然后在Service實(shí)現(xiàn)類中直接使用EsProductMapper內(nèi)置方法實(shí)現(xiàn)即可,是不是和MyBatis-Plus的用法一致?
/**
 * 搜索商品管理Service實(shí)現(xiàn)類
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    @Autowired
    private EsProductDao productDao;
    @Autowired
    private EsProductMapper esProductMapper;
    @Override
    public int importAll() {
        List<EsProduct> esProductList = productDao.getAllEsProductList(null);
        return esProductMapper.insertBatch(esProductList);
    }

    @Override
    public void delete(Long id) {
        esProductMapper.deleteById(id);
    }

    @Override
    public EsProduct create(Long id) {
        EsProduct result = null;
        List<EsProduct> esProductList = productDao.getAllEsProductList(id);
        if (esProductList.size() > 0) {
            result = esProductList.get(0);
            esProductMapper.insert(result);
        }
        return result;
    }

    @Override
    public void delete(List<Long> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            esProductMapper.deleteBatchIds(ids);
        }
    }
}

簡(jiǎn)單商品搜索

下面我們來(lái)實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的商品搜索,分頁(yè)搜索商品名稱、副標(biāo)題、關(guān)鍵詞中包含指定關(guān)鍵字的商品。

  • 通過(guò)QueryWrapper來(lái)構(gòu)造查詢條件,然后使用Mapper中的方法來(lái)進(jìn)行查詢,使用過(guò)MyBatis-Plus的小伙伴應(yīng)該很熟悉了;
/**
 * 搜索商品管理Service實(shí)現(xiàn)類
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    @Autowired
    private EsProductMapper esProductMapper;
    @Override
    public PageInfo<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
        LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>();
        if(StrUtil.isEmpty(keyword)){
            wrapper.matchAllQuery();
        }else{
            wrapper.multiMatchQuery(keyword,EsProduct::getName,EsProduct::getSubTitle,EsProduct::getKeywords);
        }
        return esProductMapper.pageQuery(wrapper, pageNum, pageSize);
    }
}
  • 使用Swagger訪問(wèn)接口后,可以在控制臺(tái)輸出查看生成的DSL語(yǔ)句,訪問(wèn)地址:http://localhost:8080/swagger-ui/

 

  • 把DSL語(yǔ)句直接復(fù)制Kibana中即可執(zhí)行查看結(jié)果了,這和我們手寫DSL語(yǔ)句沒(méi)什么兩樣的。

 

綜合商品搜索

下面我們來(lái)實(shí)現(xiàn)一個(gè)復(fù)雜的商品搜索,涉及到過(guò)濾、不同字段匹配權(quán)重不同以及可以進(jìn)行排序。

  • 首先來(lái)說(shuō)需求,按輸入的關(guān)鍵字搜索商品名稱(權(quán)重10)、副標(biāo)題(權(quán)重5)和關(guān)鍵詞(權(quán)重2),可以按品牌和分類進(jìn)行篩選,可以有5種排序方式,默認(rèn)按相關(guān)度進(jìn)行排序,看下接口文檔有助于理解;

 

  • 這個(gè)功能之前使用Spring Data來(lái)實(shí)現(xiàn)非常復(fù)雜,使用Easy-Es來(lái)實(shí)現(xiàn)確實(shí)簡(jiǎn)潔不少,下面是使用Easy-Es的實(shí)現(xiàn)方式;
/**
 * 搜索商品管理Service實(shí)現(xiàn)類
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    @Autowired
    private EsProductMapper esProductMapper;
    @Override
    public PageInfo<EsProduct> search(String keyword, Long brandId, Long productCategoryId, Integer pageNum, Integer pageSize,Integer sort) {
        LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>();
        //過(guò)濾
        if (brandId != null || productCategoryId != null) {
            if (brandId != null) {
                wrapper.eq(EsProduct::getBrandId,brandId);
            }
            if (productCategoryId != null) {
                wrapper.eq(EsProduct::getProductCategoryId,productCategoryId).enableMust2Filter(true);
            }
        }
        //搜索
        if (StrUtil.isEmpty(keyword)) {
            wrapper.matchAllQuery();
        } else {
            wrapper.and(i -> i.match(EsProduct::getName, keyword, 10f)
                    .or().match(EsProduct::getSubTitle, keyword, 5f)
                    .or().match(EsProduct::getKeywords, keyword, 2f));
        }
        //排序
        if(sort==1){
            //按新品從新到舊
            wrapper.orderByDesc(EsProduct::getId);
        }else if(sort==2){
            //按銷量從高到低
            wrapper.orderByDesc(EsProduct::getSale);
        }else if(sort==3){
            //按價(jià)格從低到高
            wrapper.orderByAsc(EsProduct::getPrice);
        }else if(sort==4){
            //按價(jià)格從高到低
            wrapper.orderByDesc(EsProduct::getPrice);
        }else{
            //按相關(guān)度
            wrapper.sortByScore(SortOrder.DESC);
        }
        return esProductMapper.pageQuery(wrapper, pageNum, pageSize);
    }
}
  • 再對(duì)比下之前使用Spring Data的實(shí)現(xiàn)方式,沒(méi)有QueryWrapper來(lái)構(gòu)造條件,還要硬編碼字段名稱,確實(shí)優(yōu)雅了不少!

 

相關(guān)商品推薦

當(dāng)我們查看相關(guān)商品的時(shí)候,一般底部會(huì)有一些商品推薦,這里簡(jiǎn)單來(lái)實(shí)現(xiàn)下。

  • 首先來(lái)說(shuō)下需求,可以根據(jù)指定商品的ID來(lái)查找相關(guān)商品,看下接口文檔有助于理解;

 

  • 這里我們的實(shí)現(xiàn)原理是這樣的:首先根據(jù)ID獲取指定商品信息,然后以指定商品的名稱、品牌和分類來(lái)搜索商品,并且要過(guò)濾掉當(dāng)前商品,調(diào)整搜索條件中的權(quán)重以獲取最好的匹配度;
  • 使用Easy-Es來(lái)實(shí)現(xiàn)依舊是那么簡(jiǎn)潔!
/**
 * 搜索商品管理Service實(shí)現(xiàn)類
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    @Autowired
    private EsProductMapper esProductMapper;
    @Override
    public PageInfo<EsProduct> recommend(Long id, Integer pageNum, Integer pageSize) {
        LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>();
        List<EsProduct> esProductList = productDao.getAllEsProductList(id);
        if (esProductList.size() > 0) {
            EsProduct esProduct = esProductList.get(0);
            String keyword = esProduct.getName();
            Long brandId = esProduct.getBrandId();
            Long productCategoryId = esProduct.getProductCategoryId();
            //用于過(guò)濾掉相同的商品
            wrapper.ne(EsProduct::getId,id);
            //根據(jù)商品標(biāo)題、品牌、分類進(jìn)行搜索
            wrapper.and(i -> i.match(EsProduct::getName, keyword, 8f)
                    .or().match(EsProduct::getSubTitle, keyword, 2f)
                    .or().match(EsProduct::getKeywords, keyword, 2f)
                    .or().match(EsProduct::getBrandId, brandId, 5f)
                    .or().match(EsProduct::getProductCategoryId, productCategoryId, 3f));
            return esProductMapper.pageQuery(wrapper, pageNum, pageSize);
        }
        return esProductMapper.pageQuery(wrapper, pageNum, pageSize);
    }
}

聚合搜索商品相關(guān)信息

在搜索商品時(shí),經(jīng)常會(huì)有一個(gè)篩選界面來(lái)幫助我們找到想要的商品,這里我們來(lái)簡(jiǎn)單實(shí)現(xiàn)下。

  • 首先來(lái)說(shuō)下需求,可以根據(jù)搜索關(guān)鍵字獲取到與關(guān)鍵字匹配商品相關(guān)的分類、品牌以及屬性,下面這張圖有助于理解;

 

  • 這里我們可以使用ES的聚合來(lái)實(shí)現(xiàn),搜索出相關(guān)商品,聚合出商品的品牌、商品的分類以及商品的屬性,只要出現(xiàn)次數(shù)最多的前十個(gè)即可;
  • 由于Easy-Es目前只用groupBy實(shí)現(xiàn)了簡(jiǎn)單的聚合,對(duì)于我們這種有嵌套對(duì)象的聚合無(wú)法支持,所以需要使用RestHighLevelClient來(lái)實(shí)現(xiàn),如果你對(duì)照之前的Spring Data實(shí)現(xiàn)方式的話,可以發(fā)現(xiàn)用法差不多,看樣子Spring Data只是做了簡(jiǎn)單的封裝而已。
/**
 * 搜索商品管理Service實(shí)現(xiàn)類
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    @Autowired
    private EsProductMapper esProductMapper;
    @Override
    public EsProductRelatedInfo searchRelatedInfo(String keyword) {
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("pms_*");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //搜索條件
        if (StrUtil.isEmpty(keyword)) {
            builder.query(QueryBuilders.matchAllQuery());
        } else {
            builder.query(QueryBuilders.multiMatchQuery(keyword, "name", "subTitle", "keywords"));
        }
        //聚合搜索品牌名稱
        builder.aggregation(AggregationBuilders.terms("brandNames").field("brandName"));
        //集合搜索分類名稱
        builder.aggregation(AggregationBuilders.terms("productCategoryNames").field("productCategoryName"));
        //聚合搜索商品屬性,去除type=1的屬性
        AbstractAggregationBuilder<NestedAggregationBuilder> aggregationBuilder = AggregationBuilders.nested("allAttrValues", "attrValueList")
                .subAggregation(AggregationBuilders.filter("productAttrs", QueryBuilders.termQuery("attrValueList.type", 1))
                        .subAggregation(AggregationBuilders.terms("attrIds")
                                .field("attrValueList.productAttributeId")
                                .subAggregation(AggregationBuilders.terms("attrValues")
                                        .field("attrValueList.value"))
                                .subAggregation(AggregationBuilders.terms("attrNames")
                                        .field("attrValueList.name"))));
        builder.aggregation(aggregationBuilder);
        searchRequest.source(builder);
        try {
            SearchResponse searchResponse = esProductMapper.search(searchRequest, RequestOptions.DEFAULT);
            return convertProductRelatedInfo(searchResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 將返回結(jié)果轉(zhuǎn)換為對(duì)象
     */
    private EsProductRelatedInfo convertProductRelatedInfo(SearchResponse response) {
        EsProductRelatedInfo productRelatedInfo = new EsProductRelatedInfo();
        Map<String, Aggregation> aggregationMap = response.getAggregations().asMap();
        //設(shè)置品牌
        Aggregation brandNames = aggregationMap.get("brandNames");
        List<String> brandNameList = new ArrayList<>();
        for(int i = 0; i<((Terms) brandNames).getBuckets().size(); i++){
            brandNameList.add(((Terms) brandNames).getBuckets().get(i).getKeyAsString());
        }
        productRelatedInfo.setBrandNames(brandNameList);
        //設(shè)置分類
        Aggregation productCategoryNames = aggregationMap.get("productCategoryNames");
        List<String> productCategoryNameList = new ArrayList<>();
        for(int i=0;i<((Terms) productCategoryNames).getBuckets().size();i++){
            productCategoryNameList.add(((Terms) productCategoryNames).getBuckets().get(i).getKeyAsString());
        }
        productRelatedInfo.setProductCategoryNames(productCategoryNameList);
        //設(shè)置參數(shù)
        Aggregation productAttrs = aggregationMap.get("allAttrValues");
        List<? extends Terms.Bucket> attrIds = ((ParsedStringTerms) ((ParsedFilter) ((ParsedNested) productAttrs).getAggregations().get("productAttrs")).getAggregations().get("attrIds")).getBuckets();
        List<EsProductRelatedInfo.ProductAttr> attrList = new ArrayList<>();
        for (Terms.Bucket attrId : attrIds) {
            EsProductRelatedInfo.ProductAttr attr = new EsProductRelatedInfo.ProductAttr();
            attr.setAttrId(Long.parseLong((String) attrId.getKey()));
            List<String> attrValueList = new ArrayList<>();
            List<? extends Terms.Bucket> attrValues = ((ParsedStringTerms) attrId.getAggregations().get("attrValues")).getBuckets();
            List<? extends Terms.Bucket> attrNames = ((ParsedStringTerms) attrId.getAggregations().get("attrNames")).getBuckets();
            for (Terms.Bucket attrValue : attrValues) {
                attrValueList.add(attrValue.getKeyAsString());
            }
            attr.setAttrValues(attrValueList);
            if(!CollectionUtils.isEmpty(attrNames)){
                String attrName = attrNames.get(0).getKeyAsString();
                attr.setAttrName(attrName);
            }
            attrList.add(attr);
        }
        productRelatedInfo.setProductAttrs(attrList);
        return productRelatedInfo;
    }
}

總結(jié)

今天將之前的使用Spring Data的商品搜索案例使用Easy-Es改寫了一下,確實(shí)使用Easy-Es更簡(jiǎn)單,但是對(duì)于復(fù)雜的聚合搜索功能,兩者都需要使用原生的RestHighLevelClient用法來(lái)實(shí)現(xiàn)。使用Easy-Es來(lái)操作ES確實(shí)足夠優(yōu)雅,它類似MyBatis-Plus的用法能大大降低我們的學(xué)習(xí)成本,快速完成開發(fā)工作!

參考資料

官方文檔:https://www.easy-es.cn/

項(xiàng)目源碼地址

https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-easyes

分享到:
標(biāo)簽:MyBatis
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定