Openlayers 를 개발할 때, 가장 많이 사용하는 GIS 서버는 역시 Geoserver 이다. Geoserver를 통해 wms, wfs 레이어를 가져올 수 있고, 상황에 따라 tif 파일도 레이어로 발행해서 웹 지도상에 가져올 수 있다. Geoserver는 많은 기능을 제공하는데, 그 중에서 특정 형식의 포맷으로 다운로드 할 수 있는 기능의 샘플 소스를 확인해보려고 한다.
package songjang.map;
import egovframework.com.cmm.service.EgovProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Geoserver 파일 다운로드 컨트롤러
* @author 송장
* @since 2018.06.19
* @version 1.0
* @see
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ----------- --------- ---------------------------
* 2018.06.19 송장 최초 생성
*
* </pre>
*/
@Controller
public class GeoserverDownloadController {
private static final Logger LOGGER = LoggerFactory.getLogger(GeoserverDownloadController.class);
private String GEOSERVER_URL = "http://localhost:8080/geoserver/songjang/wfs";
/**
* 한글 값 처리
* @param value 인코딩할 문자열
* @return
* @throws java.io.UnsupportedEncodingException
*/
private String getLocaleString(String value) throws UnsupportedEncodingException {
byte[] b;
b = value.getBytes("8859_1");
final CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
try {
final CharBuffer r = decoder.decode(ByteBuffer.wrap(b));
return r.toString();
} catch (final CharacterCodingException e) {
return new String(b, "EUC-KR");
}
}
/**
* Export (여러개 일 때 한개(.zip)로 압축)
*
* @param params
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value="/map/dxfExport.do")
public void dxfExport(@RequestParam HashMap<String, Object> params, HttpServletRequest request, HttpServletResponse response) throws Exception {
String[] arrLayer = ((String)params.get("layerNames")).split("/");
String fileName = arrLayer.length == 1 ? arrLayer[0] + ".dxf" : "dxf.zip";
response.setCharacterEncoding("UTF-8");
response.setHeader("Accept-Ranges", "bytes");
String agent = request.getHeader("User-Agent");
fileName = URLEncoder.encode(fileName, "UTF-8");
if(agent.indexOf("MSIE 5.5") > -1){
response.setHeader("Content-Disposition", "filename=" + fileName + ";");
} else{
response.setHeader("Content-Type", "application/octet-stream;charset=utf-8;");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";");
}
request.setCharacterEncoding("UTF-8");
StringBuffer sb = new StringBuffer();
for(Object param : request.getParameterMap().entrySet()) {
@SuppressWarnings("unchecked")
Entry<String, String[]> entry = (Entry<String, String[]>) param;
if ("layerNames".equals(entry.getKey())) continue;
if(entry.getKey().indexOf('=') >= 0) {
sb.append(getLocaleString(entry.getKey()));
} else {
sb.append(entry.getKey());
sb.append("=");
String[] values = entry.getValue();
if(values.length > 0) {
String layerName = request.getCharacterEncoding() == null ? URLEncoder.encode(getLocaleString(values[0]), "UTF-8") : URLEncoder.encode(values[0], "UTF-8");
sb.append(layerName);
}
sb.append("&");
}
}
HttpURLConnection huc = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
ZipOutputStream zout = null;
try {
if (arrLayer.length == 1) {
URL url = new URL(GEOSERVER_URL.concat("?") + sb + "typeName=" + arrLayer[0]);
URLConnection connection = url.openConnection();
huc = (HttpURLConnection)connection;
huc.setRequestMethod("GET");
huc.setDoOutput(true);
huc.setDoInput(true);
huc.setUseCaches(false);
huc.setDefaultUseCaches(false);
huc.setConnectTimeout(1000000);
huc.setReadTimeout(1000000);
bis = new BufferedInputStream(huc.getInputStream());
bos = new BufferedOutputStream(response.getOutputStream());
byte[] inputData = null;
int read = 0;
int bufSize = 4096;
inputData = new byte[bufSize];
while ((read = bis.read(inputData)) > 0) {
bos.write(inputData, 0, read);
}
bos.flush();
} else if (arrLayer.length > 1) {
zout = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
for (String layerName : arrLayer) {
URL url = new URL(GEOSERVER_URL.concat("?") + sb + "typeName=" + layerName);
URLConnection connection = url.openConnection();
huc = (HttpURLConnection)connection;
huc.setConnectTimeout(1000000);
huc.setReadTimeout(500000);
bis = new BufferedInputStream(huc.getInputStream());
ZipEntry ze = new ZipEntry(layerName + ".dxf");
zout.putNextEntry(ze);
int read = 0;
int bufSize = 4096;
byte[] inputData = new byte[bufSize];
while ((read = bis.read(inputData)) > 0) {
zout.write(inputData, 0, read);
}
zout.closeEntry();
// zout.flush();
bis.close();
}
} else {
LOGGER.debug("retry!!");
}
} catch (IOException e) {
LOGGER.warn(e.getMessage());
//throw e;
// e.printStackTrace();
} finally {
if(bis != null) {
bis.close();
}
if(bos != null) {
bos.close();
}
if(huc != null) {
huc.disconnect();
}
if(zout != null) {
zout.close();
}
}
}
}
원리는 간단했다. Geoserver에서 파일 export url을 지원하기 때문에 내 컨트롤러(Java) 에서 URLConnection 을 통해 지오서버로 요청한 방식이다. 이 때, 내가 요청한 레이어 개수가 1개면 파일로, 1개 이상이면 java.util.zip 라이브러리를 사용하여 zip 파일로 묶어서 내려받도록 작성하였다.
이 때, 중요한 것은 현재 소스코드는 dxf 형식을 export 하는 것 위주로 작업하였지만, 상황에 따라 더 유연하게 소스코드를 변경할 수 있는 여지가 있다는 점이다.
API 를 요청할 때 파라미터 outputFormat 을 통해 Geoserver 에서 내보낼 파일 형식 지정이 가능(Geoserver에서 Export 형식을 지원한다면..) 하고, bbox 를 통해 해당 영역만 추출해서 다운로드 할 수 있다.
Front의 요청 부분을 일부 확인해보면
/**
* dxf export 함수
*
* @param layerNames
* @param params
*/
const dxfExport = function(layerNames, params) {
params = $.extend({}, {
request : "GetFeature", // 기본
outputFormat : "dxf", // 다운로드 받을 확장자
layerNames : layerNames, // 요청 레이어 이름 목록(1개 이상)
bbox: [0, 0, 0, 0] // 다운로드 추출 영역 (minx, miny, maxx, maxy)
}, params);
var $form = $("<form/>");
$.each(params, function(key, val){
var inputHtml = "<input type='hidden' id='" + key + "' name='" + key + "' value='" + val + "'/>";
$form.append(inputHtml);
});
$form.appendTo("body");
$form.attr({ action : contextPath + "map/dxfExport.do", method : "post" }).submit().remove();
};
outputFormat 을 유동적으로 변경하여 Geoserver에서 지원하는 export format 을 유연하게 다운로드 할 수 있을 것으로 보인다.
'Spring' 카테고리의 다른 글
Kabeja 를 통한 DXF 파일 GML 로 parsing 예제 (3) | 2021.06.05 |
---|