使用SpringBoot+Vue+快递100API搭建一个快递查询网站

news/2024/5/13 15:34:29/文章来源:https://blog.csdn.net/qq_46788415/article/details/128785262

一、需求描述

1、需求

对接快递100快递查询接口,后端使用Springboot,前端使用vue2+element-plus,搭建一个简洁、美观、适配手机端PC端且前后端分离的快递查询网站项目。

2、工具

idea

3、项目准备

前往快递100API开放平台注册账号,注册用户有50个测试单量

4、效果

4.1 PC端效果展示
在这里插入图片描述
4.2 移动端效果展示
在这里插入图片描述

二、构建前端项目

1、安装vue脚手架
2、通过vue create创建项目

2.1 在项目构建目录下进入cmd黑窗口

2.2 输入命令创建vue项目

vue create 你的项目名

操作键指引:

按空格键选中
a子母键全选
i子母键反选
回车键确定到下一步

2.3 选择Manually select features,自己选择需要的功能
在这里插入图片描述

2.4 选择需要的配置项

  • Babel 支持babel(选上)
  • TypeScript 安装ts(选上)
  • Progressive Web App (PWA) Support(一般不选)
  • Router 路由模块(选上)
  • Vuex 状态管理(需要用到就选上)
  • CSS Pre-processors css预处理器(选上)
  • Linter / Formatter 代码校验(选上)
  • Unit Testing 单元测试(一般不需要)
  • E2E Testing 端到端测试(一般不用)

2.5 选择vue的版本
该项目选择2.x

2.6 选择配置中选择了TypeScript,就会有这一步,class-style component syntax 是否使用class类风格编码,选y

在这里插入图片描述
2.7 是否使用history路由模式,默认是hash模式,hash模式会在url后面带#f符号,选y
在这里插入图片描述
2.8 选择css预处理器类型,选Saas/SCSS
在这里插入图片描述
2.9 选择一个代码校验配置支持代码风格检查和格式化,选ESLint with error prevention only

  • ESLint with error prevention only (仅具有错误预防功能)
  • ESLint + Airbnb config (Airbnb配置)
  • ESLint + Standard config (标准配置)
  • ESLint + Prettier (Prettier)

2.10 选择什么时候校验格式,选Lint on save

  • Lint on save(保存时)
  • Lint and fix on commit(提交时)

2.11 选择配置文件的位置,由于每个插件都有自己单独的配置文件,所以择第一个
在这里插入图片描述

2.12 否将当前配置选项保存起来,方便下次创建项目时使用,选n
在这里插入图片描述
2.13 vue项目创建成功

三、创建Springboot项目

1、创建一个初始化项目

在这里插入图片描述

2、创建完Spring项目后将vue项目移动到该项目下

项目结构如下图,其中kd-query-vue是vue项目
在这里插入图片描述

3、配置启动类

3.1 配置Springboot项目启动类
在这里插入图片描述
在这里插入图片描述
3.2 配置vue项目启动类
在这里插入图片描述

四、构建前端项目

1、项目结构

在这里插入图片描述

2、main.js导入项目需要的包
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//mdeditor
import VueMarkdownEditor from '@kangc/v-md-editor';
import '@kangc/v-md-editor/lib/style/base-editor.css';
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';//中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn'import Prism from 'prismjs';
//mdeditor
VueMarkdownEditor.use(vuepressTheme, {Prism,
});const app = createApp(App)
// 图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}
app.use(store).use(VueMarkdownEditor).use(router).use(ElementPlus, {locale: zhCn,}).mount('#app')
3、新建utils/request.js用于发送axios请求
import axios from 'axios'const request = axios.create({baseURL: '/api',timeout: 5000
})request.interceptors.request.use(config => {config.headers['Content-Type'] = 'application/json;charset=utf-8';if (localStorage.getItem('token')) {config.headers['token'] = localStorage.getItem('token');}return config
}, error => {return Promise.reject(error)
});request.interceptors.response.use(response => {let res = response.data;if (response.config.responseType === 'blob') {return res}if (typeof res === 'string') {res = res ? JSON.parse(res) : res}return res;},error => {console.log('err' + error);// for debugreturn Promise.reject(error)}
)export default request
4、vue.config.js配置跨域请求

请求url与后端项目的请求地址对应

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true
});
// 跨域配置
module.exports = {devServer: {open: true,host: 'localhost',port: 8081,proxy: {'/api': {target: 'http://localhost:8923',changeOrigin: true,pathRewrite: {'^/api': ''}}}}
};
5、新建views/Query.vue作为查询主页面

在这里插入图片描述

5.1、此处的页面设计

1、输入框,用于输入单号
2、按键,点击进行查询
3、选择框,用于选择快递公司
4、输入框,用于输入收件人或寄件人姓名(顺丰查询快递需要)
5、物流轨迹展示盒子,超出自动滚动
6、存放所有物流轨迹的盒子,置于物流轨迹展示盒子中

5.2 其他

1、标题为快递侠
2、版权展示,居中靠近底部

5.3 注意

1、为了兼容移动端和PC端,页面中的样式长宽高大部分使用百分比
2、对输入框进行简单校验
3、单号输入框进行回车操作后即可进行查询
4、对消息提示进行封装

物流轨迹选择的是element-plus中的 Timeline-时间线,通过自定义节点样式达到我们物流轨迹的效果,其中我们需要自定义的主要样式有内容、时间、节点颜色、节点图标,我们可以在后端通过物流轨迹内容给物流节点的颜色和图标赋值。

在这里插入图片描述

5.4 页面代码

请求后端返回的查询结果格式:

{"code": "200","msg": "成功","data": [{"content": "[河北省 石家庄市 裕华区]包裹已签收!(凭取件码)如有问题请电联:,投诉电话:0311-68048041","timestamp": "2023-01-15 11:47:56","icon": "Select","color": "green","code": 102},{"content": "[河北省 石家庄市 裕华区]您的包裹已存放至【代收点】,记得早点来【恒大雅苑百世快递恒大雅苑百世快递】取它回家!如有问题请联系:,投诉电话:0311-68048041","timestamp": "2023-01-15 10:49:00","icon": null,"color": null,"code": 101},{"content": "[河北省 石家庄市 裕华区]【石家庄化校网点】的兔兔快递员刘辉(13888888888)正在派件(可放心接听952300专属热线),投诉电话:0311-68048041。今天的兔兔,体温正常,口罩戴好,消毒到位,即将为您派件。","timestamp": "2023-01-15 08:28:57","icon": null,"color": null,"code": 101},{"content": "[河北省 石家庄市 裕华区]快件到达【石家庄化校网点】","timestamp": "2023-01-15 08:20:57","icon": null,"color": null,"code": 101},{"content": "[河北省 石家庄市 裕华区]快件离开【石家庄转运中心】已发往【石家庄化校网点】","timestamp": "2023-01-14 15:46:07","icon": null,"color": null,"code": 101},{"content": "[河北省 石家庄市 裕华区]快件到达【石家庄转运中心】","timestamp": "2023-01-14 14:18:18","icon": null,"color": null,"code": 101},{"content": "[福建省 泉州市 晋江市]快件离开【泉州转运中心】已发往【石家庄转运中心】","timestamp": "2023-01-13 03:12:30","icon": null,"color": null,"code": 101},{"content": "[福建省 泉州市 晋江市]快件到达【泉州转运中心】","timestamp": "2023-01-13 03:08:07","icon": null,"color": null,"code": 101},{"content": "[福建省 三明市 沙县]快件离开【三明转运中心】已发往【泉州转运中心】","timestamp": "2023-01-12 21:57:17","icon": null,"color": null,"code": 101},{"content": "[福建省 三明市 沙县]快件到达【三明转运中心】","timestamp": "2023-01-12 21:54:58","icon": null,"color": null,"code": 101},{"content": "[福建省 三明市 沙县]快件离开【三明市沙县一部集散点】已发往【三明转运中心】","timestamp": "2023-01-12 21:54:48","icon": null,"color": null,"code": 101},{"content": "[福建省 南平市 建阳区]快件离开【南平建阳区网点】已发往【三明市沙县一部集散点】","timestamp": "2023-01-12 13:19:45","icon": null,"color": null,"code": 101},{"content": "[福建省 南平市 建阳区]【南平建阳区网点】的练文斌(13888888888)已取件。投诉电话:0599-8500490","timestamp": "2023-01-12 13:13:45","icon": null,"color": null,"code": 101}]
}

Query.vue页面的代码如下:

<template><div class="common-layout"><el-container><el-header style="padding: 0; margin: 0"><div style="height: 60px; background: #6c8fce; padding-left: 15%"><h3 style="height:60px; line-height:60px; color: white; font-size: 26px; font-weight: 500">快递侠</h3></div></el-header><el-main style="height: calc(100vh - 120px);"><div class="user_input"><div style="position:relative; width: 70%;margin-left: 15%; margin-bottom: 30px;margin-top: 30px"><el-inputv-model="kuaidinum"class="w-50 m-2 selfinput"size="mini"placeholder="输入单号"@keyup.enter = "query"/><el-button type="primary" class="self_btn" :icon="Search" @click="query">查询</el-button></div><div style="width: 70%;margin-left: 15%; margin-bottom: 30px"><el-select v-model="kuaidicom" class="m-2" placeholder="选择快递公司"><el-optionv-for="item in options":key="item.value":label="item.label":value="item.value"/></el-select></div><div style="width: 70%;margin-left: 15%; margin-bottom: 30px;margin-top: 30px"><el-input v-model="phone" placeholder="收寄件人电话号码(顺丰必填)" /></div></div><div class="trackBox" style="width: 70%; margin-left: 15%; height: 400px; overflow: auto"><el-timeline><el-timeline-itemv-for="(item,index) in trackData":key="index":icon="item.icon":color="item.color":timestamp="item.timestamp">{{ item.content }}</el-timeline-item></el-timeline></div></el-main><el-footer style="height: 60px"><p style="height: 60px; line-height:60px; text-align: center; font-weight: 300; font-size: 12px">©2023 http://www.roud.top</p></el-footer></el-container></div>
</template><script>
import request from "../utils/request";
import {ElMessage} from "element-plus";export default {name: "Query",data(){return{//快递公司选择框数据,value为发送表单时的值,键为对应的v-model,value值参考快递100API快递公司编码表(https://api.kuaidi100.com/manager/openapi/download/kdbm.do)options : [{value: 'zhongtong',label: '中通快递',},{value: 'jtexpress',label: '极兔速递',},{value: 'yunatong',label: '圆通速递',},{value: 'shunfeng',label: '顺丰速运',},{value: 'yunda',label: '韵达快递',},{value: 'shentong',label: '申通快递',},{value: 'youzhengguonei',label: '邮政速递',},{value: 'ems',label: 'EMS',},{value: 'jd',label: '京东物流',},{value: 'debangkuaidi',label: '德邦快递',},{value: 'debang物流',label: '德邦物流',},{value: 'fengwang',label: '丰网速运',},{value: 'sxjdfreight',label: '顺心捷达',},{value: 'zhaijisong',label: '宅急送',},{value: 'danniao',label: '丹鸟',},{value: 'shunfengkuaiyun',label: '顺丰快运',},{value: 'shunfengkuaiyun',label: '顺丰快运',},{value: 'disifang',label: '递四方',},{value: 'zhuanyunsifang',label: '转运四方',},{value: 'ups',label: 'UPS',},{value: 'jinguangsudikuaijian',label: '京广速递',},{value: 'yimidida',label: '壹米滴答',},{value: 'shunfengkuaiyun',label: '顺丰快运',}],kuaidinum: "",kuaidicom: "",phone: "",trackData: [],form: {}}},methods:{//成功提示showSuccessMessage(msg){ElMessage.success({message: msg,});},//失败提示showFailMessage(msg){ElMessage.error({message: msg,});},//警告提示showWarningMessage(msg){ElMessage.warning({message: msg,});},//点击查询执行的方法query(){this.form = {}this.trackData = []//判断输入是否为空if(this.kuaidinum === "" || this.kuaidinum == null || this.kuaidicom == null || this.kuaidicom === ""){this.showWarningMessage("请输入准确的信息!");return;}//对单号进行简单检验var reg = /^[a-zA-Z]*[0-9]+$/if(!reg.test(this.kuaidinum)){this.showWarningMessage("请输入正确的单号!");return;}this.form.num = this.kuaidinum;this.form.com = this.kuaidicom;if("shunfeng" === this.kuaidicom){this.form.phone = this.phone;}//发送查询请求request.post("/query/kd100", this.form).then(res => {//处理查询结果let data = res["data"];if((data[0])["code"] === 101){(data[0])["color"] = "green";}if(data.length > 1 && (data[data.length-1])["code"] === 101){(data[data.length-1])["icon"] = "ArrowDownBold"}if((data[0])["code"] === 101 || (data[0])["code"] === 102){this.showSuccessMessage("查询成功");}else {this.showWarningMessage("查询异常")}this.trackData = data.reverse();});}}
}
</script><style>*{padding: 0;margin: 0;}.el-select{width: 100%;}.selfinput{width: 90% !important;}.self_btn{position: absolute;right: 0 !important;}::-webkit-scrollbar {height: 6px;width: 3px;}::-webkit-scrollbar-track {background-color: transparent;}::-webkit-scrollbar-thumb {box-shadow: inset 0 0 0 rgba(240, 240, 240, .5);border-radius: 2px;background-color: rgba(240, 240, 240, .5);}
</style>
6、router/index.js配置路由

配置默认路由及/kdx/query为该查询页面

import { createRouter, createWebHistory } from 'vue-router'
import Query from "@/views/Query";const routes = [{path: '/kdx/query',name: 'query',component: Query,},{path: '/',name: 'q',component: Query,}]
const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
})export default router

五、构建后端项目

1、项目结构

在这里插入图片描述

2、pom.xml导入所需依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>top.roud</groupId><artifactId>kd-query100</artifactId><version>0.0.1-SNAPSHOT</version><name>kd-query100</name><description>kd-query100</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.6</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.6</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.10</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories><pluginRepositories><pluginRepository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></pluginRepository><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></pluginRepository></pluginRepositories></project>
3、src/main/resources/application.yml配置文件

这里简单配置一下项目端口

server:port: 8923
4、新建src/main/java/top/roud/kdquery100/utils包存放工具类
4.1 http包

用于存放http请求工具类

目录结构如下:
在这里插入图片描述

4.1.1 HttpResult请求结果封装类

package top.roud.kdquery100.utils.http;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @description : TODO* @author: roud* @date: 2023/1/4* @version:*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HttpResult {private int status;private String body;private String error;
}

4.1.2 HttpUtil请求工具类

package top.roud.kdquery100.utils.http;import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;/*** @description : TODO* @author: roud* @date: 2023/1/4* @version:*/
public class HttpUtil {public static HttpResult doPost(String url, Object obj, int connectTimeout, int socketTimeout) {CloseableHttpClient httpClient = HttpClientBuilder.create().build();CloseableHttpResponse resp = null;HttpResult result = new HttpResult();try {Map<String, String> params = ObjectToMapUtil.objectToMap(obj);HttpPost httpPost = new HttpPost(url);RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();httpPost.setConfig(requestConfig);if (params != null && params.size() > 0) {List<NameValuePair> list = new ArrayList();Iterator var11 = params.entrySet().iterator();while(var11.hasNext()) {Map.Entry<String, String> entry = (Map.Entry)var11.next();list.add(new BasicNameValuePair((String)entry.getKey(), (String)entry.getValue()));}
//                httpPost.setHeader("Content-Type","application/x-www-form-urlencoded");httpPost.setEntity(new UrlEncodedFormEntity(list, "UTF-8"));}resp = httpClient.execute(httpPost);String body = EntityUtils.toString(resp.getEntity(), "UTF-8");int statusCode = resp.getStatusLine().getStatusCode();result.setStatus(statusCode);result.setBody(body);} catch (Exception var21) {var21.printStackTrace();} finally {if (null != resp) {try {resp.close();} catch (IOException var20) {var20.printStackTrace();}}}return result;}
}

4.1.3 ObjectToMapUtil

package top.roud.kdquery100.utils.http;import java.lang.reflect.Field;
import java.util.*;/*** @description : TODO* @author: roud* @date: 2023/1/4* @version:*/
public class ObjectToMapUtil {public ObjectToMapUtil() {}public static Map<String, String> objectToMap(Object obj) throws IllegalAccessException {if (obj == null) {return null;} else {Map<String, String> map = new HashMap();List<Field> allField = getAllField(obj);String fieldName;String fieldValue;for(Iterator var3 = allField.iterator(); var3.hasNext(); map.put(fieldName, fieldValue)) {Field field = (Field)var3.next();field.setAccessible(true);fieldName = field.getName();fieldValue = "";if (field.getType() == String.class || field.getType() == Integer.class || field.getType() == Integer.TYPE) {fieldValue = field.get(obj) == null ? "" : field.get(obj).toString();}}return map;}}private static List<Field> getAllField(Object obj) {List<Field> fieldList = new ArrayList();for(Class clazz = obj.getClass(); clazz != null; clazz = clazz.getSuperclass()) {fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));}return fieldList;}
}
4.2 md包

主要存放md5加密的工具类
目录结构:
在这里插入图片描述
DigestUtil 加密工具类

package top.roud.kdquery100.utils.md;import org.springframework.util.DigestUtils;import java.io.IOException;
import java.io.UnsupportedEncodingException;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
public class DigestUtil {public static String md5(String str) {String md5 = "";try {md5 = DigestUtils.md5DigestAsHex(str.getBytes("utf-8"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}return md5;}
}
4.3 rusult包

主要存放返回给用户的结果的封装类
目录结构:
在这里插入图片描述
4.3.1 StatusCode 返回结果状态码枚举类

package top.roud.kdquery100.utils.result;/*** @description : TODO* @author: roud* @date: 2023/1/6* @version:*/
public enum StatusCode {SUCCESS("200","成功"),ERROR("500","服务器错误"),FAIL("501","查无结果"),ACCOUNT_CHECK_FAIL("301","账号校验失败");private String code;public String getCode() {return code;}private String message;public String getMessage() {return message;}StatusCode(String code, String message) {this.code = code;this.message = message;}}

4.3.2 StatusCode返回结果类

package top.roud.kdquery100.utils.result;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @description : TODO* @author: roud* @date: 2023/1/6* @version:*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {private String code;private String msg;private Object data;public Result(StatusCode sc, Object data){this.code = sc.getCode();this.msg = sc.getMessage();this.data = data;}
}
5、新建src/main/java/top/roud/kdquery100/entity包存放实体类

目录结构如下:
在这里插入图片描述
根据快递100实时查询API技术文档的参数要求构建请求实体类,包括请求、请求参数、请求结果

在这里插入图片描述
5.1 QueryParam 查询参数类

package top.roud.kdquery100.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QueryParam {private String com;private String num;private String phone;private String from;private String to;private String resultv2;private String show;private String order;
}

5.2 QueryRequest 查询请求类

package top.roud.kdquery100.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QueryRequest {private String customer;private String sign;private String param;
}

5.3 QueryResult 查询结果类

package top.roud.kdquery100.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @description : TODO* @author: roud* @date: 2023/1/19* @version:*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QueryResult {private String content;private String timestamp;private String icon;private String color;/*** 101  在途中* 102  已签收* 103  查无结果* 104  服务器错误*/private Integer code;}
6、业务类编写

目录结构:
在这里插入图片描述
6.1 QueryServiceImpl 查询业务接口

package top.roud.kdquery100.service.impl;import top.roud.kdquery100.entity.QueryParam;
import top.roud.kdquery100.utils.result.Result;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
public interface QueryServiceImpl {public Result queryKdTrack(QueryParam param);
}

6.2 QueryService 查询业务实现类

需要前往快递100API开放平台注册账号,注册用户有50个测试单量。在我的信息-企业信息中获取授权Key和customer替换填入代码中
在这里插入图片描述
代码如下,根据完成的前端项目所需的JSON格式进行构造:

package top.roud.kdquery100.service;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import top.roud.kdquery100.entity.QueryParam;
import top.roud.kdquery100.entity.QueryRequest;
import top.roud.kdquery100.entity.QueryResult;
import top.roud.kdquery100.service.impl.QueryServiceImpl;
import top.roud.kdquery100.utils.http.HttpResult;
import top.roud.kdquery100.utils.http.HttpUtil;
import top.roud.kdquery100.utils.md.DigestUtil;
import top.roud.kdquery100.utils.result.Result;
import top.roud.kdquery100.utils.result.StatusCode;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
@Service
public class QueryService implements QueryServiceImpl{@Overridepublic Result queryKdTrack(QueryParam param) {String paramStr = JSONObject.toJSONString(param);QueryRequest queryRequest = new QueryRequest();queryRequest.setParam(paramStr);queryRequest.setCustomer("快递100API企业管理后台customer");String sign = DigestUtil.md5(paramStr + "快递100API企业管理后台key" + "快递100API企业管理后台customer").toUpperCase();queryRequest.setSign(sign);ArrayList<QueryResult> list = new ArrayList<>();try{HttpResult httpResult = HttpUtil.doPost("https://poll.kuaidi100.com/poll/query.do", queryRequest, 3000, 300);if(httpResult.getStatus() == 200){String body = httpResult.getBody();JSONObject jsonObject = JSONObject.parseObject(body);if(StringUtils.contains(body, "\"status\":\"200\"")){JSONArray datas = jsonObject.getJSONArray("data");List<QueryResult> resList = datas.stream().map(o -> {QueryResult queryResult = new QueryResult();String ftime = ((JSONObject) JSONObject.toJSON(o)).getString("ftime");String content = ((JSONObject) JSONObject.toJSON(o)).getString("context");queryResult.setContent(content);if(StringUtils.contains(content,"签收")){queryResult.setIcon("Select");queryResult.setColor("green");queryResult.setCode(102);}else {queryResult.setCode(101);}queryResult.setTimestamp(ftime);return queryResult;}).collect(Collectors.toList());return new Result(StatusCode.SUCCESS,resList);}else{return getResultList(list,"查无结果", "orange", "SemiSelect", 103, StatusCode.FAIL);}}}catch (Exception e){return getResultList(list,"服务器异常,请联系管理员修复", "red", "CloseBold",104, StatusCode.ERROR);}return getResultList(list,"服务器异常,请联系管理员修复", "red", "CloseBold",104, StatusCode.ERROR);}private Result getResultList(ArrayList<QueryResult> list, String content, String color, String icon, Integer code, StatusCode sc) {String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));QueryResult queryResult = new QueryResult();queryResult.setTimestamp(time);queryResult.setContent(content);queryResult.setIcon(icon);queryResult.setColor(color);queryResult.setCode(code);list.add(queryResult);return new Result(sc, list);}
}
7、 控制层

目录结构:
在这里插入图片描述
QueryController 查询控制层类,定义的接口入口为/query/kd100

package top.roud.kdquery100.controller;import org.springframework.beans.factory.annotation.Autowired;
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 top.roud.kdquery100.entity.QueryParam;
import top.roud.kdquery100.service.impl.QueryServiceImpl;
import top.roud.kdquery100.utils.result.Result;/*** @description : TODO* @author: roud* @date: 2023/1/18* @version:*/
@RestController
@RequestMapping("query")
public class QueryController {@Autowiredprivate QueryServiceImpl queryService;@PostMapping("/kd100")public Result query(@RequestBody QueryParam param){return queryService.queryKdTrack(param);}
}

六、前后端联调测试

先启动后端项目,再启动前端项目。
实现效果如下:
在这里插入图片描述
项目完成,撒花~~~

七、项目地址

点此进入该项目的github仓库地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_899341.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新浪云服务搭建个人web网站入门

废话不说直接开始&#xff1a; 一&#xff1a; 首先你要申请个新浪云的账户。为什么用它就是因为它免费&#xff01;免费&#xff01;免费&#xff01; 注册地址&#xff1a;http://www.sinacloud.com/public/login/inviter/gaimrn-mddmzeKWrhKW3roGufWh_iKOufnzQdg.html 他…

[含论文+答辩PPT+源码等]基于javaweb实现的高校社团信息管理平台网站

下载&#xff1a;https://download.csdn.net/download/m0_68856272/85052024 项目介绍: 《基于javaweb实现的高校社团信息管理平台网站》 系统说明: 使用技术&#xff1a; 前端使用技术&#xff1a;JSP,HTML5,CSS3、JavaScript等 后台使用技术&#xff1a;Servlet、JDBC等 …

[含任务书+答辩PPT+源码等]B2C婚纱摄影网站的设计与实现S2SH

下载&#xff1a;https://download.csdn.net/download/m0_68856272/85052024 项目介绍: 《B2C婚纱摄影网站的设计与实现S2SH》 系统说明: 《B2C婚纱摄影网站的设计与实现S2SH》该项目采用技术jsp、strust2、Spring、hibernate、tomcat服务器、mysql数据库 开发工具eclipse&am…

[教程+论文+答辩PPT+开题报告+源码等]基于javaweb的旅游网站

下载&#xff1a;https://download.csdn.net/download/m0_68856272/85052024 项目介绍: 《基于javaweb实现的旅游网》 系统说明: 前端使用技术&#xff1a;JSP,HTML5,CSS3、JavaScript、jQuery、bootstrap、Validform.js等 后台使用技术&#xff1a;Servlet、JDBC等 数据库…

三个网站让你成为Linux命令行高手

Linux的命令行是通向Linux高级应用的必经之路&#xff0c;Linux系统管理员、开发者都是学习对象。Susan Linton向我们推荐了三个学习Linux命令行的网站&#xff0c;现在介绍给大家&#xff1a;0. LinuxCommand  LinuxCommand是一个学习Linux命令行最好的网站之一。网站分为&a…

ChinaHR(智联招聘)网站的一个小bug

测试空间旗下大头针出品 这几天有个学生面试&#xff0c;笔试的时候让他测试一下ChinaHR&#xff08;智联招聘&#xff09;网站,找网站的bug。 找了半天都是找了些界面方面。 像网站的测试&#xff0c;一般主要关注的网站的性能和功能以及内容。 网站的性能短时间我们不容易…

基于SSM java的超市销售网站

介绍&#xff1a;springspringmvcmybatismysqleclipse。 系统实现 前台管理 1)超市信息自定义。关于超市的信息介绍。 2)登录功能。如果是超市会员&#xff0c;填写用户名、密码即可享受商城服务。 3)注册功能。顾客首先要注册为超市的会员。 4)订单管理。会员可查看自己的消费…

基于JSP java音乐网站

介绍: jsp+servlet+mysql+eclipse技术 效果截图:

基于SSM java jsp汽车俱乐部网站

介绍&#xff1a; springspringmvcmybatismysqleclipse。 截图&#xff1a; 数据库表&#xff1a; CREATE TABLE adminuser (uid int(11) NOT NULL AUTO_INCREMENT,username varchar(255) DEFAULT NULL COMMENT ‘管理员姓名’,password varchar(255) DEFAULT NULL COMMENT ‘…

自定义ActionBar样式并生成相应主题xml的网站

http://jgilfelt.github.io/android-actionbarstylegenerator/

[转载]说说大型高并发高负载网站的系统架构

转载请保留出处&#xff1a;俊麟 Michael’s blog (http://www.toplee.com/blog/?p71) Trackback Url : http://www.toplee.com/blog/wp-trackback.php?p71 我在CERNET做过拨号接入平台的搭建&#xff0c;而后在Yahoo&3721从事过搜索引擎前端开发&#xff0c;又在MOP处理…

利用dns解析来实现网站的负载均衡

参看的地址&#xff1a;https://segmentfault.com/a/1190000002578457 当网站的访问量大了就会考虑负载均衡&#xff0c;这也是每一个架构师的基本功了&#xff0c;其基本地位就相当于相声里的说学逗唱&#xff0c;活好不好就看这个了 :) 传统的负载均衡思路是单点的&#xff…

web连接数据库,创建一个网站

期末作业&#xff1a; 用visual studio连接数据库&#xff0c;创建网页 包含功能如图所示&#xff1a; 以下是做出来的效果。。。 老师说界面太丑了。。。辛辛苦苦做的。。。 就到这里吧 若有需要&#xff0c;直接dd我就行啦 如果我能及时看到的话

Django入门笔记(一)_建站基本流程

Django入门笔记&#xff08;一&#xff09;_建站基本流程 逻辑总览基本环境虚拟配置命令行创建模型URLconf视图编写模板编写全局settings测试超级用户 逻辑总览 基本环境 # 安装python3# 安装virtualenv pip3 install virtualenv虚拟配置 # 生成激活 # win virtualenv -p pyt…

存图网站

http://imagehosting.biz

Wordress博客网站查看文章时显示进度条

可以在Wordress的插件里面下载 Post Reading Progress 插件 安装完之后&#xff0c;可以在后台的&#xff1a; 设置->读取进度条->中设置 如下图 我们就可以设置进度条相对应的功能

20多个漂亮的使用jQuery交互的网站设计欣赏

jQuery是使用最多的JS库之一&#xff0c;它有很多优点&#xff0c;比如轻量、易用、完善的Ajax、良好的浏览器兼容&#xff0c;以及它有健壮的选择器等。这些优点使得jQuery成为帮助前端开发人员的有力工具。越来越多的大型网站开始使用jQuery及其插件实现其前端交互。 这里&am…

老旧asp.net网站搬家导致的反编译实例1

2020年12月&#xff0c;朋友的海外win2008r2的服务器就要到期了&#xff0c;上面也没几个站了&#xff0c;租服务器就不合算了。3个人合伙买了一个海外的虚拟主机&#xff0c;算下来&#xff0c;平均下来每人每年一百不到。无限流量、无限网站、无限空间&#xff0c;放一些小站…

老旧asp.net网站搬家导致的反编译实例2

https://blog.csdn.net/liufile/article/details/112001740 前面提到了&#xff0c;迁移老破旧asp.net网站出现的兼容性问题&#xff0c;在反编译dll&#xff0c;修补了相应代码&#xff0c;编译的dll出现&#xff0c;新的错误&#xff1a; 未能加载文件或程序集“NVelocity,…

老旧asp.net网站搬家导致的反编译实例3

https://blog.csdn.net/liufile/article/details/112002023 前一篇已经介绍了&#xff0c;如何解决无源代码的老旧asp.net的兼容性或小范围修改问题&#xff0c;但是&#xff0c;对于我调试的网站&#xff0c;又出现新的问题&#xff0c;就是功能有缺失&#xff0c;这可能是反…