Huawei Cloud Yaoyun Server Lインスタンスの評価|カナルキャッシュ&SpringBootプロジェクトの適用事例とソースコードに基づく自動更新プロセス

ここに画像の説明を挿入します

序文

最近、Huawei Cloud Yaoyun Server L インスタンスがリリースされ、私も構築して遊んでみましたが、その過程でさまざまな問題に遭遇し、問題を解決する過程での運用保守について多くのことを学びました。

前回のブログでcanalのインストールと設定について紹介しましたので、ぜひ参考にしてください。

このブログでは、canal プロジェクトのアプリケーション ケースを示し、canal に基づくデータベースとキャッシュの同期プロセスを詳しく説明し、コア ディアマンテのソース コードを提供します。

ここに画像の説明を挿入します

その他の関連する Huawei Cloud Yaoyun Server L インスタンスの評価記事のリストは次のとおりです。

ここに画像の説明を挿入します

導き出す


1. canal に基づいたデータベースとキャッシュの同期プロセスを紹介します;
2. core diamante のソース コードを提供します。

カナルキャッシュに基づく同期更新

全体的なプロセス

Spring プロジェクトを開始すると、同期的にキャッシュの自動更新が開始され、データベースの該当テーブルデータが変更されると、canal がそれをリッスンしてキャッシュ Redis 内の対応するデータを更新します。

ここに画像の説明を挿入します

キャッシュから取得されるデータは何ですか? ——頻繁に更新されないデータ: 会社の部門、倉庫など。

プロジェクトが開始されると、データベースの変更を監視するために使用される canal が開始されました。

ビジネス ロジック: フロントエンドから関連データを要求 –> Redis に要求

(1) redis に存在する場合はフロントエンドに返されます。

(2) Redis にない場合は、データベースからクエリを実行し、redis に保存してフロントエンドに返します。

(3) データベースが更新されると、canal は変更を監視し、それを Redis に同期的に更新して、キャッシュとデータベースの一貫性を確保します。

ここに画像の説明を挿入します

関連するコードとプロセス

1.運河水路の構成

ここに画像の説明を挿入します

キャッシュは自動的に更新され、構成ファイル内の IP とポート番号が読み取られます。

ここに画像の説明を挿入します

自動キャッシュ更新を有効にし、構成ファイルから構成を読み取るかどうか。

ここに画像の説明を挿入します

2. フロントエンドクエリのビジネスコード

ここに画像の説明を挿入します

データベースのデータが更新されていない場合にキャッシュ内のデータを取得する

ここに画像の説明を挿入します

3. データベースデータの更新

データベース内のデータが更新され、canal がリッスンして、対応するテーブルがキャッシュされ、対応するフィールドが変更されたことが判明した場合、キャッシュは自動的に更新されます。

ここに画像の説明を挿入します

キャッシュ自動同期更新

ここに画像の説明を挿入します

Redisに保存されている最新のデータ

ここに画像の説明を挿入します

4. キャッシュ更新フロントエンド表示

キャッシュが更新された後、フロントエンドは最新のデータを取得するために再度クエリを実行します。

ここに画像の説明を挿入します

コアコードのソースコード

1. yml と構成クラスを構成する

設定ymlファイル

server:
  port: 10050

## 是否启用安全框架 true为开启,false为关闭
security:
  isOpen: true

## 是否开启canal管道,true为开启,false为关闭
canal:
  isOpen: true

# canal的相关配置
canalConfig:
  host: 124.70.138.34
  port: 11111

ここに画像の説明を挿入します

Redis に Java オブジェクトを格納するための構成クラス

package com.tianju.fresh.config.redis;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisSerializeConfig {
    
    
    @Bean
    public RedisTemplate redisTemplateInit(RedisConnectionFactory redisConnectionFactory) {
    
    

        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        /**
         *
         * 设置Hash类型存储时,对象序列化报错解决
         */
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }
}

2.canalはコードを自動的に更新します

Canal 自動更新コード。Canal パイプラインを使用して MySQL データの変更を監視し、Redis キャッシュを自動的に更新します。

package com.tianju.fresh.config.redis;


import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.common.utils.AddressUtils;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import com.baomidou.mybatisplus.annotation.TableField;
import com.tianju.fresh.entity.common.GoodsTypeVo;
import com.tianju.fresh.entity.common.WarehouseVo;
import com.tianju.fresh.entity.goods.GoodsType;
import com.tianju.fresh.mapper.goods.GoodsTypeMapper;
import com.tianju.fresh.mapper.warehouse.StorehouseMapper;
import com.tianju.fresh.service.common.CommonStaticMethod;
import com.tianju.fresh.util.Constance;
import com.tianju.fresh.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 用canal管道监听MySQL数据变化,自动更新redis缓存
 */
@Slf4j
@Component
public class AutoUpdateRedis {
    
    

    @Value("${canalConfig.host}")
    private String host;

    @Value("${canalConfig.port}")
    private Integer port;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private GoodsTypeMapper typeMapper;

    @Autowired
    private StorehouseMapper storehouseMapper;

    @Autowired
    private RedisUtil redisUtil;


    public void run() {
    
    
        // 创建链接
        final InetSocketAddress HOST = new InetSocketAddress(host,port);
//        final InetSocketAddress HOST = new InetSocketAddress("192.168.111.130",11111);
        CanalConnector connector = CanalConnectors.newSingleConnector(HOST, "example", "", "");
        int batchSize = 1000;
        int emptyCount = 0;
        try {
    
    
            connector.connect();
            connector.subscribe(".*\\..*");
            connector.rollback();
            int totalEmptyCount = 120;
//            while (emptyCount < totalEmptyCount) {
    
    
            while (true) {
    
    
                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据
                long batchId = message.getId();
                int size = message.getEntries().size();
                if (batchId == -1 || size == 0) {
    
    
                    emptyCount++;
                    if(emptyCount % 100==0 || emptyCount==1){
    
    
                        System.out.println("empty count : " + emptyCount);
                    }
                    try {
    
    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
    
    
                    }
                } else {
    
    
                    emptyCount = 0;
                    // System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);
                    printEntry(message.getEntries());
                }

                connector.ack(batchId); // 提交确认
                // connector.rollback(batchId); // 处理失败, 回滚数据
            }

//            System.out.println("empty too many times, exit");
        } finally {
    
    
            connector.disconnect();
        }
    }

    private void printEntry(List<Entry> entrys) {
    
    
        for (Entry entry : entrys) {
    
    
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
    
    
                continue;
            }

            RowChange rowChage = null;
            try {
    
    
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
    
    
                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
                        e);
            }

            EventType eventType = rowChage.getEventType();
            System.out.println(String.format("================&gt; binlog[%s:%s] , name[%s,%s] , eventType : %s",
                    entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
                    entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
                    eventType));

            String tableName = entry.getHeader().getTableName();
            if (Constance.LISTEN_TAB_NAMES.contains(tableName)){
    
    
                for (RowData rowData : rowChage.getRowDatasList()) {
    
    
                    if (eventType == EventType.DELETE){
    
    
                        // 删除之前
                        log.debug("-------删除之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------删除之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
//                        changeAfter(rowData.getAfterColumnsList(),tableName);

                    }else if (eventType == EventType.INSERT){
    
    
                        // 插入之前
                        log.debug("-------插入之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------插入之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
//                        changeAfter(rowData.getAfterColumnsList(),tableName);

                    }else {
    
    
                        // 修改之前
                        log.debug("-------修改之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------修改之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
                        changeAfter(rowData.getAfterColumnsList(),tableName);
                    }
                }
            }
        }
    }


    /**
     * 数据库更新之前
     * @param columns
     */

    private  void changeBefore(List<Column> columns) {
    
    
        for (Column column : columns) {
    
    
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());
        }
    }

    private  void changeAfter(List<Column> columns, String tableName) {
    
    
        for (Column column : columns) {
    
    
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());

            // 如果是商品类别表变化

            if ("name".equals(column.getName()) && Constance.GOODS_TYPE_TAB_NAME.equals(tableName)){
    
     // 默认是名称那一列变化才更新缓存
                // 先删除key,再设置好新的key
                Map tabNameToRedisKey = Constance.getTabNameToRedisKey();
                String redisKey = (String) tabNameToRedisKey.get(tableName);
                redisTemplate.delete(redisKey);
                // TODO:设置新的key
                List<GoodsTypeVo> list = CommonStaticMethod.getGoodsTypeVos(typeMapper);
                redisUtil.saveObjectToRedis(Constance.GOODS_TYPE_REDIS_KEY, list);
                break;
            }

            // 如果是仓库那张表变化 storehouse
            if ("name".equals(column.getName()) && Constance.STOREHOUSE_TAB_NAME.equals(tableName)){
    
     // 默认是名称那一列变化才更新缓存
                // 先删除key,再设置好新的key
                Map tabNameToRedisKey = Constance.getTabNameToRedisKey();
                String redisKey = (String) tabNameToRedisKey.get(tableName);
                redisTemplate.delete(redisKey);

                // 设置新的key,存到redis里面
                List<WarehouseVo> list = CommonStaticMethod.getStorehouseVos(storehouseMapper);

                redisUtil.saveObjectToRedis(Constance.STOREHOUSE_REDIS_KEY,list);

                break;
            }
        }
    }
}

ここに画像の説明を挿入します

Redisツールクラス

package com.tianju.fresh.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisUtil {
    
    

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    public void  saveObjectToRedis(String key,Object json){
    
    
        redisTemplate.opsForValue().set(key,json);
    }

    /**
     * 从redis里面获取json对象,如果没有,返回null
     * @param key
     * @return
     */
    public Object getJsonFromRedis(String key){
    
    
        return redisTemplate.opsForValue().get(key);
    }

}

データベーステーブルと列名を監視するための定数クラス

package com.tianju.fresh.util;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 专门放各种常量
 */
public interface Constance {
    
    
    // 设置哪些数据库表需要监听,比如单位unit,仓库warehouse,商品类型等
    List<String> LISTEN_TAB_NAMES = Arrays.asList("goods_type","unit_commodity","warehouse_center","warehouse_tab");

    String GOODS_TYPE_TAB_NAME = "goods_type";
    String GOODS_TYPE_REDIS_KEY = "goodsTypeVo";
    String UNIT_TAB_NAME = "unit_commodity";
    String UNIT_REDIS_KEY = "unitVo";
    String WAREHOUSE_TAB_NAME = "warehouse_center";
    String WAREHOUSE_REDIS_KEY = "warehouseCenterVo";
    String STOREHOUSE_TAB_NAME = "warehouse_tab";
    String STOREHOUSE_REDIS_KEY = "storehouseVo";

    static Map getTabNameToRedisKey(){
    
    
        Map<String,String> map = new HashMap<>();
        map.put(GOODS_TYPE_TAB_NAME,"goodsTypeVo");
        map.put("unit_commodity","unitVo");
        map.put("warehouse_center","warehouseCenterVo");
        map.put("warehouse_tab","storehouseVo");
        return map;
    }
}

3. ビジネス層サービスコードをクエリする

ここに画像の説明を挿入します

    @Override
    public List<WarehouseVo> findStorehouse() {
    
    
//        List<Storehouse> storehouses = storehouseMapper.selectList(null);
//        List<WarehouseVo> list = new ArrayList<>(storehouses.size());
//        storehouses.forEach(s->{
    
    
//            list.add(new WarehouseVo(s.getId()+"", s.getName()));
//        });

        // 是否有小仓库的redis的key
        Boolean hasKey = redisTemplate.hasKey(Constance.STOREHOUSE_REDIS_KEY);
        if (hasKey){
    
     // 如果有,走缓存
            List<WarehouseVo> list = (List<WarehouseVo>) redisTemplate.opsForValue()
                    .get(Constance.STOREHOUSE_REDIS_KEY);
            log.debug("get storehouseVo from redis: "+list);
            return list;
        }
        // 如果没有从数据库查询,存到redis里面
        List<WarehouseVo> list = CommonStaticMethod.getStorehouseVos(storehouseMapper);
        log.debug("get storehouseVo from mysql: "+list);
        redisUtil.saveObjectToRedis(Constance.STOREHOUSE_REDIS_KEY, list);
        return list;
    }

4. メインスタートアップクラス

メインの起動クラスは、CommandLineRunner メソッドを実装し、運河チャネルを開始し、データベース内の変更を監視し、キャッシュ同期更新を実装します。

package com.woniu.fresh;


import com.woniu.fresh.config.redis.AutoUpdateRedis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;


@SpringBootApplication
@Slf4j
@EnableAspectJAutoProxy // 让动态代理生效
@EnableScheduling // 让定时任务生效
public class FreshApp implements CommandLineRunner {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(FreshApp.class);
    }

    @Autowired
    private AutoUpdateRedis autoUpdateRedis;

    @Value("${canal.isOpen}")
    private Boolean isCanal;

    @Override
    public void run(String... args) throws Exception {
    
    

        if (isCanal){
    
    
            log.debug(">>>>>启动缓存自动更新");
            autoUpdateRedis.run();
        }
    }
}

5. フロントエンドの Vue コード

<template>
    <div>
        <el-row>
            <el-col :span="24">
                <el-form :inline="true" label-width="80px">
                    <el-form-item label="领料单号">
                        <el-input v-model="findGoodsParams.shoppingNo"></el-input>
                    </el-form-item>

                    <el-form-item label="领料数量≥">
                        <el-input v-model="findGoodsParams.nums"></el-input>
                    </el-form-item>

                    <el-form-item label="原料名称">
                        <el-input v-model="findGoodsParams.rawName"></el-input>
                    </el-form-item>

                    <el-form-item label="领料仓库">
                        <el-select v-model="findGoodsParams.warehouseId" placeholder="请选择">
                            <el-option v-for="item in commondata.storehouse" :key="item.value" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>

                    <el-form-item label="状态">
                        <el-select v-model="findGoodsParams.status" placeholder="请选择">
                            <el-option v-for="item in commondata.status" :key="item.value" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>

                    <el-form-item>
                        <el-button type="primary" @click="findGoods">查询</el-button>
                        <el-button type="success" @click="reFindGoods">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>

        <el-row>
            <el-col :span="24">
                <el-button type="success" @click="addGoodsBtn">新增</el-button>
                <el-button type="warning" icon="el-icon-edit" @click="batchDelete">批量审批</el-button>
                <el-button type="primary" icon="el-icon-magic-stick" @click="batchPickDoing">批量领取中</el-button>
                <el-button type="primary" icon="el-icon-shopping-cart-full" @click="batchPickDown">批量已领完</el-button>

            </el-col>
        </el-row>

        <el-row>
            <el-col :span="24">
                <el-table :data="tableData" style="width: 100%" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="55">
                    </el-table-column>
                    <el-table-column prop="pickNo" label="领料单号" width="240">
                    </el-table-column>
                    <el-table-column prop="name" label="原材料名" width="100">
                    </el-table-column>
                    <el-table-column prop="nums" label="领料数量" width="80">
                    </el-table-column>
                    <el-table-column prop="unit" label="单位" width="80">
                    </el-table-column>
                    <el-table-column prop="warehouse" label="领料仓库" width="180">
                    </el-table-column>
                    <el-table-column prop="emp" label="仓管员" width="150">
                    </el-table-column>

                    <el-table-column prop="status" label="状态" width="80">

                        <template slot-scope="scope">
                            <span v-if="scope.row.status == '0'" style="color: red;">未审批</span>
                            <span v-if="scope.row.status == '1'" style="color: rgb(9, 209, 109);">已审批</span>
                            <span v-if="scope.row.status == '2'" style="color: rgb(44, 39, 205);">已领取</span>
                            <span v-if="scope.row.status == '3'" style="color: rgb(173, 16, 157);">已领完</span>
                            <!-- {
    
    {
    
     scope.row.status == 1 ? '已上架' : '下架' }} -->
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <template slot-scope="scope">
                            <el-button type="primary" icon="el-icon-edit" circle
                                @click="loadBtn(scope.row.id)">审批</el-button>
                        </template>
                    </el-table-column>
                </el-table>

            </el-col>
        </el-row>
        <el-row>
            <el-col :span="24">
                <div class="block">
                    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
                        :current-page.sync="currentPage" :page-sizes="[3, 5, 10]" :page-size="3"
                        layout="total,sizes, prev, pager, next" :total=total>
                    </el-pagination>
                </div>
            </el-col>
        </el-row>


        <!-- 新增原材料入库弹窗 ******* -->
        <el-dialog title="添加原材料单" :visible.sync="b">
            <el-form>
                <el-row>
                    <el-col :span="12">

                        <el-form-item label="原料名称" clearable>
                            <el-select v-model="shoppingNoId" placeholder="请选择"
                                style="width: 355px;margin-right:px;margin-left:px" @change="selectBuyNo">
                                <el-option v-for="item in shoppingIdToNo" :key="item.label" :label="item.label"
                                    :value="item.label">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="数量" :label-width="formLabelWidth">
                            <el-input v-model="goods.nums" autocomplete="off"></el-input>
                        </el-form-item>



                        <el-form-item label="单位" clearable>
                            <el-select v-model="goods.unit" placeholder="请选择商品单位"
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.unit" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="中心仓库" clearable>
                            <el-select v-model="goods.warehouse" placeholder="请选择" disabled
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.warehouse" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="领料仓库" clearable>
                            <el-select v-model="goods.storehouse" placeholder="请选择"
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.storehouse" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>


                    </el-col>
                </el-row>

            </el-form>

            <div slot="footer" class="dialog-footer">
                <el-button @click="b = false">取 消</el-button>
                <el-button type="primary" @click="addGoods()">确 定</el-button>
            </div>
        </el-dialog>



    </div>
</template>

<script>
export default {
    
    
    data() {
    
    
        return {
    
    
            findGoodsParams: {
    
    
                "pickNo": ""
                , "name": ""
                , "nums": ""
                , "storehouseId": ""
                , "status": ""
            },
            // 批量删除的id
            deleteIds: [],


            tableData: [
                {
    
    
                    "id": 1,
                    "pickNo": "PICK2023090818003927",
                    "name": "富士苹果",
                    "nums": "350.00",
                    "unit": "千克",
                    "warehouse": "南京江宁生鲜1号仓库",
                    "storehouseId": 2,
                    "emp": "领料操作员1李四",
                    "status": "0"
                }
            ],

            // 分页相关的参数
            total: 10,
            currentPage: 1,
            pageSize: 3,

            options: [
                {
    
     value: '0', label: '未审批' },
                {
    
     value: '1', label: '审批通过' },
                {
    
     value: '2', label: '已领取' },
                {
    
     value: '3', label: '已领完' },
            ],

            commondata: {
    
    
                "storehouse": [
                    {
    
    
                        "value": 1, "label": "南京中心仓库南京总统府"
                    },],
                "status": [
                    {
    
     "value": 0, "label": "未审批" },
                    {
    
     "value": 1, "label": "审批通过" }]
            },


            // 新增商品弹窗控制变量
            b: false,



            // 新增的入库信息 goods shoppingNoId
            goods: {
    
    
                "name":"富士苹果",
                "nums":"200.56",
                "unit":"1",
                // 中心仓库
                "warehouse":"1", 
                // 目标仓库
                "storehouse":"2"
            },

            formLabelWidth: '100px',

            
            // 新增原材料入库清单
            addRawTab:[{
    
    
                "name": {
    
    
                    "unit": "",
                    "warehouse": {
    
    
                        "1": 1000.20
                    }
                }},
            ],

            // 和上面进行比对
            shoppingNoId:"",

            // 选择采购清单的下拉框
            shoppingIdToNo: [
                    {
    
    "label": "BUY2023091317093927"},],
        }

    },
    methods: {
    
    
        handleSizeChange(val) {
    
    
            console.log(`每页 ${
    
    val} 条`);
            this.pageSize = val
            this.findGoods()
        },
        handleCurrentChange(val) {
    
    
            console.log(`当前页: ${
    
    val}`);
            this.pageNum = val
            this.findGoods()
        },
        findGoods() {
    
    
            let params = {
    
    }
            params.pageNum = this.currentPage
            params.pageSize = this.pageSize
            params.param = this.findGoodsParams
            console.log(params)
            this.$axios.post("/api/warehouse/findPagePickRaw", params)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.tableData = resp.results.list
                        this.total = resp.results.total
                        this.currentPage = resp.results.pageNum
                        this.pageSize = resp.results.pageSize
                    }
                })
        },

        reFindGoods() {
    
    
            let params = {
    
    }

            this.findGoodsParams = {
    
    
                "pickNo": ""
                , "name": ""
                , "nums": ""
                , "storehouseId": ""
                , "status": ""
            },

            params.pageNum = this.currentPage
            params.pageSize = this.pageSize
            params.param = this.findGoodsParams

            console.log(params)
            this.$axios.post("/api/warehouse/findPagePickRaw", params)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.tableData = resp.results.list
                        this.total = resp.results.total
                        this.currentPage = resp.results.pageNum
                        this.pageSize = resp.results.pageSize
                    }
                })
        },

        handleSelectionChange(val) {
    
    
            this.deleteIds = []
            console.log(val);
            val.forEach(e => this.deleteIds.push(e.id))
        },

        // 批量修改领取中
        batchPickDoing() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchDoingPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 批量修改已领完
        batchPickDown() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchDownPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 批量审批通过
        batchDelete() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchPassPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 逐一审批通过
        loadBtn(val) {
    
    
            console.log(val)
            const deleteIds = []
            deleteIds.push(val)
            console.log(deleteIds)
            this.$axios.put("/api/warehouse/batchPassPickMaterial", deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 获取公共数据
        getCommonData() {
    
    
            this.$axios.get("/api/common/pickCommon")
                .then(response => {
    
    
                    let resp = response.data
                    
                    if (resp.resultCode.code == 20000) {
    
    
                        this.commondata = resp.results
                        console.log("#############")
                        console.log(this.commondata)
                    }
                })
        },

        addGoodsBtn() {
    
    
            this.b = true
            this.goods = {
    
    } 
            this.shoppingIdToNo = []
            this.$axios.get('/api/warehouse/findRawNames')
                .then(res => {
    
    
                if (res.data.resultCode.code == 20000) {
    
    
                    this.addRawTab = res.data.results
                    console.log(this.addRawTab)
                    this.addRawTab.forEach(r=>{
    
    
                        this.shoppingIdToNo.push(
                            {
    
    "label": Object.keys(r)[0]}
                        )
                    })
                    console.log(this.shoppingIdToNo)
                }
            })

        },
        // 弹出的新增窗口的添加
        addGoods() {
    
    
            console.log("#############")
            console.log(this.goods)
            this.$axios.post('/api/warehouse/addPickRaw', this.goods)
                .then(res => {
    
    
                    console.log("&&&&&")
                    console.log(res.data)
                    if (res.data.resultCode.code == 20000) {
    
    
                        alert('添加成功')
                        this.findGoods()
                    }else{
    
    
                        alert('添加失败')
                    }
                }),
                this.b = false
        },

        // 绑定下拉框的选择事件
        selectBuyNo(){
    
    
            console.log("change")
            const goodsTemp = this.addRawTab.filter(r=> Object.keys(r)[0] == this.shoppingNoId)[0]
            console.log(goodsTemp)
            const nameTmp = Object.keys(goodsTemp)[0]
            const nextTmp = Object.values(goodsTemp)[0].warehouse
            const keyTmp = Object.keys(nextTmp)[0]
            console.log(nextTmp)
            this.goods={
    
    
                name:nameTmp,
                nums:nextTmp[keyTmp],
                unit:Object.values(goodsTemp)[0].unit+"",
                warehouse:Object.keys(nextTmp)[0]
            }
            console.log(this.goods)
        },
    },
    created() {
    
    
        this.findGoods()
        this.getCommonData()
    }

}

</script>

要約する

1. canal に基づいたデータベースとキャッシュの同期プロセスを紹介します;
2. core diamante のソース コードを提供します。

おすすめ

転載: blog.csdn.net/Pireley/article/details/133548639