做它的原因
接了老师一个项目,老师要我先去收集各个省市县级的边界座标以及中心城区范围,然后老师要用R语言去画图调用。然后我就直接百度去下载现成的数据,但是老师说不行,要最新的,以前网上的数据都是以前的。现在好多行政区县都已经更新了。近几年的数据还没有。所以只能自己做了。也能确保数据的准确性。
特地强调。确实echarts可以画地图。但是里面的边界数据并不精确。如果你需要做的项目是边界必须特别精确的,而是最新的。你得自己获取。echarts里的china.js数据已经老了。
前期准备
首先我们需要城市信息。哪里来这些城市的信息呢?第一个想到的是百度文科直接下载,第二个是爬虫。但是老师说,还是爬虫好,让我把中国天气预报网上的数据爬下来。那里的城市信息准确。然后我就用八爪鱼爬了(懒得自己写爬虫。。。)。爬下来以后发现。数据不对。天气预报网上的地方确实是最新的。但是天气预备有个特点。相邻区域就不一定会报。比如上海市中心就包含了好几个区。其次用风景区代替城市。导致我查找的地址不准确。做出来画的地图不对。所以,我还是去百度文库里下了一份2016年的省市县级的名称。
不过数据不准确还是得做处理。可以看见,首先,各个省没有分开。意思是我省的数据也是需要的。然后应该纯在省,空,空这样的数据元。还有安庆这里就写了安庆。有些百度是可以直接出来的。但是还有的不行比如巢湖。这个城市你在查找边界范围的时候不输入巢湖市出不来。所以我们需要对这些数据做处理。把省级分开。把名字补全,那些结尾不是区,镇,县,街道,旗(蒙古的比较多)的数据,尾部补上市,便于查找。把重复的给规整,市级是三沙市就是三沙市,县级下面不应该再来个三沙市。
当然这么做还有个前提,要读取excel文件。
我这里采用的是个包pio-3.16。具体方式是参考 http://blog.csdn.net/sinat_29581293/article/details/52122191 它的。
然后展示下,我修改数据的文件
package dealWithSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
*
* @描述:测试excel读取
*
*/
public class importExcel
{
/** 总行数 */
private int totalRows= 0;
/** 总列数 */
private int totalCells= 0;
/** 错误信息 */
private String errorInfo;
/** 构造方法 */
public importExcel()
{
}
public int getTotalRows()
{
return totalRows;
}
public int getTotalCells()
{
return totalCells;
}
public String getErrorInfo()
{
return errorInfo;
}
public boolean validateExcel(String filePath)
{
/** 检查文件名是否为空或者是否是Excel格式的文件 */
if(filePath == null || !(WDWUtil.isExcel2003(filePath) || WDWUtil.isExcel2007(filePath)))
{
errorInfo= "文件名不是excel格式";
return false;
}
/** 检查文件是否存在 */
File file= new File(filePath);
if(file == null || !file.exists())
{
errorInfo= "文件不存在";
return false;
}
return true;
}
public List<List<String>> read(String filePath)
{
List<List<String>> dataLst= new ArrayList<List<String>>();
InputStream is= null;
try
{
/** 验证文件是否合法 */
if(!validateExcel(filePath))
{
System.out.println(errorInfo);
return null;
}
/** 判断文件的类型,是2003还是2007 */
boolean isExcel2003= true;
if(WDWUtil.isExcel2007(filePath))
{
isExcel2003= false;
}
/** 调用本类提供的根据流读取的方法 */
File file= new File(filePath);
is= new FileInputStream(file);
dataLst= read(is,isExcel2003);
is.close();
}catch (Exception ex)
{
ex.printStackTrace();
}finally
{
if(is != null)
{
try
{
is.close();
}catch (IOException e)
{
is= null;
e.printStackTrace();
}
}
}
/** 返回最后读取的结果 */
return dataLst;
}
public List<List<String>> read(InputStream inputStream, boolean isExcel2003)
{
List<List<String>> dataLst= null;
try
{
/** 根据版本选择创建Workbook的方式 */
Workbook wb= null;
if(isExcel2003)
{
wb= new HSSFWorkbook(inputStream);
}else
{
wb= new XSSFWorkbook(inputStream);
}
dataLst= read(wb);
}catch (IOException e)
{
e.printStackTrace();
}
return dataLst;
}
private List<List<String>> read(Workbook wb)
{
List<List<String>> dataLst= new ArrayList<List<String>>();
/** 得到第一个shell */
Sheet sheet= wb.getSheetAt(0);
/** 得到Excel的行数 */
this.totalRows= sheet.getPhysicalNumberOfRows();
/** 得到Excel的列数 */
if(this.totalRows >= 1 && sheet.getRow(0) != null)
{
this.totalCells= sheet.getRow(0).getPhysicalNumberOfCells();
}
/** 循环Excel的行 */
for(int r= 0; r < this.totalRows; r++)
{
Row row= sheet.getRow(r);
if(row == null)
{
continue;
}
List<String> rowLst= new ArrayList<String>();
/** 循环Excel的列 */
for(int c= 0; c < this.getTotalCells(); c++)
{
Cell cell= row.getCell(c);
String cellValue= "";
if(null != cell)
{
// 以下是判断数据的类型
switch(cell.getCellType())
{
case HSSFCell.CELL_TYPE_NUMERIC: // 数字
cellValue= cell.getNumericCellValue() + "";
break;
case HSSFCell.CELL_TYPE_STRING: // 字符串
cellValue= cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
cellValue= cell.getBooleanCellValue() + "";
break;
case HSSFCell.CELL_TYPE_FORMULA: // 公式
cellValue= cell.getCellFormula() + "";
break;
case HSSFCell.CELL_TYPE_BLANK: // 空值
cellValue= "";
break;
case HSSFCell.CELL_TYPE_ERROR: // 故障
cellValue= "非法字符";
break;
default:
cellValue= "未知类型";
break;
}
}
rowLst.add(cellValue);
}
/** 保存第r行的第c列 */
dataLst.add(rowLst);
}
return dataLst;
}
// 到处表格
public void write(List<List<String>> source)
{
// 第一步,创建一个webbook,对应一个Excel文件
HSSFWorkbook wb= new HSSFWorkbook();
// 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
HSSFSheet sheet= wb.createSheet("省市");
// 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
HSSFRow row= sheet.createRow((int) 0);
// 第四步,创建单元格,并设置值表头 设置表头居中
HSSFCellStyle style= wb.createCellStyle();
style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
HSSFCell cell= row.createCell((short) 0);
cell.setCellValue("省");
cell.setCellStyle(style);
cell= row.createCell((short) 1);
cell.setCellValue("市");
cell.setCellStyle(style);
cell= row.createCell((short) 2);
cell.setCellValue("县");
cell.setCellStyle(style);
// 第五步,写入实体数据 实际应用中这些数据从数据库得到,
List<List<String>> list= source;
List<String> temp=new ArrayList<String>();
for(int i= 0; i < list.size(); i++)
{
row= sheet.createRow((int) i + 1);
temp=list.get(i);
// 第四步,创建单元格,并设置值
for(int j=0;j<temp.size();j++)
{
row.createCell((short) j).setCellValue(temp.get(j));
}
}
// 第六步,将文件存到指定位置
try
{
FileOutputStream fout= new FileOutputStream("E:/模版.xls");
wb.write(fout);
fout.close();
}catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception
{
importExcel poi= new importExcel();
// List<List<String>> list = poi.read("d:/aaa.xls");
List<List<String>> list= poi.read("E:/QQ文件/中国各省市邮政编码、电话区号大全.xls");
if(list != null)
{
for(int i= 0; i < list.size(); i++)
{
System.out.print("第" + (i) + "行");
List<String> cellList= list.get(i);
for(int j= 0; j < cellList.size(); j++)
{
// System.out.print(" 第" + (j + 1) + "列值:");
System.out.print(" " + cellList.get(j));
}
System.out.println();
}
}
}
}
class WDWUtil
{
public static boolean isExcel2003(String filePath)
{
return filePath.matches("^.+\\.(?i)(xls)$");
}
public static boolean isExcel2007(String filePath)
{
return filePath.matches("^.+\\.(?i)(xlsx)$");
}
}
package dealWithSource;
import java.util.ArrayList;
import java.util.List;
//处理表单。把表格调节成标准格式 (省,市,县)
public class createTable
{
public static void main(String[] args)
{
importExcel poi= new importExcel();
// 省 市 县
List<List<String>> result= new ArrayList<List<String>>();
try
{
List<List<String>> list= poi.read("E:/全国县级以上城市行政区划表.xls");
if(list != null)
{
//上一个省的名字,用于把省分隔开
String previousProvince="";
for(int i= 0; i < list.size(); i++)
{
List<String> cellList= list.get(i);
List<String> res= new ArrayList<String>();
String province=cellList.get(0).trim();
String city= dealWith(cellList.get(1).trim());
String country=dealWith(cellList.get(2).trim());
if(!previousProvince.equals(province))
{
previousProvince=province;
//当遇到一个新的省的时候,那一行,就一个省字段,市,县为空
res.add(province);
res.add("");
res.add("");
result.add(res);
res= new ArrayList<String>();
}
//省和市的照常添加
res.add(province);
res.add(city);
if(country.equals("")||country.equals(city))
{
res.add("");// 县为空
}
else
{
res.add(country);
}
System.out.println(province+" "+city+" "+country);
result.add(res);
}
}
poi.write(result);
}catch (Exception e)
{
poi.write(result);
e.printStackTrace();
}
}
//给没加市的城市加上市,便于查找相应地区
public static String dealWith(String result)
{
result=result.trim();
if(result==null||result.equals(""))
return result;
if(result.substring(result.length()-1).equals("镇")||result.substring(result.length()-1).equals("县")||result.substring(result.length()-1).equals("街道")||result.substring(result.length()-1).equals("区")||result.substring(result.length()-1).equals("旗")||(result.length()>4&&result.substring(result.length()-3).equals("自治州"))||(result.length()>2&&result.substring(result.length()-2).equals("街道")))
return result;
else
{
return result.trim()+"市";
}
}
}
然后这个文件用java application运行下,就可得到我要的初始数据模版了。
这里可以说明我为什么要先人为处理数据,而不是放到后面获取边界时一起处理。因为,减少bug的判断。万一后面出了很多bug要改,至少我能排除,我这里没有bug。也能确保后期万一我处理失败,这里每个数据元名字不会重复的再做处理。
然后我们就进入了工作阶段了跑数据,获取市中心以及边界。
什么是行政中心?不应该是简单的获取边界后取一个重心就当作城市中心的。而是应该以行政中心为准。大多数行政中心独有个特点。就是都是人民政府,如浙江省人民政府,这是省级的,到市级就有杭州市人民政府,县级有县级的人们政府。街道没有人民政府。自治州的是政府。开发区的只有管理委员会。当然,当你跑完数据后你也会发现一些特例,但是觉得不会多。到时候百度查找修改下就好了。
然后怎么获取数据呢?通过百度http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition 获取座标
代码如下 先去百度地图获取个ak,然后下载个数据包
导入到程序里。(其实,这个不用服务器,直接用java application也可以运行出来的)
package service;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class Parser_Tool
{
/**
* post 获取 rest 资源
*
* @param url
* @param name_value_pair
* @return
* @throws IOException
*/
public static String doPost(String url, List<NameValuePair> nameValuePair) throws IOException
{
String body= "{}";
DefaultHttpClient httpclient= new DefaultHttpClient();
try
{
HttpPost httpost= new HttpPost(url);
httpost.setEntity(new UrlEncodedFormEntity(nameValuePair,StandardCharsets.UTF_8));
HttpResponse response= httpclient.execute(httpost);
HttpEntity entity= response.getEntity();
body= EntityUtils.toString(entity);
}finally
{
httpclient.getConnectionManager().shutdown();
}
return body;
}
/**
* get 获取 rest 资源
*
* @param url
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public static String doGet(String url) throws ClientProtocolException, IOException
{
String body= "{}";
DefaultHttpClient httpclient= new DefaultHttpClient();
try
{
HttpGet httpget= new HttpGet(url);
HttpResponse response= httpclient.execute(httpget);
HttpEntity entity= response.getEntity();
body= EntityUtils.toString(entity);
}finally
{
httpclient.getConnectionManager().shutdown();
}
return body;
}
//把x,y座标区分开
public static String[] dealWith(String result)
{
int x= result.indexOf("\"lng\":");
int y= result.indexOf(",\"lat\":");
int end= result.indexOf("},\"precise");
if(x == -1)
{
String[] answer= { "", "" };
return answer;
}
String xs= result.substring(x + 6,y);
String ys= result.substring(y + 7,end);
String[] answer= { xs, ys };
return answer;
}
}
这是个获取座标的工具类。
然后我们就解决边界了。通过我是通过js调用百度地图api去获取的。
代码如下
这是jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>获取地区轮廓线</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.3">
</script>
<style type="text/css">
body {
font-size: 13px;
margin: 10px
}
#container {
width: 800px;
height: 500px;
border: 1px solid gray
}
</style>
</head>
<body>
<div id="container"></div>
<br /> 输入省、直辖市或县名称:
<script type="text/javascript">
var map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(116.403765, 39.914850), 5);
map.addControl(new BMap.NavigationControl({
type : BMAP_NAVIGATION_CONTROL_SMALL
}));
map.enableScrollWheelZoom();
function getBoundary()
{
var bdary = new BMap.Boundary();
var name = document.getElementById("districtName").value;
bdary.get(name, function(rs) { //获取行政区域
map.clearOverlays(); //清除地图覆盖物
var count = rs.boundaries.length; //行政区域的点有多少个
for (var i = 0; i < count; i++) {
var ply = new BMap.Polygon(rs.boundaries[i], {
strokeWeight : 2,
strokeColor : "#ff0000"
}); //建立多边形覆盖物
map.addOverlay(ply); //添加覆盖物
map.setViewport(ply.getPath()); //调整视野
}
var answer=document.getElementById("result");
answer.value=rs.boundaries;
});
}
setTimeout(getBoundary,1);
setTimeout(a,5000);
// var i=0;
function a()
{
//if(document.getElementById("result").value!="")
document.getElementById("fom").submit();
//else
//{
// setTimeout(a,200);
// }
}
</script>
<form id="fom" action="excel" method="post">
<input type="text" id="districtName" name="districtName" style="width: 80px" value="${result}">
<input id="result" name="result" value=""></input>
<input onclick="getBoundary()" type="button" id="start" value="获取轮廓线"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
我这里是定时。5秒后自动提交数据。理由是,搜索需要时间。最晚5秒内肯定能好。不能设置一获取数据就传递到servlet里去,因为缺失存在一些找不到边界的。可能是百度地图里没有边界,或者省政府名字不正确,简写等导致的。这时候如果设置一获取数据就传递就会卡主。不动,除非手工按。所以我采用设置5秒自动提交。万一没有数据也不等了。直接提交。说明那个城市是有问题的。
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.WebExcel;
@WebServlet("/excel")
public class servlce extends HttpServlet
{
static WebExcel work;
static boolean first=true;
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String local= request.getParameter("result");
//String now= new String(request.getParameter("districtName").getBytes("iso-8859-1"), "utf-8");
String next="";//下一个查找的城市
if(first)
{
first=false;
work= new WebExcel();
}
next= work.doWork(local);
if(next == "over")
return;
request.setAttribute("result",next);
request.getRequestDispatcher("baiduMap.jsp").forward(request,response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request,response);
}
}
package service;
import java.util.ArrayList;
import java.util.List;
import Dao.CountryDao;
public class WebExcel
{
int i = 0;
static List<List<String>> list;
static List<List<String>> result;
String place;
Excel poi;
CountryDao dao;
// 1.地理编码服务,即根据地址来查经度纬度
String ak = "你百度获取的ak";
String url1 = "http://api.map.baidu.com/geocoder/v2/?address=";
String url2 = "&output=json&ak=" + ak;
public WebExcel()
{
result = new ArrayList<List<String>>();
dao = new CountryDao();
poi = new Excel();
list = poi.readExcel();
}
// 为每个城市添加边境范围座标
public String doWork(String border)
{
try
{
if (list != null && i < list.size())
{
// 每一列加范围座标
if (i != 0)
{
List<String> temp = new ArrayList<String>();
String province = list.get(i).get(0);
String city = list.get(i).get(1);
String country = list.get(i).get(2);
temp.add(province);// 放入省市
temp.add(city);// 放入市区
temp.add(country);// 放入县
place = "";
// 获取中心点座标
if (city.equals(""))
{
place = province;// 放入省
}else if (country.equals(""))
{
place = city;// 放入市
}else
{
if (city.substring(city.length() - 1).equals("市"))
place = city.substring(0, city.length() - 1) + country;// 放入县
else
place = city + country;
}
if (place.length() >= 3)
{
String end = place.substring(place.length() - 3);
if (end.equals("自治州"))
{
place += "政府";
}
if (end.equals("开发区"))
{
place += "管理委员会";
}else
{
place += "人民政府";
}
}
//获取中心点的x,y
String[] answer = Parser_Tool.dealWith(Parser_Tool.doGet(url1 + place + url2));
temp.add(answer[0]);
temp.add(answer[1]);
System.out.println(place+": x:"+answer[0]+" y:"+answer[1]);
// x,y区分处理
String[] arr = border.split(",|;");
String x = "";
String y = "";
for(int i = 0; i < arr.length; i++)
{
if (i % 2 == 0)
{
if (i != arr.length - 2)
x += arr[i] + ",";
else
{
x += arr[i];
}
}else
{
if (i != arr.length - 1)
y += arr[i] + ",";
else
{
y += arr[i];
}
}
}
temp.add(x);// 放入边界范围
temp.add(y);
result.add(temp);
// dao.addExcel(temp);
}else
{
// 默认导入的是同一个数据源
result = dao.getDate();
i=result.size();
}
System.out.println("边界范围" + ":"+border);
i++;
if (i >= list.size())
{
dao.addAllExcel(result);
// dao.fillBorder(result);
return "over";
}
//返回下一个省
if(list.get(i).get(1).equals(""))
return list.get(i).get(0);
//返回下一个市
if(list.get(i).get(2).equals(""))
return list.get(i).get(0)+list.get(i).get(1);
else
{
if (list.get(i).get(1).substring(list.get(i).get(1).length() - 1).equals("市"))
place = list.get(i).get(0)+list.get(i).get(1).substring(0, list.get(i).get(1).length() - 1) + list.get(i).get(2);// 放入县
else
place = list.get(i).get(0)+list.get(i).get(1) + list.get(i).get(2);
return place;
}
}
return "over";
}catch(Exception e)
{
e.printStackTrace();
dao.addAllExcel(result);
return "over";
}
}
}
我当时是分开做实验的。获取地址和边界。所以获取边界的时候我是采用另一种方式读取excelde 。用的是jxl
导入个这个包就好了
package service;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
public class Excel
{
File file = new File("E:模版.xls");
File write = new File("E:");
List<List<String>> library = new ArrayList<List<String>>();
int i = 0, j = 0;
public Excel()
{
}
// 去读Excel的方法readExcel,该方法的入口参数为一个File对象
public List<List<String>> readExcel()
{
try
{
// 创建输入流,读取Excel
InputStream is = new FileInputStream(file.getAbsolutePath());
// jxl提供的Workbook类
Workbook wb = Workbook.getWorkbook(is);
// Excel的页签数量
int sheet_size = wb.getNumberOfSheets();
for(int index = 0; index < sheet_size; index++)
{
// 每个页签创建一个Sheet对象
Sheet sheet = wb.getSheet(index);
// sheet.getRows()返回该页的总行数
for(int i = 0; i < sheet.getRows(); i++)
{
// sheet.getColumns()返回该页的总列数
List<String> temp = new ArrayList<String>();
for(int j = 0; j < sheet.getColumns(); j++)
{
String cellinfo = sheet.getCell(j, i).getContents();
temp.add(cellinfo);
// System.out.println(cellinfo);
}
library.add(temp);
}
}
return library;
}catch(FileNotFoundException e)
{
e.printStackTrace();
}catch(BiffException e)
{
e.printStackTrace();
}catch(IOException e)
{
e.printStackTrace();
}
return null;
}
// 去读Excel的方法readExcel,该方法的入口参数为一个File对象
public void writeExcel(List<List<String>> out)
{
try
{
// 打开文件
WritableWorkbook book = Workbook.createWorkbook(new File("final.xls"));
// 生成名为“sheet1”的工作表,参数0表示这是第一页
WritableSheet sheet = book.createSheet("sheet1", 0);
// 在Label对象的构造子中指名单元格位置是第一列第一行(0,0),单元格内容为string
for(int i = 0; i < out.size(); i++)
for(int j = 0; j < out.get(i).size(); j++)
{
Label label = new Label(j,i, out.get(i).get(j));
// 将定义好的单元格添加到工作表中
sheet.addCell(label);
}
// 写入数据并关闭文件
book.write();
book.close();
}catch(Exception e)
{
System.out.println(e);
}
}
}
我把结果直接写到数据库的
package Dao;
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class BaseDao
{
DataSource dataSource;
//构造方法中返回数据源对象
public BaseDao()
{
try
{
Context context=new InitialContext();
dataSource=(DataSource)context.lookup("java:comp/env/jdbc/yanfan");
}catch(NamingException ne)
{
ne.printStackTrace();
}
}
//返回一个连接对象
public Connection getConnection()throws Exception
{
return dataSource.getConnection();
}
}
package Dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.mysql.jdbc.Statement;
public class CountryDao extends BaseDao
{
Connection conn;
PreparedStatement pstmt;
Statement stmt;
ResultSet rst;
// 插入国家信息记录(全部)
public boolean addAllExcel(List<List<String>> list)
{
String sql = "insert into china (province,city,country,xcenter,ycenter,xborders,yborders) values(?,?,?,?,?,?,?)";
try
{
conn = dataSource.getConnection();
for(int i = 0; i < list.size(); i++)
{
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, list.get(i).get(0));
pstmt.setString(2, list.get(i).get(1));
pstmt.setString(3, list.get(i).get(2));
pstmt.setString(4, list.get(i).get(3));
pstmt.setString(5, list.get(i).get(4));
pstmt.setString(6, list.get(i).get(5));
pstmt.setString(7, list.get(i).get(6));
pstmt.executeUpdate();
}
System.out.println("完成");
return true;
}catch(SQLException se)
{
se.printStackTrace();
return false;
}
}
// 添加单个数据元
public boolean addExcel(List<String> list)
{
String sql = "insert into china (province,city,country,xcenter,ycenter,xborders,yborders) values(?,?,?,?,?,?,?)";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
for(int i = 0; i < list.size(); i++)
{
pstmt.setString(i + 1, list.get(i));
}
pstmt.executeUpdate();
System.out.println("完成");
return true;
}catch(SQLException se)
{
se.printStackTrace();
return false;
}
}
// 先检查数据库里已经存在了多少个数据,减少重复输入
public List<List<String>> getDate()
{
List<List<String>> result = new ArrayList<List<String>>();
String sql = "SELECT * FROM work.china";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
rst = pstmt.executeQuery();
// 获取元数据
ResultSetMetaData rsmd = rst.getMetaData();
while(rst.next())
{
List<String> temp = new ArrayList<String>();
// 根据结果表得出的
for(int i = 0; i < rsmd.getColumnCount(); i++)
{
String conlumnLabel = rsmd.getColumnLabel(i + 1);
Object comlumnValue = rst.getObject(conlumnLabel);
temp.add("" + comlumnValue);
}
result.add(temp);
}
return result;
}catch(SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
// 获取缺失边界点的数据
public List<List<String>> getBordersDate()
{
List<List<String>> result = new ArrayList<List<String>>();
String sql = "SELECT * FROM work.china where xborders=',' and yborders=''";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
rst = pstmt.executeQuery();
// 获取元数据
ResultSetMetaData rsmd = rst.getMetaData();
while(rst.next())
{
List<String> temp = new ArrayList<String>();
// 根据结果表得出的
for(int i = 0; i < rsmd.getColumnCount(); i++)
{
String conlumnLabel = rsmd.getColumnLabel(i +1);
Object comlumnValue = rst.getObject(conlumnLabel);
temp.add("" + comlumnValue);
}
result.add(temp);
}
return result;
}catch(SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
// 获取缺少中心点的数据
public List<List<String>> getCenterDate()
{
List<List<String>> result = new ArrayList<List<String>>();
String sql = "SELECT * FROM work.china where xcenter='' and ycenter=''";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
rst = pstmt.executeQuery();
// 获取元数据
ResultSetMetaData rsmd = rst.getMetaData();
while(rst.next())
{
List<String> temp = new ArrayList<String>();
// 根据结果表得出的
for(int i = 0; i < rsmd.getColumnCount(); i++)
{
String conlumnLabel = rsmd.getColumnLabel(i + 1);
Object comlumnValue = rst.getObject(conlumnLabel);
temp.add("" + comlumnValue);
}
result.add(temp);
}
return result;
}catch(SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
// 检查填充边界的数据
public boolean fillBorder(List<List<String>> list)
{
String sql = "update china set country = ?,xborders = ? ,yborders=? where province = ? and city = ? and country = ?";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
System.out.println("数量"+list.size());
for(int i=0;i<list.size();i++)
{
pstmt.setString(1, list.get(i).get(7));
pstmt.setString(2, list.get(i).get(5));
pstmt.setString(3, list.get(i).get(6));
pstmt.setString(4, list.get(i).get(0));
pstmt.setString(5, list.get(i).get(1));
pstmt.setString(6, list.get(i).get(2));
System.out.println("加载"+i);
pstmt.executeUpdate();
System.out.println("完成"+i);
}
System.out.println("完成");
return true;
}catch(SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
// 填充中心
public boolean fillCenter(List<List<String>> list)
{
String sql = "update china set country = ? ,xcenter = ? ,ycenter=? where province = ? and city = ? and country = ?";
try
{
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
for(int i = 0; i < list.size(); i++)
{
pstmt.setString(1, list.get(i).get(2));
pstmt.setString(2, list.get(i).get(3));
pstmt.setString(3, list.get(i).get(4));
pstmt.setString(4, list.get(i).get(0));
pstmt.setString(5, list.get(i).get(1));
pstmt.setString(6, list.get(i).get(2));
pstmt.executeUpdate();
}
return true;
}catch(SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
}
记得配置个context.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true">
<Resource name="jdbc/yanfan" type="javax.sql.DataSource"
maxActive="40" maxIdle="29" username="root" maxWait="5000"
driverClassName="com.mysql.jdbc.Driver" password="123456789"
url="jdbc:mysql://localhost:3306/work" />
</Context>
有了以上代码后就可以开始跑数据了。修改下数据库地方就可以了
跑下来可能存在一些数据不正确,比如名字不对,还有可能一些城市已经合并了。因为原数据是近两年的。但是这两年也有些城市发生了变动,所以我只能一个个百度,找到有问题的城市查明原因,去对应修改。修改数据的代码如下
package service;
import java.util.ArrayList;
import java.util.List;
import Dao.CountryDao;
//用于填空的座标
public class FillBorder
{
List<List<String>> list;
List<List<String>> result = new ArrayList<List<String>>();
CountryDao dao = new CountryDao();
String ak = "你的百度ak";
String url1 = "http://api.map.baidu.com/geocoder/v2/?address=";
String url2 = "&output=json&ak=" + ak;
String place = "";
int i = 0;// 行
static boolean end;
public FillBorder()
{
list = dao.getBordersDate();
System.out.println("边界缺损数量:" + list.size());
}
public String doWork(String border)
{
try
{
if(end)
return "over";
String[] arr = border.split(",|;");
String x = "", y = "";
List<String> temp = new ArrayList<String>();
if (i >= list.size())
{
dao.fillBorder(result);
end=true;
return "over";
}
//加入省,市
for(int j = 0; j < 2; j++)
{
temp.add(list.get(i).get(j));
}
//加入县
String country = list.get(i).get(2);
if ((country.length() > 3 && country.substring(country.length() - 3).equals("街道市"))||(country.length() > 2 && country.substring(country.length() - 2).equals("旗市")))
{
country = country.substring(0, country.length() - 1);// 去掉街道名字里的市
}
if ((country.length() > 3 && country.substring(country.length() - 3).equals("县图市")))
{
country = country.substring(0, country.length() - 2);// 去掉街道名字里的图市
}
temp.add(list.get(i).get(2));
temp.add(list.get(i).get(3));
temp.add(list.get(i).get(4));
if ((country.length()>0&&country.substring(country.length() - 1).equals("镇"))||(country.length()>2&&country.substring(country.length()-2).equals("街道")))
{
String city = list.get(i).get(1);
if (city.substring(city.length() - 1).equals("市"))
{
city = city.substring(0, city.length() - 1);
}
place += city + country;
String[] town = Parser_Tool.dealWith(Parser_Tool.doGet(url1 + place + url2));
temp.add(town[0]);
temp.add(town[1]);
temp.add(country);
System.out.println(temp.get(7) + " 边界:" + town[0]+" , "+town[1]);
}else
{
for(int i = 0; i < arr.length; i++)
{
if (i % 2 == 0)
{
x += arr[i];
if (i != arr.length - 2)
{
x += ",";
}
}else
{
y += arr[i];
if (i != arr.length - 1)
{
y += ",";
}
}
}
temp.add(x);
temp.add(y);
temp.add(country);
System.out.println(temp.get(2) + " 边界:" + border);
}
result.add(temp);
++i;
if (i >= list.size())
{
dao.fillBorder(result);
return "over";
}
country = list.get(i).get(2);
if ((country.length() > 3 && country.substring(country.length() - 3).equals("街道市"))||(country.length() > 2 && country.substring(country.length() - 2).equals("旗市")))
{
country = country.substring(0, country.length() - 1);// 去掉街道名字里的市
}
if ((country.length() > 3 && country.substring(country.length() - 3).equals("县图市")))
{
country = country.substring(0, country.length() - 2);// 去掉街道名字里的图市
}
return list.get(i).get(0)+list.get(i).get(1)+country;
}catch(Exception e)
{
e.printStackTrace();
dao.fillBorder(result);
return "over";
}
}
public String first()
{
String first = list.get(i).get(0)+list.get(i).get(1)+list.get(i).get(2);
return first;
}
}
package service;
import java.util.List;
import Dao.CountryDao;
//用于填空的座标
public class FillCenter
{
List<List<String>> list;
CountryDao dao = new CountryDao();
// 1.地理编码服务,即根据地址来查经度纬度
String ak = "你的百度ak";
String url1 = "http://api.map.baidu.com/geocoder/v2/?address=";
String url2 = "&output=json&ak=" + ak;
String place;
public FillCenter()
{
list = dao.getCenterDate();
System.out.println("一共有及格没找到中心点" + list.size());
}
public boolean doWork()
{
try
{
for(int i = 0; i < list.size(); i++)
{
if (list.get(i).get(2).equals(""))
{
place = list.get(i).get(1);
if (place.equals("芒市"))
place += "人民政府";
if (place.equals("三沙市"))
place += "政府";
String[] center = Parser_Tool.dealWith(Parser_Tool.doGet(url1 + place + url2));
list.get(i).set(3, center[0]);
list.get(i).set(4, center[1]);
System.out.println(place + "x:" + center[0] + " y:" + center[1]);
continue;
}
place = list.get(i).get(2);
if (place.substring(place.length() - 2).equals("旗市"))
{
place.substring(0, place.length() - 1);// 修改名字,去掉市
list.get(i).set(2, place);
}
if (place.equals("镇原县"))
place += "人民政府政务大厅";
else if (place.equals("镇平县") || place.equals("樊城区") || place.equals("襄城区") || place.equals("红寺堡区")
|| place.equals("茂县"))
place += "政府";
else if (place.equals("郧县"))
place += "政协";
else
place += "人民政府";
String[] center = Parser_Tool.dealWith(Parser_Tool.doGet(url1 + place + url2));
list.get(i).set(3, center[0]);
list.get(i).set(4, center[1]);
System.out.println(place + "x:" + center[0] + " y:" + center[1]);
}
return dao.fillCenter(list);
}catch(Exception e)
{
e.printStackTrace();
dao.fillCenter(list);
return false;
}
}
}
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.FillBorder;
import service.FillCenter;
@WebServlet("/fillBack")
public class fillBack extends HttpServlet
{
boolean first=true;
String city=null;
FillBorder fill=new FillBorder();
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String border=request.getParameter("result");
System.out.println(border);
if(first)
{
//顺手填了中心的座标系
FillCenter fillCenter=new FillCenter();
fillCenter.doWork();
first=false;
city=fill.first();
}
else
{
city=fill.doWork(border);
}
if(city == "over")
return;
request.setAttribute("result",city);
request.getRequestDispatcher("fillBorder.jsp").forward(request,response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request,response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>获取地区轮廓线</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.3">
</script>
<style type="text/css">
body {
font-size: 13px;
margin: 10px
}
#container {
width: 800px;
height: 500px;
border: 1px solid gray
}
</style>
</head>
<body>
<div id="container"></div>
<br /> 输入省、直辖市或县名称:
<script type="text/javascript">
var map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(116.403765, 39.914850), 5);
map.addControl(new BMap.NavigationControl({
type : BMAP_NAVIGATION_CONTROL_SMALL
}));
map.enableScrollWheelZoom();
function getBoundary()
{
var bdary = new BMap.Boundary();
var name = document.getElementById("districtName").value;
bdary.get(name, function(rs) { //获取行政区域
map.clearOverlays(); //清除地图覆盖物
var count = rs.boundaries.length; //行政区域的点有多少个
for (var i = 0; i < count; i++) {
var ply = new BMap.Polygon(rs.boundaries[i], {
strokeWeight : 2,
strokeColor : "#ff0000"
}); //建立多边形覆盖物
map.addOverlay(ply); //添加覆盖物
map.setViewport(ply.getPath()); //调整视野
}
var answer=document.getElementById("result");
answer.value=rs.boundaries;
});
}
setTimeout(getBoundary,1);
setTimeout(a,5000);
function a()
{
document.getElementById("fom").submit();
}
</script>
<form id="fom" action="fillBack" method="post">
<input type="text" id="districtName" name="districtName" style="width: 80px" value="${result}">
<input id="result" name="result" value=""></input>
<input onclick="getBoundary()" type="button" id="start" value="获取轮廓线"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
经过这些数据处理就可以了.顺序是先用省,市县去找。然后再用市县去找,最后再用县去找。跑三次,就可以确定这些数据最全了。剩下的得人工修改。因为省市县名字不对。或者城市已经没了,或者简写找不到等导致的。
带吗到数据库里修改(Sql代码)
//删除没有的数据(城市已经被合并了)
delete from china where province=''
//修改数据(因为没有主键,直接修改会报错Error: 1175 SQLSTATE: HY000 (ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE))
//这是先运行下 SET SQL_SAFE_UPDATES = 0; 修改下更新模式就好
update china set xborders=',',yborders='' where province='浙江省'
//查询语句
SELECT * FROM work.china;
//如果数据里面有重复的,可以采用再建立的temp表。和china表一模一样的。
//然后运行sql语句
insert into temp select distanct * from china;
truncate table china;
insert into china select distanct * from temp;
//如果不需要temp了可以人工删除
然后就好了。
一下是我的代码。得自己创建下数据库,按照自己的数据库修改下代码context等部分。
http://download.csdn.net/download/qq_33359282/9896354