整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

原生JS + HTML + CSS 实现快递物流信息

原生JS + HTML + CSS 实现快递物流信息 API 的数据链式展示

全国快递物流查询 API 是一种提供实时、准确、可靠的快递物流信息查询服务的接口。它基于现有的物流信息系统,通过API接口的方式,向用户提供快递物流信息的查询、跟踪、统计等功能。使用全国快递物流查询 API,用户可以在自己的应用程序或网站上,快速、方便地查询快递物流信息。

本文从全国快递物流查询 API 的工作原理开始说起,给出包括 API 的应用场景、如何调用以及实际代码示例,供大家参考。


工作原理

全国快递物流查询 API 的工作原理比较简单,通过请求第三方数据源获取最新的快递物流信息,再进行处理和解析,最终返回标准格式的数据给用户,我们可以参考下图的工作过程:


主要应用场景

全国快递物流查询 API 的应用场景广泛,能够帮助各个行业和场景中的用户快速查询、管理和分析快递物流信息,提高工作效率和服务质量。


全国快递物流 API 使用教程

APISpace 是 国内一个较大的 API 供应平台,提供多种类型的 API 接口,包括手机号码归属地查询 API 、天气预报查询API、手机在网状态 API 、反欺诈(羊毛盾)API 以及当前比较热门的 AI 绘画 API 等等,感兴趣的小伙伴可以去官网体验一下。


1.申请 API 密钥

用户需要在 API 提供商的官方网站进行注册,并申请 API 密钥,获得 API 接口调用的权限。

以 APISpace 为例,使用全国快递物流 API 的步骤通常如下:

进入全国快递物流 API 详情页,点击【免费试用】或者【注册】都可以获取 API 密钥。

访问地址:

https://www.apispace.com/eolink/api/wlgj1/introduction?utm_source=tth&utm_content=high021&utm_term=qqwl

注册成功后,我们在页面导航菜单点击【我的 API】进入【访问控制】页面,即可看到平台提供的密钥。


2.在线测试 API

点击免费试用成功后,系统会自动进入 API 的测试界面,如下图,我们只需要填入快递公司名称以及单号就能获取到完整的快递轨迹信息


3.使用代码接入 API 接口 - JS 方式

var data="{\"cpCode\":\"YTO\",\"mailNo\":\"YTO1111111111\",\"tel\":\"13000000000或0000\",\"orderType\":\"asc\"}"

var xhr=new XMLHttpRequest();
xhr.withCredentials=true;

xhr.addEventListener("readystatechange", function () {
    if (this.readyState===4) {
        console.log(this.responseText);
    }
});

xhr.open("POST", "https://eolink.o.apispace.com/wlgj1/paidtobuy_api/trace_search");
xhr.setRequestHeader("X-APISpace-Token","替换成平台提供的 API");
xhr.setRequestHeader("Authorization-Type","apikey");
xhr.setRequestHeader("Content-Type","application/json");

xhr.send(data);

其他语言的接入可以点【接入指南】查看,包括Java、微信小程序等多种示例语言都整理出来了。


4.物流轨迹数据展示

根据 API 返回的结果

{
    "traceId": "xxx",
    "trace_id": "xxx",
    "success": true,
    "logisticsTrace": {
        "theLastTime": "2023-04-13 13:33:17",
        "cpCode": "EMS",
        "cpUrl": "https://www.ems.com.cn/",
        "takeTime": "2天21小时27分",
        "logisticsStatusDesc": "已代收",
        "logisticsTraceDetailList": [{
            "areaCode": "xxx",
            "areaName": "天津,天津市,武清区",
            "subLogisticsStatus": "ACCEPT",
            "time": 1681113967000,
            "logisticsStatus": "ACCEPT",
            "desc": "【天津市武清区电商客户揽投部】已收寄,揽投员:xxx,电话:185xxxxxxx4"
        }, {
            "areaCode": "CN120114000000",
            "areaName": "天津,天津市,武清区",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681124599000,
            "logisticsStatus": "TRANSPORT",
            "desc": "离开【天津市武清区电商客户揽投部】,下一站【天津邮件处理中心包件车间】"
        }, {
            "areaCode": "CN120100000000",
            "areaName": "天津,天津市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681134781000,
            "logisticsStatus": "TRANSPORT",
            "desc": "到达【天津邮件处理中心包件车间】"
        }, {
            "areaCode": "CN120100000000",
            "areaName": "天津,天津市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681141155000,
            "logisticsStatus": "TRANSPORT",
            "desc": "离开【天津邮件处理中心包件车间】,下一站【广州市江高包件车间】"
        }, {
            "areaCode": "CN440100000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681281085000,
            "logisticsStatus": "TRANSPORT",
            "desc": "到达【xx车间】"
        }, {
            "areaCode": "CN440100000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681297051000,
            "logisticsStatus": "TRANSPORT",
            "desc": "离开【xx车间】,下一站【xx车间】"
        }, {
            "areaCode": "CN442000000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681307392000,
            "logisticsStatus": "TRANSPORT",
            "desc": "到达【xx车间】(经转)"
        }, {
            "areaCode": "CN442000000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681318786000,
            "logisticsStatus": "TRANSPORT",
            "desc": "离开【xxx车间】,下一站【xxx处理车间】(经转)"
        }, {
            "areaCode": "CN440100000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681331119000,
            "logisticsStatus": "TRANSPORT",
            "desc": "到达【xxx处理车间】"
        }, {
            "areaCode": "CN440100000000",
            "areaName": "广东省,xx市",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681337879000,
            "logisticsStatus": "TRANSPORT",
            "desc": "离开【xxx处理车间】,下一站【xxx揽投部】"
        }, {
            "areaCode": "CN440113000000",
            "areaName": "广东省,xx市,xx区",
            "subLogisticsStatus": "TRANSPORT",
            "time": 1681342169000,
            "logisticsStatus": "TRANSPORT",
            "desc": "到达【xxxx投部】"
        }, {
            "areaCode": "CN440113000000",
            "courier": "xxx",
            "areaName": "广东省,xx,xx区",
            "subLogisticsStatus": "DELIVERING",
            "courierPhone": "13xxxxxxxxx",
            "time": 1681352410000,
            "logisticsStatus": "DELIVERING",
            "desc": "【xxx揽投部】安排投递,投递员:xxx,电话:1xxxxxxxxxx,揽投部电话:0xx-xxxxxxx2"
        }, {
            "areaCode": "CN440100000000",
            "courier": "xxx",
            "areaName": "广东省,xxx市",
            "subLogisticsStatus": "xxx",
            "courierPhone": "1xxxxxxxxx3",
            "time": 1681363997000,
            "logisticsStatus": "AGENT_SIGN",
            "desc": "已签收,他人代收:xxxxx,投递员:xxx,电话:1xxxxxxxxx"
        }],
        "mailNo": "9853491117528",
        "cpMobile": "xxx",
        "theLastMessage": "已签收,他人代收:xxxxx,投递员:xxx,电话:1xxxxxxxxx",
        "logisticsCompanyName": "EMS",
        "courier": "xxx",
        "courierPhone": "1xxxxxxxxxx",
        "logisticsStatus": "xxx"
    }
}


物流信息展示代码示例( 原生JS + HTML + CSS)

下面的代码是手敲的,有错误欢迎评论区指正~

Html

<div class="" id="logistics-trace"></div>


Css

样式觉得简陋的话可以自行调整

<style>
    .logistics-trace {
      margin: 0;
      padding: 0;
      list-style: none;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      justify-content: center;
    }
    .logistics-trace li {
      width: 180px;
      margin: 10px;
      padding: 10px;
      background-color: #fff;
      border: 1px solid #ddd;
      border-radius: 5px;
      box-shadow: 0 0 10px rgba(0,0,0,0.2);
      text-align: center;
      position: relative;
    }
    .logistics-trace li:after {
      content: "";
      display: block;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      border: 2px solid #ddd;
      background-color: #fff;
      position: absolute;
      top: -10px;
      left: calc(50% - 10px);
      z-index: 1;
    }
    .logistics-trace li:before {
      content: "";
      display: block;
      width: 2px;
      height: 100%;
      border-left: 1px solid #ddd;
      position: absolute;
      top: 10px;
      left: calc(50% - 1px);
      z-index: 1;
    }
    .logistics-trace li:first-child:before {
      display: none;
    }
    .logistics-trace li:last-child:after {
      display: none;
    }
    .logistics-time {
      font-size: 14px;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .logistics-status {
      font-size: 12px;
      margin-bottom: 5px;
    }
    .logistics-desc {
      font-size: 12px;
    }
    .logistics-status.accept {
      color: green;
    }
    .logistics-status.transport {
      color: blue;
    }
    .logistics-status.delivering {
      color: red;
    }
  </style>


JS

使用 JS 对返回的物流信息做处理

function generateLogisticsTrace(logisticsTraceData) {
      const logisticsTraceDetailList=logisticsTraceData.logisticsTrace.logisticsTraceDetailList;
      let logisticsTrace='<ul>';
      logisticsTraceDetailList.forEach((logisticsTraceDetail, index)=> {
        let logisticsStatus='';
        let logisticsStatusDesc='';
        let desc=logisticsTraceDetail.desc;
        let time=new Date(logisticsTraceDetail.time).toLocaleString();
        if (logisticsTraceDetail.subLogisticsStatus==='ACCEPT') {
          logisticsStatus='accept';
          logisticsStatusDesc='揽收';
        } else if (logisticsTraceDetail.subLogisticsStatus==='TRANSPORT') {
          logisticsStatus='transport';
          logisticsStatusDesc='运输';
        } else if (logisticsTraceDetail.subLogisticsStatus==='DELIVERING') {
          logisticsStatus='delivering';
          logisticsStatusDesc='派送';
          desc='【' + logisticsTraceDetail.areaName + '】' + logisticsTraceDetail.desc.replace(',', ',<br>投递员:');
        }
        logisticsTrace +=`
          <li class="${logisticsStatus}">
            <div class="logistics-time">${time}</div>
            <div class="logistics-status">${logisticsStatusDesc}</div>
            <div class="logistics-desc">${desc}</div>
          </li>
        `;
        if (index===logisticsTraceDetailList.length - 1) {
          logisticsTrace +='</ul>';
        }
      });
      return logisticsTrace;
    }


调用

刀PPT提供免费总结报告PPT模板,货轮集装箱背景的港口物流PPT模板,模板是设计好的PPT模板直接打开编辑即可。

页数:23页

编号:PPT83361

大小:1.68MB

软件:PowerPoint

格式:PPTX

比例:16:9

复制下载:

101dao.com/ppt/ppt-PPT83361.html


、目的

做这个项目的初衷是因为我去年在微信卖老家水果,好多朋友下单后都问我快递单号,每天发货后我都要挨个甄别这个人是哪个快递信息,很麻烦一部小心就搞错了。基于这件小事我有了自助快递查询的这个想法。将发货的快递信息导入到我的系统里,用户访问我的系统,通过输入手机号就可以查看自己的快递物流信息。 项目是去年8月写的,一直搁浅在哪,最近无意间翻看我发的那篇文章自助快递单号查询阅读量竟然都1.8w了,有图有真相。

这着实让我很震惊,看来自助快递查询这块确实是个热点。今天我就讲一下我手撸的快递查询系统。

二、开发

项目地址:github.com/hellowHuaai… 有兴趣的可以直接下载源码,觉得项目不错的伙伴记得点个star,谢谢啦!

2.1技术栈

项目涉及到的技术栈有:

  • SpringBoot: 一款 Java 微服务框架。Spring boot 是 Spring 家族中的一个新框架,它用来简化 Spring 应用程序的创建和开发。
  • Mybitas: 一款ORM框架,即对象关系映射。ORM框架的作用是把持久化对象的保存、修改、删除等操作,转换成对数据库的操作。
  • Jquery:一个轻量级的写的少,做的多的 JavaScript 函数库。
  • Bootstrap:Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的。

2.2后端开发

创建entity 创建快递单实体类,属性包括id,用户名(userName),电话(phone),快递单号(kuaidiNo),快递公司(company),数据创建时间(createTime)。代码如下:

@Data
@Builder
public class KuaiDi {
    private Integer id;
    /* 收件人姓名 */
    private String userName;
    /**收件人电话*/
    private String phone;
    /* 快递单号*/
    private String kuaidiNo;
    /*快递公司名称(拼音)*/
    private String company;
    /*订单创建时间*/
    private Date createTime;
    
    public KuaiDi(Integer id, String userName, String phone, String kuaidiNo, String company, Date createTime) {
        this.id=id;
        this.userName=userName;
        this.phone=phone;
        this.kuaidiNo=kuaidiNo;
        this.company=company;
        this.createTime=createTime;
    }
    public KuaiDi(Integer id, String userName, String phone, String kuaidiNo, String company) {
        this.id=id;
        this.userName=userName;
        this.phone=phone;
        this.kuaidiNo=kuaidiNo;
        this.company=company;
    }
}

service,mapper是常规的增删查改操作,就是保存快递的基本信息在数据库中,并可以对数据进行简单的维护功能。详细可参考项目源码。接下来看核心代码。

查询快递信息 快递的基本信息存入数据库,然后就是通过这些信息查询快递的详细物流信息。这里我做过很多尝试,想直接调用一些快递公司的快递信息查询接口,但是都发现接口都有session,当session失效后就无法查询到数据或者就查询到的数据不正确。最终在网上找到一种付费的方案,使用快递100接口。www.kuaidi100.com/ 查询快递的demo代码如下:

public class SynQueryDemo {

	/**
	 * 实时查询请求地址
	 */
	private static final String SYNQUERY_URL="http://poll.kuaidi100.com/poll/query.do";
	
	private String key;			//授权key
	private String customer;	//实时查询公司编号

	public SynQueryDemo(String key, String customer) {
		this.key=key;
		this.customer=customer;
	}
	
	/**
	 * 实时查询快递单号
	 * @param com			快递公司编码
	 * @param num			快递单号
	 * @param phone			手机号
	 * @param from			出发地城市
	 * @param to			目的地城市
	 * @param resultv2		开通区域解析功能:0-关闭;1-开通
	 * @return
	 */
	public String synQueryData(String com, String num, String phone, String from, String to, int resultv2) {

		StringBuilder param=new StringBuilder("{");
		param.append("\"com\":\"").append(com).append("\"");
		param.append(",\"num\":\"").append(num).append("\"");
		param.append(",\"phone\":\"").append(phone).append("\"");
		param.append(",\"from\":\"").append(from).append("\"");
		param.append(",\"to\":\"").append(to).append("\"");
		if(1==resultv2) {
			param.append(",\"resultv2\":1");
		} else {
			param.append(",\"resultv2\":0");
		}
		param.append("}");
		
		Map<String, String> params=new HashMap<String, String>();
		params.put("customer", this.customer);
		String sign=MD5Utils.encode(param + this.key + this.customer);
		params.put("sign", sign);
		params.put("param", param.toString());
		
		return this.post(params);
	}
	
	/**
	 * 发送post请求
	 */
	public String post(Map<String, String> params) {
		StringBuffer response=new StringBuffer("");
		
		BufferedReader reader=null;
		try {
			StringBuilder builder=new StringBuilder();
			for (Map.Entry<String, String> param : params.entrySet()) {
				if (builder.length() > 0) {
					builder.append('&');
				}
				builder.append(URLEncoder.encode(param.getKey(), "UTF-8"));
				builder.append('=');
				builder.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
			}
			byte[] bytes=builder.toString().getBytes("UTF-8");

			URL url=new URL(SYNQUERY_URL);
			HttpURLConnection conn=(HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(3000);
			conn.setReadTimeout(3000);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setRequestProperty("Content-Length", String.valueOf(bytes.length));
			conn.setDoOutput(true);
			conn.getOutputStream().write(bytes);

			reader=new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
			
			String line="";
            while ((line=reader.readLine()) !=null) {
            	response.append(line);
            }
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null !=reader) {
					reader.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		return response.toString();
	}
}

上面的代码就是通过java代码调用kuaidi100的查询接口,这个查询接口会通过快递单号自动识别快递是属于哪个快递公司,然后调用对应快递公司接口获取响应数据。付费购买接口使用权其实就是生成一个授权key和实时查询公司编号customer,在线调用会做身份认证。这样就可以获取快递信息的json数据了。我已经购买了100块大洋的接口使用权,大家可直接调用快递查询接口。

controller代码 快递信息增删查改的controller就不在列了,这里主要看下我对查询快递的接口进行了一次包装处理。代码如下:

@RestController
public class KuaiDiQueryController {

    @Autowired
    private KuaiDiService kuaiDiService;
    @Autowired
    private KuaiDiQueryService kuaiDiQueryService;

    /**
     * 返回json数据
     * @param com
     * @param no
     * @return
     */
    @GetMapping("/getKuaiDiInfoByJson")
    @ResponseBody
    public String queryKuadiInfoByJson(String com, String no) {
        return kuaiDiQueryService.synQueryData(com, no,"", "", "", 0);
    }

    @GetMapping("/getKuaiDiInfoByPhone")
    @ResponseBody
    public Response queryKuaidiByPhone(String phone){
        Response response=new Response();
        if(StringUtils.isNotEmpty(phone)){
            List<ResponseData> responseDataList=new ArrayList<>();
            //  1.通过手机号查询下面的所有订单号
            List<KuaiDi> kuaiDiList=kuaiDiService.getList("", phone);
            if(!CollectionUtils.isEmpty(kuaiDiList)){
                kuaiDiList.forEach(kuaiDi -> {
                    //  2.依次查出所有的订单号
                    String responseDataStr=kuaiDiQueryService.synQueryData(kuaiDi.getCompany(), kuaiDi.getKuaidiNo(),"", "", "", 0);
                    ResponseData responseData=CommonUtils.convertJsonStr2Object(responseDataStr);
                    responseDataList.add(responseData);
                });
            }
            // 3.组装数据返回给前台
            response.setDataList(responseDataList);
        }
        return response;
    }
}

2.3前端开发

前端展示主要包括两个页面,管理员页面和客户页面。管理员页面功能包括快递信息的新增,修改,删除,分页查询,在线快递物流信息接口。客户页面包括快递信息的分页查询和在线快递物流信息接口。所以主要看一下管理员页面。

html页面 html页面引入了jQuery和Bootstrap,jQuery已经过时了,但是使用起来还是很方便的。

<html>
<head>
  <title>快递单号查询</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://cdn.bootcss.com/bootbox.js/4.4.0/bootbox.min.js"></script>
    <link href="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.js"></script>
    <script src="https://cdn.bootcss.com/bootstrap-table/1.11.1/locale/bootstrap-table-zh-CN.min.js"></script>
  ...
</head>
<body>
    <div class="container-fluid">

        <div class="row">
            <nav class="navbar navbar-inverse navbar-fixed-top">
                <a class="navbar-brand" href="http://mhtclub.com">我的个人主页</a>
                <button class="navbar-toggle" data-toggle="collapse" data-target="#collapseMenu">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <div class="collapse navbar-collapse" id="collapseMenu">
                    <ul class="nav navbar-nav">
                        <li class="nav-li">
                            <a href="https://github.com/hellowHuaairen/kuaidi" target="_blank">本项目github</a>
                        </li>
                    </ul>
                </div>
            </nav>
        </div>

        <h1 class="page-header">
            快递单号自助查询
        </h1>

        <!-- 查询工具栏 -->
        <div class="form-inline">
            <div class="form-group">
                <label for="queryNameText">收件人姓名:</label>
                <input id="queryNameText" class="form-control input-sm">
            </div>
            <div class="form-group">
                <label for="queryPhoneText">收件人电话:</label>
                <input id="queryPhoneText" class="form-control input-sm">
            </div>
            <button class="btn btn-primary btn-sm" id="queryBtn">查询</button>
            <button class="btn btn-primary btn-sm" id="resetBtn">重置</button>
            <button class="btn btn-primary btn-sm" id="addBtn">新增</button>
        </div>
        <hr>

        <table id="testTable"></table>

        <!-- 查看订单信息模态窗 -->
        <div class="modal fade" id="viewModal">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal">×</button>
                        <h4 class="modal-title">订单信息</h4>
                    </div>
                    <div class="modal-body" id="viewDataList"></div>
                    <div class="modal-footer">
                        <button class="btn btn-default" data-dismiss="modal">关闭</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- 新增模态窗 -->
        <div class="modal fade" id="addModal">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal">×</button>
                        <h4 class="modal-title">新增信息</h4>
                    </div>
                    <div class="modal-body">
                        <div class="form-inline">

                        </div>
                        <div class="form-group">
                            <label for="addNameText">收件人姓名:</label>
                            <input id="addNameText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="addPhoneText">收件人电话:</label>
                            <input id="addPhoneText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="addKuaiDiNoText">快递单号:</label>
                            <input id="addKuaiDiNoText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="addCompanyText">快递公司(拼音):</label>
                            <input id="addCompanyText" class="form-control input-sm">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button class="btn btn-default" data-dismiss="modal">关闭</button>
                        <button class="btn btn-primary" id="saveAdd">保存</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 修改模态窗 -->
        <div class="modal fade" id="modifyModal">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal">×</button>
                        <h4 class="modal-title">修改信息</h4>
                    </div>
                    <div class="modal-body">
                        <div class="form-inline">

                        </div>
                        <div class="form-group">
                            <label for="modifyNameText">收件人姓名:</label>
                            <input id="modifyNameText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="modifyPhoneText">收件人电话:</label>
                            <input id="modifyPhoneText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="modifyKuaiDiNoText">快递单号:</label>
                            <input id="modifyKuaiDiNoText" class="form-control input-sm">
                        </div>
                        <div class="form-group">
                            <label for="modifyCompanyText">快递公司(拼音):</label>
                            <input id="modifyCompanyText" class="form-control input-sm">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button class="btn btn-default" data-dismiss="modal">关闭</button>
                        <button class="btn btn-primary" id="saveModify">保存</button>
                    </div>
                </div>
            </div>
        </div>
    </div>  <!-- container-fluid -->

    <script type="text/javascript" src="js/admin.js"></script>
</body>
</html>

admin.js 这里说明一下前端我引入的jQuery,包括新增,修改,删除,查询的功能,查询事件添加了对电话号码的必填校验。

var $testTable=$('#testTable');
$testTable.bootstrapTable({
    url: 'getList',
    queryParams: function (params) {
        return {
            offset: params.offset,
            limit: params.limit,
            userName: $('#queryNameText').val(),
            phone: $('#queryPhoneText').val()
        }
    },
    columns: [{
        field: 'id',
        title: '编号'
    }, {
        field: 'userName',
        title: '收件人姓名'
    }, {
        field: 'phone',
        title: '收件人电话'
    },  {
        field: 'company',
        title: '快递公司'
    },{
        field: 'kuaidiNo',
        title: '快递单号',
        formatter: function (value, row, index) {
            return [
				'<a onclick="kuaidiRecordInfo(' + "'" + row.kuaidiNo + "','" + row.company + "')" + '">' + row.kuaidiNo +'</a>',
            ].join('');
        },
    }, {
        formatter: function (value, row, index) {
            return [
                '<a href="javascript:modifyKuaiDi(' + row.id + ",'" + row.userName + "'," + row.phone + ",'" + row.kuaidiNo + "'" + ')">' +
                    '<i class="glyphicon glyphicon-pencil"></i>修改' +
                '</a>',
                '<a href="javascript:delKuaiDi(' + row.id + ')">' +
                    '<i class="glyphicon glyphicon-remove"></i>删除' +
                '</a>'
            ].join('');
        },
        title: '操作'
    }],
    striped: true,
    pagination: true,
    sidePagination: 'server',
    pageSize: 10,
    pageList: [5, 10, 25, 50, 100],
    rowStyle: function (row, index) {
        var ageClass='';
        if (row.age < 18) {
            ageClass='text-danger';
        }
        return {classes: ageClass}
    },
});

// 设置bootbox中文
bootbox.setLocale('zh_CN');

var titleTip='提示';

function kuaidiRecordInfo(no, company) {
    $('#viewModal').modal('show');
    $.ajax({
        type:'get',
        url:'getKuaiDiInfoByJson?com='+ company +'&no=' + no,
        cache:false,
        dataType:'json',
        success:function(result){
            // 显示详细信息 发送请求通过单号
			$("#viewDataList").empty();
            console.log(result.data);
            var dataList=result.data;
            if(null !=dataList){
				$("#viewDataList").append('<li class="accordion-navigation"><a href="#kuaidi'+ '">快递单号:'+ result.nu +'</a><div id="kuaidi'+ '" class="content"></div></li>');
				$("#kuaidi").append('<section class="result-box"><div id="resultTop" class="flex result-top"><time class="up">时间</time><span>地点和跟踪进度</span></div><ul id="reordList'+'" class="result-list sortup"></ul></section>');  
                for(var i=0;i<dataList.length; i++){
                    var kuaiRecodList=dataList[i];
                    if( i==0){
                        $("#reordList").append('<li class="last finish"><div class="time"> '+ kuaiRecodList.ftime + '</div><div class="dot"></div><div class="text"> '+ kuaiRecodList.context +'</div></li>');
                    }else{
                        $("#reordList").append('<li class=""><div class="time"> '+ kuaiRecodList.ftime + '</div><div class="dot"></div><div class="text"> '+ kuaiRecodList.context +'</div></li>');
                    }
                }
            }
        }
    });
}

// 验证姓名和地址是否为空
function verifyNameAndAddress(name, address) {
    if (name !='' && address !='') {
        return true;
    }
    return false;
}

function nullAlert() {
    bootbox.alert({
        title: titleTip,
        message: '所有项均为必填!'
    });
}

// 点击查询按钮
$('#queryBtn').click(function () {
    var age=$('#queryAgeText').val();
    // 刷新并跳转到第一页
    $testTable.bootstrapTable('selectPage', 1);

});

// 点击重置按钮,清空查询条件并跳转回第一页
$('#resetBtn').click(function() {
    $('.form-group :text').val('');
    $testTable.bootstrapTable('selectPage', 1);
});

// 用于修改服务器资源
function exchangeData(path, id, userName, phone, kuaiDiNo, company) {
    $.ajax({
        url: path,
        type: 'post',
        data : {
            id: id,
            userName: userName,
            phone: phone,
            kuaiDiNo: kuaiDiNo,
            company: company
        },
        success: function(res) {
            bootbox.alert({
                title: titleTip,
                message: res.message
            });
            // 在每次提交操作后返回首页
            $testTable.bootstrapTable('selectPage', 1);
        }
    });
}

// 新增
$('#addBtn').click(function() {
    $('#addNameText').val('');
    $('#addPhoneText').val('');
    $('#addKuaiDiNoText').val('');
	   $('#addCompanyText').val('');
    $('#addModal').modal('show');
});

$('#saveAdd').click(function() {
    $('#addModal').modal('hide');
    bootbox.confirm({
        title: titleTip,
        message: '确认增加?',
        callback: function (flag) {
            if (flag) {
                var userName=$('#addNameText').val();
                var phone=$('#addPhoneText').val();
                var kuaiDiNo=$('#addKuaiDiNoText').val();
                var company=$('#addCompanyText').val();
                if (verifyNameAndAddress(userName, kuaiDiNo)) {
                    exchangeData('addKuaiDi', null, userName, phone, kuaiDiNo, company);
                } else {
                    nullAlert();
                }
            }
        }
    });
});

var mid;

// 修改
function modifyKuaiDi(id, name, age, address) {
    mid=id;
    $('#modifyNameText').val(name);
    $('#modifyPhoneText').val(age);
    $('#modifyKuaiDiNoText').val(address);
	$('#modifyCompanyText').val(address);
    $('#modifyModal').modal('show');
}

$('#saveModify').click(function() {
    $('#modifyModal').modal('hide');
    bootbox.confirm({
        title: titleTip,
        message: '确认修改?',
        callback: function (flag) {
            if (flag) {
                var userName=$('#modifyNameText').val();
                var phone=$('#modifyPhoneText').val();
                var kuaiDiNo=$('#modifyKuaiDiNoText').val();
                var company=$('#modifyCompanyText').val();
                if (verifyNameAndAddress(userName, phone)) {
                    exchangeData('modifyKuaiDi', mid, userName, phone, kuaiDiNo, company);
                } else {
                    nullAlert();
                }
            }
        }
    });
});

// 删除
function delKuaiDi(id) {
    bootbox.confirm({
        title: titleTip,
        message: '确认删除?',
        callback: function(flag) {
            if (flag) {
                exchangeData("delKuaiDi", id);
            }
        }
    });

2.4运行项目

修改配置文件 项目配置文件src/resources/application.properties,根据实际情况修改对应的数据库连接信息。

#MySQL配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/kuaidi?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root #数据库账号
spring.datasource.password=root #数据库密码
#MyBatis日志配置
mybatis.mapperLocations=classpath:mapper/*.xml
mybatis.config-location=classpath:/config/mybatis-config.xml
#端口配置
server.port=8082

# 定位模板的目录
spring.mvc.view.prefix=classpath:/templates/
# 给返回的页面添加后缀名
spring.mvc.view.suffix=.html

创建数据库表 表结构如下:

DROP TABLE IF EXISTS `kuaidi`;
CREATE TABLE `kuaidi`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人姓名',
  `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人电话',
  `kuaidi_no` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '快递单号',
  `company` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '快递公司名称拼音',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 CHARACTER SET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=Dynamic;

运行 将项目导入Idea工具,找到com.wangzg.kuaidi.KuaiDiApplication文件,执行main方法即可,如下图:

三、部署

3.1 jar部署

上传安装包 在服务器创建/usr/myworkspace,执行下面命令可直接创建:

mkdir -p /usr/myworkspace
复制代码

下载相关文件,上传到服务器/usr/myworkspace。下载地址:github.com/hellowHuaai… 文件主要包括:

  • application.properties 说明:项目配置文件,可能会涉及到修改服务器端口,数据库访问、端口、账号、密码等。
  • kuaidi.jar 说明:后端服务的可执行jar文件。
  • kuaidi.sql 说明:数据库初始化脚本。
  • start.sh 说明: 启动服务器shell脚本。
  • stop.sh 说明: 停止服务器shell脚本。

初始化数据库 打开Navicat工具,选中数据库,右键选择运行SQL文件...,具体操作,这样数据库就初始化完成。

运行项目
在服务器/usr/myworkspace目录下,执行如下命令,即可运行项目:

chmod +x *.sh #给所有 .sh文件添加执行权限
./start.sh

3.2 Docker部署

Docker 容器化部署项目,需要创建一个 mysql 的容器,创建kuaidi的容器,再初始化一下数据库。

创建数据库容器 代码如下:

docker run -d --name mysql5.7 -e MYSQL_ROOT_PASSWORD=root -it -p 3306:3306 daocloud.io/library/mysql:5.7.7-rc

导入数据库脚本 数据库脚本kuaidi.sql内容如下:

create DATABASE kuaidi;
use kuaidi;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `kuaidi`;
CREATE TABLE `kuaidi`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人姓名',
  `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人电话',
  `kuaidi_no` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '快递单号',
  `company` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '快递公司名称拼音',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 CHARACTER SET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=Dynamic;

然后执行下面命令,就可以导入kuaidi.sql脚本:

docker exec -i mysql5.7 mysql -uroot -proot mysql < kuaidi.sql

创建kuaidi容器 执行下面命令就可以创建容器:

docker run -d -p 9082:8082 -v application.properties:/home/conf/application.properties --name kuaidi1 huaairen/kuaidi:latest

注:application.properties文件为项目的配置文件,在src/main/resources目录下;huaairen/kuaidi:latest是我打包好的镜像,直接下载就可以。

四、最后

项目功能还特别简陋,很多功能需要开发和完善。如果你也遇到类似的问题我们可以一起讨论,合作共赢哦!

作者:不安分的猿人

链接:https://juejin.im/post/5e9313ece51d4546c62f9ac4

来源:掘金