做它的原因
接了老師一個項目,老師要我先去收集各個省市縣級的邊界座標以及中心城區範圍,然後老師要用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