接下来我们要接入违章查询接口啦,然后就可以根据查询结果决定是否发送邮件提醒用户。
一 根据车牌获取城市参数
因为我们是使用第三方接口,违章查询稳定性依赖交管方,交管方维护升级会导致部分城市查询不稳定,所以我们按照车牌地查询违章信息。所以查询违章之前,先根据车牌前缀获取车牌所属城市需要的查询参数:
接口地址:http://v.juhe.cn/sweizhang/carPre
接口非常简单,请求参数就是key+车牌前缀((前2位)或车牌号,如:浙A;需要utf8 urlencode)。重大在解析返回的结果,并将结果作为违章查询的参数,所以我们定义一个返回结果模型类(实体类),方便提取有用信息:
/**
* 接口返回结果的模型类
* @author hao
*/
public class ReturnResultModel {
private String status; //发送状态:成功/失败
private String date; //发送时间
private Map allResult; //返回的全部具体结果
private String result; //结果
private String mode; //发送方式:短信/邮件
private int code; //返回码
private String receiver; //接收者
private String error; //出错及原因
private int level; //监控级别 1-5 最大5,用于是否向用户发短信/邮件
//省略各个属性的get/set方法
}
有了返回结果的模型类,我们可以写获取城市参数的查询类了,为了方便调用,统一写成静态方法:
/**
* 根据车牌前缀(京A)查询所在城市及需求
* @author hao
*/
public class CarCity {
public static final String url_Address = "http://v.juhe.cn/sweizhang/carPre";// 聚合数据的违章城市请求接口地址
// public static final String hphm = "京A";//车牌前缀(前2位)或车牌号,如:浙A;需要utf8 urlencode
// public static final int isNer = 0;//是否新能源,默认为0,可选参数0:否,1:是
public static final String key = "APPKEY";// 您应用APPKEY(应用详细页查询)
/**
* 根据车牌前缀(京A)查询所在城市及需求
*
* @param hphm 车牌前缀(前2位)或车牌号,如:浙A;
* @param isNer 是否新能源,默认为0
* @return
*/
public static ReturnResultModel SelectCity(String hphm, int isNer) {
String result = null;
ReturnResultModel returnResult = new ReturnResultModel();
String url = url_Address;
Map params = new HashMap();// 请求参数
params.put("hphm", hphm);// 车牌前缀(前2位)
params.put("key", key);// 应用APPKEY(应用详细页查询)
if (isNer != 0) {
params.put("isNer", isNer);// 是否新能源,默认为0,如果没有则不写入请求参数列表
}
try {
result = Utils.net(url, params, "GET");
JSONObject object = JSONObject.fromObject(result);
if(object != null) {
//纪录发送结果
returnResult.setMode("根据车牌前缀查询车辆所在城市");
returnResult.setCode(object.getInt("error_code"));
returnResult.setDate(Utils.GetNowDate());
returnResult.setResult(object.get("reason").toString());
if (object.getInt("error_code") == 0) {
returnResult.setStatus("成功");
//读取返回json中的json,如果短信发送失败,则无此项result
JSONObject resultStr = object.optJSONObject("result");
Map resultJson = new HashMap();
returnResult.setReceiver("查询车牌前缀为【"+hphm+"】的车辆所在城市为:"+resultStr.getString("city_name"));
resultJson.put("city_name", resultStr.getString("city_name"));
resultJson.put("city_code", resultStr.getString("city_code"));
resultJson.put("abbr", resultStr.getString("abbr"));
resultJson.put("engine", resultStr.getString("engine"));
resultJson.put("engineno", resultStr.getString("engineno"));
resultJson.put("classa", resultStr.getString("classa"));
resultJson.put("classno", resultStr.getString("classno"));
resultJson.put("province", resultStr.getString("province"));
returnResult.setAllResult(resultJson);
} else {
returnResult.setStatus("失败");
}
}else {
returnResult.setError("根据车牌前缀查询车辆所在城市API返回result为空!");
}
} catch (Exception e) {
e.printStackTrace();
}
return returnResult;
}
}
程序整体没有技术难度,比较麻烦的就是解析json结果,注意json格式,不然解析容易出错。这里推荐给大家一个在线json格式化/解析网站,肥常好用:https://tool.lu/json/
二 查询车辆违章信息
接口地址:http://v.juhe.cn/sweizhang/query
其中的可选参数的判断来自于我们上面写的查询城市方法,所以现在就省事了,其中还需要一个单独的违章查询信息模型类:
/**
* 违章查询具体信息 的模型类
* @author hao
*
*/
public class CarWZModel {
private String date; //违章时间
private String area; //违章地点
private String archiveno; //文书编号(不一定获取到)
private String act; //违章行为
private String code; //违章代码(仅供参考,不一定有值)
private String fen; //违章扣分(仅供参考,不一定有值)
private String money; // 违章罚款(仅供参考,不一定有值)
private String handled; // 是否处理,1处理 0未处理 空未知
private String wzcity; // 违章城市(仅供参考,不一定有值)
//省略各个属性的get/set方法
}
违章查询具体代码如下:
/**
* 车辆违章查询
* @author hao
*/
public class CarWZ {
public static final String url_Address = "http://v.juhe.cn/sweizhang/query";// 聚合数据的违章请求接口地址
public static final String key = "APPKEY";// 您应用APPKEY(应用详细页查询)
/**
* 车辆违章查询
*
* @param hphm
* 号牌号码,完整7位
* @param enginenoAll
* 完整发动机号
* @param classnoAll
* 完整车架号
* @param isNer
* 是否新能源,默认为0,可选参数0:否,1:是
* @return
*/
public static ReturnResultModel QueryWZ(String hphm, String enginenoAll, String classnoAll, int isNer) {
String result = null;
ReturnResultModel returnResult = new ReturnResultModel();
// 根据车牌前缀查询城市,用以确定违章查询的具体参数
ReturnResultModel selectCityResult = CarCity.SelectCity(hphm.substring(0, 2), isNer);
//先确定是否支持此城市的车牌违章查询!!!
if (selectCityResult.getCode() == 0) {
// 遍历所需参数
String engineno = null; // 发动机号
String classno = null; // 车架号
String city = null; // (车牌所在地)城市代码
String engine = null; // 是否需要发动机号,0:不需要 1:需要
String classa = null; // 是否需要车架号,0:不需要 1:需要
String enginenoLength = null; // 需要几位发动机号0:全部, 1-9 :需要发动机号后N位
String classnoLength = null; // 需要几位车架号0:全部 , 1-9: 需要车架号后N位
Map<String, String> ctiyMap = selectCityResult.getAllResult();
for (String key : ctiyMap.keySet()) {// 取出hashmap中所有key
if (key.equals("engine")) {
engine = ctiyMap.get(key);// 是否需要发动机号
}
if (key.equals("engineno")) {
enginenoLength = ctiyMap.get(key);// 发动机号长度
}
if (key.equals("classa")) {
classa = ctiyMap.get(key);// 是否需要车架号
}
if (key.equals("classno")) {
classnoLength = ctiyMap.get(key);// 车架号长度
}
if (key.equals("city_code")) {
city = ctiyMap.get(key);// (车牌所在地)城市代码
}
}
// 违章查询接口的具体参数
String url = url_Address;// 请求地址
Map params = new HashMap();// 请求参数
params.put("key", key);// key
params.put("hphm", hphm);// 号牌号码 完整7位
params.put("city", city);// (车牌所在地)城市代码
// 具体的发动机号和车架号的判断赋值
if (engine != null && enginenoLength != null && engine.equals("1")) {// 需要发动机号,截取所需,并加入请求参数
if (enginenoLength.equals("0")) {// 需要几位发动机号0:全部
engineno = enginenoAll;
} else { // 需要发动机号后N位
engineno = enginenoAll.substring(enginenoAll.length() - (Integer.parseInt(enginenoLength)));
}
params.put("engineno", engineno);// 所需的发动机号
}
if (classa != null && classnoLength != null && classa.equals("1")) {// 需要发动机号,截取所需,并加入请求参数
if (classnoLength.equals("0")) {// 需要几位车架号0:全部
classno = classnoAll;
} else { // 需要发车架号后N位
classno = classnoAll.substring(classnoAll.length() - (Integer.parseInt(classnoLength)));
}
params.put("classno", classno);// 所需的车架号
}
// 测试参数
// System.err.println(params);
try {
result = Utils.net(url, params, "GET");
JSONObject object = JSONObject.fromObject(result);
if (object != null) {
// 纪录发送结果
returnResult.setMode("查询车辆违章");
returnResult.setCode(object.getInt("error_code"));
returnResult.setDate(Utils.GetNowDate());
returnResult.setResult(object.get("reason").toString());
if (object.getInt("error_code") == 0) {
returnResult.setStatus("成功");
// 读取返回json中的json,如果短信发送失败,则此项result为空
JSONObject resultStr = object.optJSONObject("result");
Map resultJson = new HashMap();
resultJson.put("province", resultStr.getString("province"));// 查询省份代码
resultJson.put("city", resultStr.getString("city"));// 查询城市代码
resultJson.put("hphm", resultStr.getString("hphm"));// 查询的号牌号码
resultJson.put("hpzl", resultStr.getString("hpzl"));// 车牌类型(02:小型车,01:大型车,52:新能源小型车,51:新能源大型车)
if (resultStr.opt("lists") != null) { // 有违章情况
returnResult.setLevel(4); // 监控级别,有违章情况属于较高级别
List lists = new ArrayList();// 接收遍历的违章具体情况
JSONArray listsTemp = resultStr.optJSONArray("lists");
for (int i = 0; i < listsTemp.size(); i++) {
JSONObject obj = (JSONObject) listsTemp.opt(i);
CarWZModel carwz = new CarWZModel();// 违章信息模型类
carwz.setDate(obj.getString("date")); // 违章时间
carwz.setArea(obj.getString("area")); // 违章地点
carwz.setArchiveno(obj.getString("archiveno"));// 文书编号(不一定获取到)
carwz.setAct(obj.getString("act"));// 违章行为
carwz.setCode(obj.getString("code"));// 违章代码(仅供参考,不一定有值)
carwz.setFen(obj.getString("fen"));// 违章扣分(仅供参考,不一定有值)
carwz.setMoney(obj.getString("money")); // 违章罚款(仅供参考,不一定有值)
carwz.setHandled(obj.getString("handled"));// 是否处理,1处理 0未处理 空未知
carwz.setWzcity(obj.getString("wzcity"));// 违章城市(仅供参考,不一定有值)
lists.add(carwz);
}
// 这里是实际的违章信息所在。即 ReturnResultModel.AllResult.lists
// 对应接口返回的三层json: https://www.juhe.cn/docs/api/id/256
resultJson.put("lists", lists);
}
returnResult.setAllResult(resultJson);
} else {
returnResult.setStatus("失败");
}
} else {
returnResult.setError("车辆违章API返回result为空!");
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
returnResult.setCode(selectCityResult.getCode());
returnResult.setStatus("失败");
returnResult.setError("不支持此城市的车辆违章查询!");
}
return returnResult;
}
}
代码本身没有难度,一些需要注意的地方也都有注释,这里不做过多解释。