Android追溯码扫码入库demo

一、功能需求

  1. 送货单绑定
    解析送货单二维码,展示药品清单,动态绑定对应追溯码,实时更新扫码进度。
  2. 追溯码解析
    支持扫描追溯码(小码、大码),并通过解析获取药品信息,包括名称、规格、生产批次、有效期等。

二、UI界面

UI界面代码如下,功能需求很简单,先扫订单的二维码,得到订单号和供应商并填入编辑框,同时药品信息出现在列表,然后扫追溯码,出现提示,最后提交入库:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F9F9F9"
    android:padding="16dp"
    tools:context=".MainActivity">

    <!-- 标题 -->
    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:gravity="center"
        android:text="送货单追溯管理"
        android:textColor="#333333"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- 订单输入部分 -->
    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/order_input_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:hint="关联订单"
        app:layout_constraintEnd_toStartOf="@id/order_button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title_text">
        <!--订单文本框-->
        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/order_input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>
    <!--扫码图标-->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/order_button"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_marginStart="5dp"
        android:background="@drawable/btn_s1"
        app:backgroundTint="@null"
        app:layout_constraintBottom_toBottomOf="@+id/order_input_layout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/order_input_layout"
        app:layout_constraintTop_toTopOf="@+id/order_input_layout" />


    <!-- 第二行:供应商和收货人 -->
    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/supplier_input_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:hint="供应商"
        app:layout_constraintEnd_toStartOf="@id/receiver_input_layout"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/order_input_layout">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/supplier_input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/receiver_input_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="收货人"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/supplier_input_layout"
        app:layout_constraintTop_toTopOf="@id/supplier_input_layout">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/receiver_input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <TextView
        android:id="@+id/medicine_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="药品信息"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/supplier_input_layout" />

    <TextView
        android:id="@+id/TraceabilityCode_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="160dp"
        android:text="请扫追溯码"
        android:textSize="15sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="@+id/medicine_label"
        app:layout_constraintStart_toEndOf="@+id/medicine_label"
        app:layout_constraintTop_toTopOf="@+id/medicine_label" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/TraceabilityCode_button"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_marginStart="10dp"
        android:background="@drawable/btn_s1"
        app:backgroundTint="@null"
        app:layout_constraintBottom_toBottomOf="@+id/TraceabilityCode_label"
        app:layout_constraintStart_toEndOf="@+id/TraceabilityCode_label"
        app:layout_constraintTop_toTopOf="@+id/TraceabilityCode_label" />>

    <!-- 表格标题行 -->
    <GridLayout
        android:id="@+id/table_header"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="#E0E0E0"
        android:columnCount="5"
        android:padding="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/medicine_label">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="3"
            android:gravity="center"
            android:text="商品名称"
            android:textColor="#000000"
            android:textSize="16sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="3"
            android:gravity="center"
            android:text="生产厂商"
            android:textColor="#000000"
            android:textSize="16sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="2"
            android:gravity="center"
            android:text="采购量"
            android:textColor="#000000"
            android:textSize="16sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="2"
            android:gravity="center"
            android:text="金额"
            android:textColor="#000000"
            android:textSize="16sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="2"
            android:gravity="center"
            android:text="追溯码"
            android:textColor="#000000"
            android:textSize="16sp" />
    </GridLayout>
    <!-- 表格内容 -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/medicine_recycler_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="8dp"
        android:background="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/table_header"
        tools:listitem="@layout/item_medicine_row" />

    <!-- 页尾部分 -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/submit_button"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:text="提交入库"
        android:textColor="@color/white"
        android:textSize="16sp"
        android:gravity="center"
        android:layout_marginBottom="16dp"
        android:background="@drawable/button_selector"
        app:cornerRadius="25dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    <TextView
        android:id="@+id/tv_result_final"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:textColor="@color/black"
        android:textSize="17sp"
        app:layout_constraintTop_toBottomOf="@+id/submit_button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

三、创建数据库

五个表的逻辑也很简单,首先是drug_info表,这是送货单二维码的查询表,通过扫码送货单二维码,得到一串数字,拿这个数字作为参数访问API接口,得到送货单绑定的订单信息。

然后是medicine_trace表,这个表代表追溯码对应的商品信息。

orderform、orderitem、tracecode表是入库需要save的表,分别代表订单信息,药品列表信息和追溯码信息。

四、开发后端API

基于springboot框架和mybatis-plus进行开发设计,其中控制层也就是核心代码如下:

@RestController
public class test {

    //从druginfo表查询数据
    @Resource
    private DrugInfoService drugInfoService;
    @RequestMapping("/api/{qrCode}")
    public R getDrugInfoByQrCode(@PathVariable String qrCode) {
        List<DrugInfo> data = drugInfoService.getDrugInfoByQrCode(qrCode);
        if (data != null){
            System.out.println("查询被调用");
            return R.OK(data);
        }else {
            return R.FAIL();
        }
    }

    //从medicine_trace表查询数据,目的是获取追溯码代表的药品信息
    @Resource
    private MedicineTraceService medicineTraceService;
    @Resource
    private MedicineTrace_1 medicineTrace_1;
    @RequestMapping("/api/tracecode/{traceCode}")
    public R getMedicineByTracecode(@PathVariable String traceCode){
        MedicineTrace medicineTrace = medicineTraceService.getById(traceCode);
        if (medicineTrace != null){
            System.out.println("药品查询被调用");
            return R.OK(medicineTrace);
        }else {
            return R.FAIL();
        }
    }

    //向Orderform表插入数据
    @Resource
    private OrderformService orderformService;
    @PostMapping("/orderForm")
    public R addOrder(@RequestBody Orderform orderform1){
        boolean save = orderformService.save(orderform1);
        System.out.println("送货单保存被调用");
        return save?R.OK():R.FAIL();
    }

    //向orderitem插入数据
    @Resource
    private OrderitemService orderitemService;
    @PostMapping("/orderItem")
    public R addOrderItem(@RequestBody List<Orderitem> orderitems){
        boolean save = orderitemService.saveBatch(orderitems);
        System.out.println("药品清单保存被调用");
        return save?R.OK():R.FAIL();
    }

    @Resource
    private TracecodeService tracecodeService;
    @PostMapping("/tracecode")
    public R addTracecode(@RequestBody List<Tracecode> tracecodes){
        boolean save = tracecodeService.saveBatch(tracecodes);
        System.out.println("追溯码保存被调用");
        return save?R.OK():R.FAIL();
    }



}
package com.yz.demo.controller;

import com.yz.demo.Utils.OrderRequestDTO;
import com.yz.demo.domain.Orderform;
import com.yz.demo.domain.Orderitem;
import com.yz.demo.domain.Tracecode;
import com.yz.demo.result.R;
import com.yz.demo.service.OrderformService;
import com.yz.demo.service.OrderitemService;
import com.yz.demo.service.TracecodeService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;

@RestController
@RequestMapping("/order")
public class addData {
    @Resource
    private OrderformService orderformService;

    @Resource
    private OrderitemService orderitemService;

    @Resource
    private TracecodeService tracecodeService;

    /**
     * 保存订单,包括 Orderform、Orderitem 和 Tracecode 数据
     */
    @PostMapping("/saveAll")
    @Transactional // 开启事务
    public R saveAll(@RequestBody OrderRequestDTO orderRequestDTO) {
        try {
            // Step 1: 保存 Orderform 表数据
            Orderform orderform = orderRequestDTO.getOrderform();
            boolean orderformSaved = orderformService.save(orderform);
            if (!orderformSaved) {
                throw new RuntimeException("保存 Orderform 数据失败");
            }

            // 获取自增的主键 ID
            Long orderformId = orderform.getId();

            // Step 2: 保存 Orderitem 表数据
            List<Orderitem> orderitems = orderRequestDTO.getOrderitems();
            for (Orderitem orderitem : orderitems) {
                orderitem.setOrderId(orderformId); // 设置外键关联 Orderform 的 ID
            }
            boolean orderitemsSaved = orderitemService.saveBatch(orderitems);
            if (!orderitemsSaved) {
                throw new RuntimeException("保存 Orderitem 数据失败");
            }

            // 获取保存后的 Orderitem ID 列表(需要手动获取)
            List<Long> orderItemIds = orderitems.stream()
                    .map(Orderitem::getId)
                    .toList();

            // Step 3: 保存 Tracecode 表数据
            List<Tracecode> tracecodes = orderRequestDTO.getTracecodes();
            for (int i = 0; i < tracecodes.size(); i++) {
                tracecodes.get(i).setOrderItemId(orderItemIds.get(i)); // 设置外键关联 Orderitem 的 ID
            }
            boolean tracecodesSaved = tracecodeService.saveBatch(tracecodes);
            if (!tracecodesSaved) {
                throw new RuntimeException("保存 Tracecode 数据失败");
            }

            // 如果全部保存成功,返回成功响应
            System.out.println("全部保存已经调用");
            return R.OK();
        } catch (Exception e) {
            e.printStackTrace();
            // 如果出现异常,返回失败响应,并回滚事务
            return R.FAIL(e.getMessage());
        }
    }
}

这样接口也就设计好了,可以通过以上的接口查询和保存数据。

五、AS环境设置

六、主程序代码

package com.example.myapplication;


import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.example.myapplication.RetrofitConfiguration.ManufacturerCallback;
import com.example.myapplication.RetrofitConfiguration.TraceCodeCallback;
import com.example.myapplication.Utils.TimeUtils;
import com.example.myapplication.bean.ApiResponse;
import com.example.myapplication.bean.ApiResponse_Medicine;
import com.example.myapplication.bean.DrugInfo;
import com.example.myapplication.bean.MedicineTrace;
import com.example.myapplication.bean.TraceCode;
import com.example.myapplication.domain.Medicine;
import com.example.myapplication.domain.MedicineAdapter;
import com.google.android.material.textfield.TextInputLayout;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class MainActivity2 extends AppCompatActivity {
    private RecyclerView medicineRecyclerView;   //列表视图
    private MedicineAdapter medicineAdapter;    //适配器

    private TextView scanResult_1;   //
    private TextView scanResult_2;

    private TextView tv_result;
    private int currentScanType;

    private List<Medicine> list_medicine; //订单二维码扫描的结果,备份到这里,方便追溯码和这里的结果来对比

    //接口
    private final static String BaseURL = "http://192.168.123.108:8080/";
    private final static String URL = BaseURL + "order/saveAll"; //这是用来保存订单表orderform的接口
    private final static String URL_order = BaseURL + "api/"; //这是用来查询订单的接口
    private final static String URL_tracecode = BaseURL + "api/tracecode/";
    //为了区分两个不同的扫码按钮,定义以下两个常量
    private static final int REQUEST_CODE_SCAN_BUTTON = 1001;   //标识送货单扫码按钮
    private static final int REQUEST_CODE_TRACECODE_BUTTON = 1002;  //标识追溯码扫码按钮
    private String scannedResult; //订单二维码扫码结果
    private String medicineName_temp; //这是通过扫追溯码,获取到的药品名
    private String manufacturer_temp; //这是通过扫追溯码,获取到的厂家名

    private TextInputLayout textInputLayout; //收货人文本输入框的输入内容
    private List<TraceCode> traceCodeList = new ArrayList<>();

    @SuppressLint("MissingInflatedId")
    @Override
    //onCreate 是 Android 活动的生命周期方法之一。当活动被首次创建时,系统会调用这个方法。
    //参数 savedInstanceState:如果活动之前的状态被保存了(比如屏幕旋转),该对象会包含之前的状态数据。可以用来恢复活动状态。
    protected void onCreate(Bundle savedInstanceState) {
        //调用父类的 onCreate 方法,以确保活动的基础初始化工作能够完成,比如创建窗口等。
        super.onCreate(savedInstanceState);
        //设置当前活动使用的布局文件为 res/layout/activity_main.xml。
        setContentView(R.layout.activity_main);


        medicineRecyclerView = findViewById(R.id.medicine_recycler_view);
        medicineRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        Button scanButton = findViewById(R.id.order_button);
        Button tracecodeButton = findViewById(R.id.TraceabilityCode_button);
        //设置扫描按钮、追溯码扫码按钮的点击事件,点击之后开始QR扫码
        scanButton.setOnClickListener(v -> {
            startQRScanner();
            currentScanType = REQUEST_CODE_SCAN_BUTTON;
        });

        tracecodeButton.setOnClickListener(v -> {
            startQRScanner();
            currentScanType = REQUEST_CODE_TRACECODE_BUTTON;
        });

        scanResult_1 = findViewById(R.id.order_input);
        scanResult_2 = findViewById(R.id.supplier_input);
        tv_result = findViewById(R.id.tv_result_final);

        textInputLayout  = findViewById(R.id.receiver_input_layout);

        //设置提交按钮的点击事件
        findViewById(R.id.submit_button).setOnClickListener(v -> {
            postJson();
        });

    }


    private void startQRScanner() {
        // 启动二维码扫描
        //在这行代码中,this 是指当前的 Activity,该 Activity 会被传递给 IntentIntegrator,它会在该 Activity 中启动扫码界面。
        IntentIntegrator integrator = new IntentIntegrator(this);
        //这一行代码设置了可以扫描的条形码类型
        // ALL_CODE_TYPES 表示允许扫描所有类型的条形码和二维码。这样扫描时,无论是 QR 码还是条形码都能被识别。
        integrator.setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES);
        //在扫描界面上,会显示这条提示信息,告诉用户如何进行操作。例如,提示用户将二维码或条形码置于扫描框内以开始扫描。
        integrator.setPrompt("请将二维码或条形码置于扫描框内");
        integrator.setCameraId(0); // 使用后置摄像头,1代表前置
        integrator.setBeepEnabled(true); // 扫描成功提示音
        integrator.setBarcodeImageEnabled(true); // 扫描结果保存为图片

        //调用 initiateScan() 后,应用会跳转到扫码界面,允许用户通过摄像头扫描二维码或条形码。
        // 一旦扫描到有效的二维码/条形码,扫码结果会传回 onActivityResult() 方法。
        integrator.initiateScan();
    }

    //用于接收并处理从外部活动(比如扫码界面)返回的结果
    //requestCode:请求码,在启动子活动时用来标识请求。
    //resultCode:表示返回的结果状态。通常使用 RESULT_OK 或 RESULT_CANCELED 来表示操作是否成功。
    //data:包含返回结果的 Intent 对象,通常包含额外的数据(比如扫码结果)。
    @SuppressLint("SetTextI18n")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);

        if (result != null && result.getContents() != null && currentScanType == REQUEST_CODE_SCAN_BUTTON) {
            //这里写扫订单二维码之后的代码
            scannedResult = result.getContents().trim();
            scanResult_1.setText(scannedResult);
            scanResult_2.setText("国药控股扬州");
            doGet(scannedResult);
        } else if (result != null && result.getContents() != null && currentScanType == REQUEST_CODE_TRACECODE_BUTTON) {
            TraceCode traceCode = new TraceCode(result.getContents().trim(), TimeUtils.getCurrentFormattedTime(), TimeUtils.getCurrentFormattedTime());
            traceCodeList.add(traceCode);
            //这里写扫追溯码之后的代码
            medicineName_temp = null;
            manufacturer_temp = null;
            String sacannedResult_2 = result.getContents().trim();
            //根据追溯码获取该药品的药品名和生产厂商
            //这里用了回调
            doGetTraceCode(sacannedResult_2, new TraceCodeCallback() {
                @Override
                public void onSuccess(MedicineTrace medicineTrace) {

                    runOnUiThread(() -> {
                        medicineName_temp = medicineTrace.getMedicineName();
                        manufacturer_temp = medicineTrace.getManufacturer();

                        int count = 0;
                        Medicine updatedMedicine = null;
                        for (Medicine item :
                                list_medicine) {
                            if (item.getName().equals(medicineName_temp) && item.getManufacturer().equals(manufacturer_temp)) {
                                //药品名和生产厂家都对上了,则需要在已扫描那里+1
                                String substring = item.getTraceCode().substring(4, 5);
                                int i = Integer.parseInt(substring) + 1;
                                item.setTraceCode("已扫描:" + i + "/" + item.getQuantity());
                                updatedMedicine = item;
                                break;
                            } else {
                                count++;
                            }
                        }
                        // UI 更新

                        if (count == list_medicine.size()) {
                            runOnUiThread(() -> {
                                tv_result.setText("药名:" + medicineName_temp + "不在清单");
                            });
                        } else {
                            medicineAdapter.updateItem(count, updatedMedicine);
                        }

                    });
                }

                @Override
                public void onFailure(String errorMessage) {
                    runOnUiThread(() -> tv_result.setText("查询失败: " + errorMessage));
                }
            });
        } else if (result == null && currentScanType == REQUEST_CODE_SCAN_BUTTON) {
            scanResult_1.setText("扫描取消");
        } else if (result.getContents() == null && currentScanType == REQUEST_CODE_SCAN_BUTTON) {
            scanResult_1.setText("扫描内容为空");
        } else {
            scanResult_1.setText("出现未知异常");
        }
    }


    //通过追溯码获取药品信息
    private void doGetTraceCode(String qrcode_2, TraceCodeCallback callback) {
        if (callback == null) {
            throw new IllegalArgumentException("Callback cannot be null");
        }
        String URL = URL_tracecode + qrcode_2;
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(URL)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                callback.onFailure("追溯码查询失败: " + e.getMessage());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (!response.isSuccessful()) {
                    callback.onFailure("请求失败,HTTP状态码: " + response.code());
                    return;
                }
                String jsonResponse = null;
                try {
                    if (response.body() == null) {
                        callback.onFailure("响应体为空");
                        return;
                    }
                    jsonResponse = response.body().string();
                    Gson gson = new Gson();
                    ApiResponse_Medicine apiResponse = gson.fromJson(jsonResponse, ApiResponse_Medicine.class);
                    if (apiResponse == null || apiResponse.getData() == null) {
                        throw new JsonSyntaxException("响应数据格式不正确或数据为空");
                    }
                    if (apiResponse.getCode() == 200) {
                        // 成功回调,传递解析后的数据
                        callback.onSuccess(apiResponse.getData());

                    } else {
                        callback.onFailure("查询失败,错误码: " + apiResponse.getCode());
                    }
                } catch (JsonSyntaxException e) {
                    callback.onFailure("JSON解析失败: " + e.getMessage());
                } catch (Exception e) {
                    callback.onFailure("未知错误: " + e.getMessage());
                }
            }
        });
    }

    //这里是通过订单号二维码扫描结果,在网格列表中展示订单详细信息
    private void doGet(String qrcode_1) {
        String URL_orderForm = URL_order + qrcode_1;

        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(URL_orderForm)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                runOnUiThread(() -> {
                    tv_result.setText("请求失败: " + e.getMessage());
                    Log.e("doGet", "请求失败", e);
                });
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
               /* public boolean isSuccessful() {
                   return code >= 200 && code < 300;
                }   需要先判断状态码是不是200-299*/
                if (!response.isSuccessful()) {
                    runOnUiThread(() -> {
                        tv_result.setText("请求失败,HTTP状态码: " + response.code());
                        Log.e("doGet", "请求失败,HTTP状态码: " + response.code());
                    });
                    return;
                }

                String jsonResponse = null;
                try {
                    jsonResponse = response.body().string();
                    Log.d("doGet", "接口返回: " + jsonResponse);

                    Gson gson = new Gson();
                    ApiResponse apiResponse = gson.fromJson(jsonResponse, ApiResponse.class);

                    if (apiResponse.getCode() == 200) {
                        List<DrugInfo> dataItems = apiResponse.getData();

                        List<Medicine> medicineList = new ArrayList<>();
                        for (DrugInfo item : dataItems) {
                            String drugName = item.getDrugName();
                            String manufacturer = item.getManufacturer();
                            int quantity = item.getQuantity();
                            double amount = item.getAmount();
                            String tracecodeTemplate = "已扫描:0/" + quantity;
                            medicineList.add(new Medicine(drugName, manufacturer, quantity, amount, tracecodeTemplate));
                        }
                        list_medicine = medicineList;
                        runOnUiThread(() -> {
                            medicineAdapter = new MedicineAdapter(medicineList);
                            medicineRecyclerView.setAdapter(medicineAdapter);

                            medicineRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity2.this));
                            tv_result.setText("请求成功,数据已更新");
                        });

                    } else {
                        runOnUiThread(() -> {
                            tv_result.setText("接口返回错误,Code: " + apiResponse.getCode());
                            Log.e("doGet", "接口返回错误,Code: " + apiResponse.getCode());
                        });
                    }
                } catch (JsonSyntaxException e) {
                    Log.e("doGet", "JSON解析失败", e);
                    String finalJsonResponse = jsonResponse; // 捕获 JSON 数据用于调试
                    runOnUiThread(() -> tv_result.setText("JSON解析失败: " + e.getMessage() + "\n响应内容: " + finalJsonResponse));
                } catch (Exception e) {
                    Log.e("doGet", "未知错误", e);
                    runOnUiThread(() -> tv_result.setText("未知错误: " + e.getMessage()));
                }
            }
        });
    }


    private void postJson() {
        String jsonString = "";
        try {
            // 获取当前时间,格式化为 yyyy-MM-dd HH:mm:ss
            String currentTime = TimeUtils.getCurrentFormattedTime();

            // 构建 Orderform 对象
            JSONObject orderform = new JSONObject();
            orderform.put("orderNumber", scannedResult);
            String receiver = textInputLayout.getEditText() != null && textInputLayout.getEditText().getText() != null
                    ? textInputLayout.getEditText().getText().toString()
                    : "";
            orderform.put("supplier", "国药扬州");
            orderform.put("receiver", receiver);
            orderform.put("createdTime", currentTime);
            orderform.put("updatedTime", currentTime);

            // 检查药品清单和追溯码列表是否为空
            if (list_medicine == null || list_medicine.isEmpty()) {
                runOnUiThread(() -> tv_result.setText("药品清单为空"));
                return;
            }
            if (traceCodeList == null || traceCodeList.isEmpty()) {
                runOnUiThread(() -> tv_result.setText("追溯码列表为空"));
                return;
            }

            // 构建 Orderitem 列表
            JSONArray orderitems = new JSONArray();
            for (Medicine medicine : list_medicine) {
                JSONObject orderitem = new JSONObject();
                orderitem.put("productName", medicine.getName());
                orderitem.put("manufacturer", medicine.getManufacturer());
                orderitem.put("quantity", medicine.getQuantity());
                orderitem.put("amount", medicine.getAmount());
                orderitem.put("createdTime", currentTime);
                orderitem.put("updatedTime", currentTime);
                orderitems.put(orderitem);
            }

            // 构建 Tracecode 列表
            JSONArray tracecodes = new JSONArray();
            for (TraceCode traceCode : traceCodeList) {
                JSONObject tracecode = new JSONObject();
                tracecode.put("traceCode", traceCode.getTraceCode());
                tracecode.put("createdTime", traceCode.getCreatedAt());
                tracecode.put("updatedTime", traceCode.getUpdatedAt());
                tracecodes.put(tracecode);
            }

            // 构建最终的 OrderRequestDTO 对象
            JSONObject orderRequestDTO = new JSONObject();
            orderRequestDTO.put("orderform", orderform);
            orderRequestDTO.put("orderitems", orderitems);
            orderRequestDTO.put("tracecodes", tracecodes);

            // 转换为字符串
            jsonString = orderRequestDTO.toString();

        } catch (Exception e) {
            e.printStackTrace();
            runOnUiThread(() -> tv_result.setText("JSON 构建失败:" + e.getMessage()));
            return;
        }

        // 打印生成的 JSON,便于调试
        System.out.println("最终生成的 JSON:" + jsonString);

        // HTTP 请求
        RequestBody body = RequestBody.create(jsonString, MediaType.parse("application/json;charset=utf-8"));
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .post(body)
                .url(URL)
                .addHeader("Content-Type", "application/json") // 确保请求头设置正确
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                runOnUiThread(() -> tv_result.setText("调用接口报错:" + e.getMessage()));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String resp = response.body() != null ? response.body().string() : "";
                if (response.isSuccessful()) {
                    try {
                        JSONObject jsonObject = new JSONObject(resp);
                        int code = jsonObject.optInt("code", -1);
                        String msg = jsonObject.optString("msg", "未返回消息");
                        runOnUiThread(() -> tv_result.setText("code: " + code + "\nmsg: " + msg));
                    } catch (JSONException e) {
                        e.printStackTrace();
                        runOnUiThread(() -> tv_result.setText("JSON 解析出错:" + e.getMessage()));
                    }
                } else {
                    runOnUiThread(() -> tv_result.setText("接口调用失败,HTTP 状态码:" + response.code()));
                }
            }
        });
    }


}

这样,一个安卓系统的入库系统就做好了,可以说非常简单!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

剑客狼心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值