coordinates = new ArrayList<>();
147 | coordinates.add(getPreciseCoordinate());
148 | String nextToken = getNextCloserOrComma();
149 | while (COMMA.equals(nextToken)) {
150 | coordinates.add(getPreciseCoordinate());
151 | nextToken = getNextCloserOrComma();
152 | }
153 | Coordinate[] array = new Coordinate[coordinates.size()];
154 | return coordinates.toArray(array);
155 | }
156 |
157 | private Coordinate getPreciseCoordinate() throws IOException, ParseException {
158 | Coordinate coordinate = new Coordinate();
159 | coordinate.setX(getNextNumber());
160 | coordinate.setY(getNextNumber());
161 | if (isNumberNext()) {
162 | coordinate.setZ(getNextNumber());
163 | }
164 | if (isNumberNext()) {
165 | // ignore M value
166 | getNextNumber();
167 | }
168 | precisionModel.makePrecise(coordinate);
169 | return coordinate;
170 | }
171 |
172 | private boolean isNumberNext() throws IOException {
173 | int type = tokenizer.nextToken();
174 | tokenizer.pushBack();
175 | return type == StreamTokenizer.TT_WORD;
176 | }
177 |
178 | /**
179 | * Parses the next number in the stream. Numbers with exponents are handled.
180 | * NaN values are handled correctly, and the case of the "NaN"
181 | * symbol is not significant.
182 | *
183 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
184 | * next token must be a number.
185 | *
186 | * @return the next number in the stream
187 | * @throws ParseException if the next token is not a valid number
188 | * @throws IOException if an I/O error occurs
189 | */
190 | private double getNextNumber() throws IOException, ParseException {
191 | int type = tokenizer.nextToken();
192 | switch (type) {
193 | case StreamTokenizer.TT_WORD: {
194 | if (tokenizer.sval.equalsIgnoreCase(NAN_SYMBOL)) {
195 | return Double.NaN;
196 | } else {
197 | try {
198 | return Double.parseDouble(tokenizer.sval);
199 | } catch (NumberFormatException ex) {
200 | parseErrorWithLine("Invalid number: " + tokenizer.sval);
201 | }
202 | }
203 | break;
204 | }
205 | default:{
206 |
207 | }
208 | }
209 | parseErrorExpected("number");
210 | return 0.0;
211 | }
212 |
213 | /**
214 | * Returns the next EMPTY or L_PAREN in the stream as uppercase text.
215 | *
216 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
217 | * next token must be EMPTY or L_PAREN.
218 | *
219 | * @return the next EMPTY or L_PAREN in the stream as uppercase text.
220 | * @throws ParseException if the next token is not EMPTY or L_PAREN
221 | * @throws IOException if an I/O error occurs
222 | */
223 | private String getNextEmptyOrOpener() throws IOException, ParseException {
224 | String nextWord = getNextWord();
225 | if (Z.equalsIgnoreCase(nextWord)) {
226 | z = true;
227 | nextWord = getNextWord();
228 | } else if (M.equalsIgnoreCase(nextWord)) {
229 | m = true;
230 | nextWord = getNextWord();
231 | } else if (ZM.equalsIgnoreCase(nextWord)) {
232 | z = true;
233 | m = true;
234 | nextWord = getNextWord();
235 | }
236 | if (EMPTY.equals(nextWord) || L_PAREN.equals(nextWord)) {
237 | return nextWord;
238 | }
239 | parseErrorExpected(EMPTY + " or " + L_PAREN);
240 | return null;
241 | }
242 |
243 | /**
244 | * Returns the next R_PAREN or COMMA in the stream.
245 | *
246 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
247 | * next token must be R_PAREN or COMMA.
248 | *
249 | * @return the next R_PAREN or COMMA in the stream
250 | * @throws ParseException if the next token is not R_PAREN or COMMA
251 | * @throws IOException if an I/O error occurs
252 | */
253 | private String getNextCloserOrComma() throws IOException, ParseException {
254 | String nextWord = getNextWord();
255 | if (COMMA.equals(nextWord) || R_PAREN.equals(nextWord)) {
256 | return nextWord;
257 | }
258 | parseErrorExpected(COMMA + " or " + R_PAREN);
259 | return null;
260 | }
261 |
262 | /**
263 | * Returns the next R_PAREN in the stream.
264 | *
265 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
266 | * next token must be R_PAREN.
267 | *
268 | * @return the next R_PAREN in the stream
269 | * @throws ParseException if the next token is not R_PAREN
270 | * @throws IOException if an I/O error occurs
271 | */
272 | private String getNextCloser() throws IOException, ParseException {
273 | String nextWord = getNextWord();
274 | if (R_PAREN.equals(nextWord)) {
275 | return nextWord;
276 | }
277 | parseErrorExpected(R_PAREN);
278 | return null;
279 | }
280 |
281 | /**
282 | * Returns the next word in the stream.
283 | *
284 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
285 | * next token must be a word.
286 | *
287 | * @return the next word in the stream as uppercase text
288 | * @throws ParseException if the next token is not a word
289 | * @throws IOException if an I/O error occurs
290 | */
291 | private String getNextWord() throws IOException, ParseException {
292 | int type = tokenizer.nextToken();
293 | switch (type) {
294 | case StreamTokenizer.TT_WORD:
295 |
296 | String word = tokenizer.sval;
297 | if (word.equalsIgnoreCase(EMPTY)){
298 | return EMPTY;
299 | }
300 |
301 | return word;
302 |
303 | case '(':
304 | return L_PAREN;
305 | case ')':
306 | return R_PAREN;
307 | case ',':
308 | return COMMA;
309 | default:{
310 |
311 | }
312 | }
313 | parseErrorExpected("word");
314 | return null;
315 | }
316 |
317 | /**
318 | * Returns the next word in the stream.
319 | *
320 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
321 | * next token must be a word.
322 | *
323 | * @return the next word in the stream as uppercase text
324 | * @throws ParseException if the next token is not a word
325 | * @throws IOException if an I/O error occurs
326 | */
327 | private String lookaheadWord() throws IOException, ParseException {
328 | String nextWord = getNextWord();
329 | tokenizer.pushBack();
330 | return nextWord;
331 | }
332 |
333 | /**
334 | * Throws a formatted ParseException reporting that the current token was
335 | * unexpected.
336 | *
337 | * @param expected a description of what was expected
338 | * @throws ParseException AssertionFailedException if an invalid token is encountered
339 | */
340 | private void parseErrorExpected(String expected) throws ParseException {
341 | // throws Asserts for tokens that should never be seen
342 | if (tokenizer.ttype == StreamTokenizer.TT_NUMBER){
343 | Assert.shouldNeverReachHere("Unexpected NUMBER token");
344 | }
345 | if (tokenizer.ttype == StreamTokenizer.TT_EOL){
346 | Assert.shouldNeverReachHere("Unexpected EOL token");
347 | }
348 |
349 | String tokenStr = tokenString();
350 | parseErrorWithLine("Expected " + expected + " but found " + tokenStr);
351 | }
352 |
353 | private void parseErrorWithLine(String msg) throws ParseException {
354 | throw new ParseException(msg + " (line " + tokenizer.lineno() + ")");
355 | }
356 |
357 | /**
358 | * Gets a description of the current token
359 | *
360 | * @return a description of the current token
361 | */
362 | private String tokenString() {
363 | switch (tokenizer.ttype) {
364 | case StreamTokenizer.TT_NUMBER:
365 | return "";
366 | case StreamTokenizer.TT_EOL:
367 | return "End-of-Line";
368 | case StreamTokenizer.TT_EOF:
369 | return "End-of-Stream";
370 | case StreamTokenizer.TT_WORD:
371 | return "'" + tokenizer.sval + "'";
372 | default:{
373 |
374 | }
375 | }
376 | return "'" + (char) tokenizer.ttype + "'";
377 | }
378 |
379 | /**
380 | * Creates a Geometry
using the next token in the stream.
381 | *
382 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
383 | * next tokens must form a <Geometry Tagged Text>.
384 | *
385 | * @return a Geometry
specified by the next token in the stream
386 | * @throws ParseException if the coordinates used to create a Polygon
387 | * shell and holes do not form closed linestrings, or if an
388 | * unexpected token was encountered
389 | * @throws IOException if an I/O error occurs
390 | */
391 | private Geometry readGeometryTaggedText() throws IOException, ParseException {
392 |
393 | String type;
394 | try {
395 | type = getNextWord();
396 | if(type == null){
397 | return null;
398 | }
399 | type= type.toUpperCase();
400 |
401 | if (type.endsWith(Z)){
402 | z = true;
403 | }
404 | if (type.endsWith(M)){
405 | m = true;
406 | }
407 | } catch (IOException e) {
408 | return null;
409 | }
410 |
411 | if (type.startsWith(POINT)) {
412 | return readPointText();
413 | } else if (type.startsWith(LINESTRING)) {
414 | return readLineStringText();
415 | } else if (type.startsWith(LINEARRING)) {
416 | return readLinearRingText();
417 | } else if (type.startsWith(POLYGON)) {
418 | return readPolygonText();
419 | } else if (type.startsWith(MULTI_POINT)) {
420 | return readMultiPointText();
421 | } else if (type.startsWith(MULTI_LINESTRING)) {
422 | return readMultiLineStringText();
423 | } else if (type.startsWith(MULTI_POLYGON)) {
424 | return readMultiPolygonText();
425 | }
426 | parseErrorWithLine("Unknown geometry type: " + type);
427 | return null;
428 | }
429 |
430 | /**
431 | * Creates a Point
using the next token in the stream.
432 | *
433 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
434 | * next tokens must form a <Point Text>.
435 | *
436 | * @return a Point
specified by the next token in the stream
437 | * @throws IOException if an I/O error occurs
438 | * @throws ParseException if an unexpected token was encountered
439 | */
440 | private Point readPointText() throws IOException, ParseException {
441 | String nextToken = getNextEmptyOrOpener();
442 | if (EMPTY.equals(nextToken)) {
443 | return geometryFactory
444 | .createPoint(geometryFactory.getCoordinateSequenceFactory().create(new Coordinate[]{}));
445 | }
446 | Point point = geometryFactory.createPoint(getPreciseCoordinate());
447 | getNextCloser();
448 | return point;
449 | }
450 |
451 | /**
452 | * Creates a LineString
using the next token in the stream.
453 | *
454 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
455 | * next tokens must form a <LineString Text>.
456 | *
457 | * @return a LineString
specified by the next token in the
458 | * stream
459 | * @throws IOException if an I/O error occurs
460 | * @throws ParseException if an unexpected token was encountered
461 | */
462 | private LineString readLineStringText() throws IOException, ParseException {
463 | return geometryFactory.createLineString(getCoordinates());
464 | }
465 |
466 | /**
467 | * Creates a LinearRing
using the next token in the stream.
468 | *
469 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
470 | * next tokens must form a <LineString Text>.
471 | *
472 | * @return a LinearRing
specified by the next token in the
473 | * stream
474 | * @throws IOException if an I/O error occurs
475 | * @throws ParseException if the coordinates used to create the LinearRing
476 | * do not form a closed linestring, or if an unexpected token
477 | * was encountered
478 | */
479 | private LinearRing readLinearRingText() throws IOException, ParseException {
480 | return geometryFactory.createLinearRing(getCoordinates());
481 | }
482 |
483 | /*
484 | * private MultiPoint OLDreadMultiPointText() throws IOException,
485 | * ParseException { return
486 | * geometryFactory.createMultiPoint(toPoints(getCoordinates())); }
487 | */
488 |
489 | private static final boolean ALLOW_OLD_JTS_MULTIPOINT_SYNTAX = true;
490 |
491 | /**
492 | * Creates a MultiPoint
using the next tokens in the stream.
493 | *
494 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
495 | * next tokens must form a <MultiPoint Text>.
496 | *
497 | * @return a MultiPoint
specified by the next token in the
498 | * stream
499 | * @throws IOException if an I/O error occurs
500 | * @throws ParseException if an unexpected token was encountered
501 | */
502 | private MultiPoint readMultiPointText() throws IOException, ParseException {
503 | String nextToken = getNextEmptyOrOpener();
504 | if (EMPTY.equals(nextToken)) {
505 | return geometryFactory.createMultiPoint(new Point[0]);
506 | }
507 |
508 | // check for old-style JTS syntax and parse it if present
509 | // MD 2009-02-21 - this is only provided for backwards compatibility for
510 | // a few versions
511 | if (ALLOW_OLD_JTS_MULTIPOINT_SYNTAX) {
512 | String nextWord = lookaheadWord();
513 | if (!nextWord.equals(L_PAREN)) {
514 | return geometryFactory.createMultiPoint(toPoints(getCoordinatesNoLeftParen()));
515 | }
516 | }
517 |
518 | List points = new ArrayList<>();
519 | Point point = readPointText();
520 | points.add(point);
521 | nextToken = getNextCloserOrComma();
522 | while (COMMA.equals(nextToken)) {
523 | point = readPointText();
524 | points.add(point);
525 | nextToken = getNextCloserOrComma();
526 | }
527 | Point[] array = new Point[points.size()];
528 | return geometryFactory.createMultiPoint( points.toArray(array));
529 | }
530 |
531 | /**
532 | * Creates an array of Point
s having the given
533 | * Coordinate
s.
534 | *
535 | * @param coordinates the Coordinate
s with which to create the
536 | * Point
s
537 | * @return Point
s created using this WKTReader
s
538 | * GeometryFactory
539 | */
540 | private Point[] toPoints(Coordinate[] coordinates) {
541 | List points = new ArrayList<>();
542 | for (Coordinate coordinate : coordinates) {
543 | points.add(geometryFactory.createPoint(coordinate));
544 | }
545 | return points.toArray(new Point[]{});
546 | }
547 |
548 | /**
549 | * Creates a Polygon
using the next token in the stream.
550 | *
551 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
552 | * next tokens must form a <Polygon Text>.
553 | *
554 | * @return a Polygon
specified by the next token in the stream
555 | * @throws ParseException if the coordinates used to create the Polygon
556 | * shell and holes do not form closed linestrings, or if an
557 | * unexpected token was encountered.
558 | * @throws IOException if an I/O error occurs
559 | */
560 | private Polygon readPolygonText() throws IOException, ParseException {
561 | String nextToken = getNextEmptyOrOpener();
562 | if (EMPTY.equals(nextToken)) {
563 | return geometryFactory.createPolygon(geometryFactory.createLinearRing(new Coordinate[]{}),
564 | new LinearRing[]{});
565 | }
566 | List holes = new ArrayList<>();
567 | LinearRing shell = readLinearRingText();
568 | nextToken = getNextCloserOrComma();
569 | while (COMMA.equals(nextToken)) {
570 | LinearRing hole = readLinearRingText();
571 | holes.add(hole);
572 | nextToken = getNextCloserOrComma();
573 | }
574 | LinearRing[] array = new LinearRing[holes.size()];
575 | return geometryFactory.createPolygon(shell, holes.toArray(array));
576 | }
577 |
578 | /**
579 | * Creates a MultiLineString
using the next token in the
580 | * stream.
581 | *
582 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
583 | * next tokens must form a <MultiLineString Text>.
584 | *
585 | * @return a MultiLineString
specified by the next token in the
586 | * stream
587 | * @throws IOException if an I/O error occurs
588 | * @throws ParseException if an unexpected token was encountered
589 | */
590 | private MultiLineString readMultiLineStringText() throws IOException, ParseException {
591 | String nextToken = getNextEmptyOrOpener();
592 | if (EMPTY.equals(nextToken)) {
593 | return geometryFactory.createMultiLineString(new LineString[]{});
594 | }
595 | List lineStrings = new ArrayList<>();
596 | LineString lineString = readLineStringText();
597 | lineStrings.add(lineString);
598 | nextToken = getNextCloserOrComma();
599 | while (COMMA.equals(nextToken)) {
600 | lineString = readLineStringText();
601 | lineStrings.add(lineString);
602 | nextToken = getNextCloserOrComma();
603 | }
604 | LineString[] array = new LineString[lineStrings.size()];
605 | return geometryFactory.createMultiLineString(lineStrings.toArray(array));
606 | }
607 |
608 | /**
609 | * Creates a MultiPolygon
using the next token in the stream.
610 | *
611 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
612 | * next tokens must form a <MultiPolygon Text>.
613 | *
614 | * @return a MultiPolygon
specified by the next token in the
615 | * stream, or if if the coordinates used to create the
616 | * Polygon
shells and holes do not form closed
617 | * linestrings.
618 | * @throws IOException if an I/O error occurs
619 | * @throws ParseException if an unexpected token was encountered
620 | */
621 | private MultiPolygon readMultiPolygonText() throws IOException, ParseException {
622 | String nextToken = getNextEmptyOrOpener();
623 | if (EMPTY.equals(nextToken)) {
624 | return new MultiPolygon(null, geometryFactory);
625 | }
626 | List polygons = new ArrayList<>();
627 | Polygon polygon = readPolygonText();
628 | polygons.add(polygon);
629 | nextToken = getNextCloserOrComma();
630 | while (COMMA.equals(nextToken)) {
631 | polygon = readPolygonText();
632 | polygons.add(polygon);
633 | nextToken = getNextCloserOrComma();
634 | }
635 | Polygon[] array = new Polygon[polygons.size()];
636 | return geometryFactory.createMultiPolygon(polygons.toArray(array));
637 | }
638 |
639 | /**
640 | * Creates a GeometryCollection
using the next token in the
641 | * stream.
642 | *
643 | * tokenizer tokenizer over a stream of text in Well-known Text format. The
644 | * next tokens must form a <GeometryCollection Text>.
645 | *
646 | * @return a GeometryCollection
specified by the next token in
647 | * the stream
648 | * @throws ParseException if the coordinates used to create a Polygon
649 | * shell and holes do not form closed linestrings, or if an
650 | * unexpected token was encountered
651 | * @throws IOException if an I/O error occurs
652 | */
653 | private GeometryCollection readGeometryCollectionText() throws IOException, ParseException {
654 | String nextToken = getNextEmptyOrOpener();
655 | if (EMPTY.equals(nextToken)) {
656 | return geometryFactory.createGeometryCollection(new Geometry[]{});
657 | }
658 | List geometries = new ArrayList<>();
659 | Geometry geometry = readGeometryTaggedText();
660 | geometries.add(geometry);
661 | nextToken = getNextCloserOrComma();
662 | while (COMMA.equals(nextToken)) {
663 | geometry = readGeometryTaggedText();
664 | geometries.add(geometry);
665 | nextToken = getNextCloserOrComma();
666 | }
667 | Geometry[] array = new Geometry[geometries.size()];
668 | return geometryFactory.createGeometryCollection(geometries.toArray(array));
669 | }
670 |
671 |
672 | }
673 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/ShpApplication.java:
--------------------------------------------------------------------------------
1 | package com.appleyk;
2 |
3 | import org.springframework.boot.CommandLineRunner;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.boot.builder.SpringApplicationBuilder;
7 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
8 | import org.springframework.context.annotation.Bean;
9 |
10 | /**
11 | * 下面是一个典型的结构:
12 | *
13 | * com
14 | * +- example
15 | * +- myproject
16 | * +- Application.java --
17 | *
18 | * 注意这个位置,习惯性的放在项目的一开始,也就是根包的第一层 | + - domain | +- Customer.java | +-
19 | * CustomerRepository.java | + - service | +- CustomerService.java | + - web +-
20 | * CustomerController.java
21 | * 文件将声明 main 方法, 还有基本的 @Configuration
22 | *
23 | * SpringBoot启动类
24 | * @author Appleyk
25 | * @blob https://blog.csdn.net/appleyk
26 | * @date Created on 上午 11:54 2018-10-12
27 | */
28 | @SpringBootApplication// same as @Configuration @EnableAutoConfiguration @ComponentScan
29 | public class ShpApplication extends SpringBootServletInitializer {
30 |
31 | /**
32 | * SpringApplication类提供了一种从main()方法启动Spring应用的便捷方式。 在很多情况下, 你只需委托给
33 | * SpringApplication.run这个静态方法:
34 | * @param args 输入参数
35 | */
36 | public static void main(String[] args) {
37 | SpringApplication.run(ShpApplication.class, args);
38 | }
39 |
40 | @Override
41 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
42 | return application.sources(ShpApplication.class);
43 | }
44 |
45 | /**
46 | * Spring-Boot启动的时候,加载、创建、初始化数据
47 | * @return 初始化信息
48 | */
49 | @Bean
50 | CommandLineRunner demo() {
51 | return args -> {
52 | System.out.println("<<<<<<<<< Hello,Spring Boot ! >>>>>>>>");
53 | };
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/controller/ShpController.java:
--------------------------------------------------------------------------------
1 | package com.appleyk.controller;
2 |
3 | import com.appleyk.pojos.ShpInfo;
4 | import com.appleyk.result.ResponseResult;
5 | import com.appleyk.service.ShpService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.web.bind.annotation.*;
8 |
9 | import javax.servlet.http.HttpServletResponse;
10 |
11 | /**
12 | * shp接口请求处理器
13 | * @author Appleyk
14 | * @blob https://blog.csdn.net/appleyk
15 | * @date Created on 下午 2018-10-24 16:27:22
16 | */
17 | @CrossOrigin
18 | @RequestMapping("/shper")
19 | @RestController
20 | public class ShpController {
21 |
22 | @Autowired
23 | private ShpService shpService;
24 |
25 | @GetMapping("/hello")
26 | public String sayHello(){
27 | return "Hello Appleyk's Controller !";
28 | }
29 |
30 |
31 | /**
32 | * 写一个shp文件
33 | * @param shpInfo
34 | * @return
35 | * @throws Exception
36 | */
37 | @PostMapping("/write")
38 | public ResponseResult write(@RequestBody ShpInfo shpInfo) throws Exception{
39 | return shpService.writeShp(shpInfo);
40 | }
41 |
42 | /**
43 | * 查询一个shp文件
44 | * @param shpFilePath 文件绝对路径
45 | * @param limit 指定显示多少条shp特征【features】
46 | * @return
47 | * @throws Exception
48 | */
49 | @GetMapping("/query")
50 | public ResponseResult query(@RequestParam(value = "path",required = true) String shpFilePath,
51 | @RequestParam(value = "limit",required = false,defaultValue = "10") Integer limit ) throws Exception{
52 | return shpService.getShpDatas(shpFilePath,limit);
53 | }
54 |
55 | /**
56 | * 将shp文件转换成png图片,图片或写入文件或通过response输出到界面【比如,客户端浏览器】
57 | * @param path shp文件路径
58 | * @param imagePath 如果imagePath不等于空,则shp文件转成图片文件存储进行存
59 | * @param color 渲染颜色
60 | */
61 | @GetMapping("/show")
62 | public void show(@RequestParam(value = "path",required = true) String path,
63 | @RequestParam(value = "imagePath",required = false) String imagePath,
64 | @RequestParam(value = "color",required = false) String color,
65 | HttpServletResponse response) throws Exception{
66 |
67 | // 设置响应消息的类型
68 | response.setContentType("image/png");
69 |
70 | // 设置页面不缓存
71 | response.setHeader("Cache-Control", "no-cache");
72 | response.setHeader("Pragma", "no-cache");
73 | response.setDateHeader("Expires", 0);
74 | shpService.showShp(path, imagePath,color ,response);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/exception/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.appleyk.exception;
2 |
3 |
4 | import com.appleyk.result.ResponseResult;
5 | import org.springframework.web.bind.annotation.CrossOrigin;
6 | import org.springframework.web.bind.annotation.ExceptionHandler;
7 | import org.springframework.web.bind.annotation.RestControllerAdvice;
8 |
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 |
12 |
13 | /**
14 | * 全局异常捕获处理类
15 | * @author Appleyk
16 | * @blob https://blog.csdn.net/appleyk
17 | * @date Created on 上午 2018年10月25日09:57:57
18 | */
19 | @CrossOrigin
20 | @RestControllerAdvice
21 | public class GlobalExceptionHandler {
22 |
23 | @ExceptionHandler
24 | public ResponseResult processException(Exception ex, HttpServletRequest request, HttpServletResponse response)
25 | throws Exception {
26 |
27 | return new ResponseResult(400, ex);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/geotools/GeometryCreator.java:
--------------------------------------------------------------------------------
1 | package com.appleyk.geotools;
2 |
3 | import org.geotools.geojson.geom.GeometryJSON;
4 | import org.locationtech.jts.geom.*;
5 | import org.locationtech.jts.io.ParseException;
6 | import org.locationtech.jts.io.WKTReader;
7 |
8 | import java.io.StringReader;
9 | import java.io.StringWriter;
10 | import java.util.List;
11 |
12 | /**
13 | * 自定义几何对象构造器
14 | * @author Appleyk
15 | * @blob https://blog.csdn.net/appleyk
16 | * @date Created on 上午 11:54 2018-10-12
17 | */
18 | public class GeometryCreator {
19 |
20 |
21 | private static GeometryCreator geometryCreator = null;
22 | private static GeometryFactory geometryFactory = new GeometryFactory();
23 |
24 | /**
25 | * 设置保留6位小数,否则GeometryJSON默认保留4位小数
26 | */
27 | private static GeometryJSON geometryJson = new GeometryJSON(6);
28 |
29 |
30 | private GeometryCreator() {
31 | }
32 |
33 | /**
34 | * 返回本类的唯一实例
35 | * @return
36 | */
37 | public static GeometryCreator getInstance() {
38 | if (geometryCreator == null) {
39 | return new GeometryCreator();
40 | }
41 | return geometryCreator;
42 | }
43 |
44 |
45 | /**
46 | * 1.1根据X,Y坐标构建一个几何对象: 点 【Point】
47 | * @param x
48 | * @param y
49 | * @return
50 | */
51 | public Point createPoint(double x,double y){
52 | Coordinate coord = new Coordinate(x, y);
53 | return geometryFactory.createPoint(coord);
54 | }
55 |
56 | /**
57 | * 1.2根据几何对象的WKT描述【String】创建几何对象: 点 【Point】
58 | * @return
59 | * @throws ParseException
60 | */
61 | public Point createPointByWKT(String PointWKT) throws ParseException {
62 | WKTReader reader = new WKTReader(geometryFactory);
63 | return (Point) reader.read(PointWKT);
64 | }
65 |
66 | /**
67 | * 1.3根据几何对象的WKT描述【String】创建几何对象:多点 【MultiPoint】
68 | * @return
69 | * @throws ParseException
70 | */
71 | public MultiPoint createMulPointByWKT(String MPointWKT)throws ParseException{
72 | WKTReader reader = new WKTReader( geometryFactory );
73 | return (MultiPoint) reader.read(MPointWKT);
74 | }
75 |
76 | /**
77 | * 2.1根据两点 创建几何对象:线 【LineString】
78 | * @param ax 第一个点的x坐标
79 | * @param ay 第一个点的y坐标
80 | * @param bx 第二个点的x坐标
81 | * @param by 第二个点的y坐标
82 | * @return
83 | */
84 | public LineString createLine(double ax,double ay,double bx,double by){
85 | Coordinate[] coords = new Coordinate[] {new Coordinate(ax, ay), new Coordinate(bx, by)};
86 | return geometryFactory.createLineString(coords);
87 | }
88 |
89 | /**
90 | * 2.2根据线的WKT描述创建几何对象:线 【LineString】
91 | * @param LineStringWKT
92 | * @return
93 | * @throws ParseException
94 | */
95 | public LineString createLineByWKT(String LineStringWKT) throws ParseException{
96 | WKTReader reader = new WKTReader( geometryFactory );
97 | return (LineString) reader.read(LineStringWKT);
98 | }
99 |
100 | /**
101 | * 2.3根据点组合的线数组,创建几何对象:多线 【MultiLineString】
102 | * @param list
103 | * @return
104 | */
105 | public MultiLineString createMLine(List list){
106 |
107 | if(list == null){
108 | return null;
109 | }
110 |
111 | LineString[] lineStrings = new LineString[list.size()];
112 | int i = 0;
113 | for (Coordinate[] coordinates : list) {
114 | lineStrings[i] = geometryFactory.createLineString(coordinates);
115 | }
116 |
117 | return geometryFactory.createMultiLineString(lineStrings);
118 | }
119 |
120 |
121 | /**
122 | * 2.4根据几何对象的WKT描述【String】创建几何对象 : 多线【MultiLineString】
123 | * @param MLineStringWKT
124 | * @return
125 | * @throws ParseException
126 | */
127 | public MultiLineString createMLineByWKT(String MLineStringWKT)throws ParseException{
128 | WKTReader reader = new WKTReader( geometryFactory );
129 | return (MultiLineString) reader.read(MLineStringWKT);
130 | }
131 |
132 |
133 | /**
134 | * 3.1 根据几何对象的WKT描述【String】创建几何对象:多边形 【Polygon】
135 | * @param PolygonWKT
136 | * @return
137 | * @throws ParseException
138 | */
139 | public Polygon createPolygonByWKT(String PolygonWKT) throws ParseException{
140 | WKTReader reader = new WKTReader( geometryFactory );
141 | return (Polygon) reader.read(PolygonWKT);
142 | }
143 |
144 | /**
145 | * 3.2 根据几何对象的WKT描述【String】创建几何对象: 多多边形 【MultiPolygon】
146 | * @param MPolygonWKT
147 | * @return
148 | * @throws ParseException
149 | */
150 | public MultiPolygon createMulPolygonByWKT(String MPolygonWKT) throws ParseException{
151 | WKTReader reader = new WKTReader( geometryFactory );
152 | return (MultiPolygon) reader.read(MPolygonWKT);
153 | }
154 |
155 | /**
156 | * 根据多边形数组 进行多多边形的创建
157 | * @param polygons
158 | * @return
159 | * @throws ParseException
160 | */
161 | public MultiPolygon createMulPolygonByPolygon(Polygon[] polygons) throws ParseException{
162 | return geometryFactory.createMultiPolygon(polygons);
163 | }
164 |
165 | /**
166 | * 4.1 根据几何对象数组,创建几何对象集合:【GeometryCollection】
167 | * @return
168 | * @throws ParseException
169 | */
170 | public GeometryCollection createGeoCollect(Geometry[] geoArray) throws ParseException{
171 | return geometryFactory.createGeometryCollection(geoArray);
172 | }
173 |
174 | /**
175 | * 5.1 根据圆点以及半径创建几何对象:特殊的多边形--圆 【Polygon】
176 | * @param x 圆点x坐标
177 | * @param y 圆点y坐标
178 | * @param radius 半径
179 | * @return
180 | */
181 | public Polygon createCircle(double x, double y, final double radius){
182 |
183 | //圆上面的点个数
184 | final int sides = 32;
185 | Coordinate[] coords = new Coordinate[sides+1];
186 | for( int i = 0; i < sides; i++){
187 | double angle = ((double) i / (double) sides) * Math.PI * 2.0;
188 | double dx = Math.cos( angle ) * radius;
189 | double dy = Math.sin( angle ) * radius;
190 | coords[i] = new Coordinate( (double) x + dx, (double) y + dy );
191 | }
192 | coords[sides] = coords[0];
193 | //线性环
194 | LinearRing ring = geometryFactory.createLinearRing(coords);
195 | return geometryFactory.createPolygon(ring, null);
196 | }
197 |
198 |
199 | /**
200 | * 6.1 根据WKT创建环
201 | * @param ringWKT
202 | * @return
203 | * @throws ParseException
204 | */
205 | public LinearRing createLinearRingByWKT(String ringWKT) throws ParseException{
206 | WKTReader reader = new WKTReader( geometryFactory );
207 | return (LinearRing) reader.read(ringWKT);
208 | }
209 |
210 | /**
211 | * 几何对象转GeoJson对象
212 | * @param geometry
213 | * @return
214 | * @throws Exception
215 | */
216 | public static String geometryToGeoJson(Geometry geometry) throws Exception {
217 | if (geometry == null) {
218 | return null;
219 | }
220 | StringWriter writer = new StringWriter();
221 | geometryJson.write(geometry, writer);
222 | String geojson = writer.toString();
223 | writer.close();
224 | return geojson;
225 | }
226 |
227 | /**
228 | * GeoJson转几何对象
229 | * @param geojson
230 | * @return
231 | * @throws Exception
232 | */
233 | public static Geometry geoJsonToGeometry(String geojson) throws Exception {
234 | return geometryJson.read(new StringReader(geojson));
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/geotools/ShpTools.java:
--------------------------------------------------------------------------------
1 | package com.appleyk.geotools;
2 |
3 | import com.appleyk.IO.StringTokenReader;
4 | import com.appleyk.pojos.ShpDatas;
5 | import com.appleyk.pojos.ShpInfo;
6 | import com.appleyk.result.ResponseMessage;
7 | import com.appleyk.result.ResponseResult;
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.geotools.data.*;
10 | import org.geotools.data.shapefile.ShapefileDataStore;
11 | import org.geotools.data.shapefile.ShapefileDataStoreFactory;
12 | import org.geotools.data.simple.SimpleFeatureSource;
13 | import org.geotools.feature.FeatureCollection;
14 | import org.geotools.feature.FeatureIterator;
15 | import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
16 | import org.geotools.geometry.jts.ReferencedEnvelope;
17 | import org.geotools.map.FeatureLayer;
18 | import org.geotools.map.Layer;
19 | import org.geotools.map.MapContent;
20 | import org.geotools.referencing.crs.DefaultGeographicCRS;
21 | import org.geotools.renderer.lite.StreamingRenderer;
22 | import org.geotools.styling.SLD;
23 | import org.geotools.styling.Style;
24 | import org.geotools.swing.JMapFrame;
25 | import org.geotools.swing.data.JFileDataStoreChooser;
26 | import org.locationtech.jts.geom.*;
27 | import org.locationtech.jts.geom.Point;
28 | import org.locationtech.jts.geom.Polygon;
29 | import org.opengis.feature.Property;
30 | import org.opengis.feature.simple.SimpleFeature;
31 | import org.opengis.feature.simple.SimpleFeatureType;
32 | import org.springframework.util.ResourceUtils;
33 |
34 | import javax.imageio.ImageIO;
35 | import javax.servlet.http.HttpServletResponse;
36 | import java.awt.*;
37 | import java.awt.image.BufferedImage;
38 | import java.io.File;
39 | import java.io.IOException;
40 | import java.io.Serializable;
41 | import java.nio.charset.Charset;
42 | import java.nio.charset.StandardCharsets;
43 | import java.text.SimpleDateFormat;
44 | import java.util.Collection;
45 | import java.util.HashMap;
46 | import java.util.Map;
47 |
48 | /**
49 | * ShapeFile文件读写工具类
50 | * @author Appleyk
51 | * @blob https://blog.csdn.net/appleyk
52 | * @date Created on 上午 11:54 2018-10-12
53 | */
54 | public class ShpTools {
55 |
56 | /**几何对象构造器【自定义的】*/
57 | private static GeometryCreator gCreator = GeometryCreator.getInstance();
58 |
59 | /**边界*/
60 | private static ReferencedEnvelope bounds;
61 |
62 | /**画布的宽度*/
63 | private static final int IMAGE_WIDTH = 1280;
64 |
65 | /**画布的高度*/
66 | private static final int IMAGE_HEIGHT = 1200;
67 |
68 | /**
69 | * 通过shp文件路径,读取shp内容
70 | * @param filePath 文件路径
71 | */
72 | public static ShpDatas readShpByPath(String filePath,Integer limit) throws Exception {
73 |
74 | // 一个数据存储实现,允许从Shapefiles读取和写入
75 | ShapefileDataStore shpDataStore = new ShapefileDataStore(new File(filePath).toURI().toURL());
76 | // 设置编码【防止中文乱码】
77 | shpDataStore.setCharset(StandardCharsets.UTF_8);
78 |
79 | // getTypeNames:获取所有地理图层,这里我只取第一个【如果是数据表,取出的就是表名】
80 | String typeName = shpDataStore.getTypeNames()[0];
81 | System.out.println("shp【图层】名称:"+typeName);
82 | FeatureCollection result = getFeatures(shpDataStore, typeName);
83 |
84 | // 迭代特征集合
85 | FeatureIterator iterator = result.features();
86 |
87 | ShpDatas shpDatas = new ShpDatas();
88 | shpDatas.setName(typeName);
89 | shpDatas.setShpPath(filePath);
90 | buildShpDatas(limit, iterator, shpDatas);
91 | iterator.close();
92 | return shpDatas;
93 | }
94 |
95 |
96 | /**
97 | * 根据数据源及图层名称拿到特征集合
98 | * @param shpDataStore shp数据存储对象
99 | * @param typeName 图层名称
100 | * @return FeatureCollection
101 | */
102 | private static FeatureCollection getFeatures(ShapefileDataStore shpDataStore, String typeName) throws IOException {
103 |
104 | // 通过此接口可以引用单个shapefile、数据库表等。与数据存储进行比较和约束
105 | FeatureSource featureSource = shpDataStore.getFeatureSource(typeName);
106 | // 一个用于处理FeatureCollection的实用工具类。提供一个获取FeatureCollection实例的机制
107 | FeatureCollection result = featureSource.getFeatures();
108 | System.out.println("地理要素【记录】:"+result.size()+"个");
109 | System.out.println("==================================");
110 | return result;
111 | }
112 |
113 | /**
114 | * 构建shpDatas对象
115 | * @param limit 要素查询限制数
116 | * @param iterator 迭代器
117 | * @param shpDatas shp封装的数据集
118 | */
119 | private static void buildShpDatas(Integer limit, FeatureIterator iterator, ShpDatas shpDatas) {
120 | // 这里我们只迭代前limit个
121 | int stop = 0;
122 | while (iterator.hasNext()) {
123 | if (stop > limit) {
124 | break;
125 | }
126 | // 拿到一个特征
127 | SimpleFeature feature = iterator.next();
128 | // 取出特征里面的属性集合
129 | Collection p = feature.getProperties();
130 |
131 | // 遍历属性集合
132 | Map prop = new HashMap<>();
133 | for (Property pro : p) {
134 | String key = pro.getName().toString();
135 | String val;
136 | if ("java.util.Date".equals(pro.getType().getBinding().getName())){
137 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
138 | val = pro.getValue() ==null ? "" : dateFormat.format(pro.getValue());
139 | }else{
140 | val = pro.getValue()==null ?"":pro.getValue().toString();
141 | }
142 | prop.put(key, val);
143 | System.out.println("key【字段】:"+key+"\t||value【值】:"+val);
144 | }
145 | System.out.println("\n============================ 序号:"+stop+"\n");
146 | shpDatas.addProp(prop);
147 | stop++;
148 | } // end 最外层 while
149 | }
150 |
151 | /**
152 | * 将一个几何对象写进shapefile
153 | * @param filePath 文件路径
154 | * @param geometry 几何对象
155 | */
156 | public static void writeShpByGeom(String filePath, Geometry geometry) throws Exception{
157 |
158 | ShapefileDataStore ds = getshpDS(filePath, geometry);
159 |
160 | FeatureWriter writer = ds.getFeatureWriter(ds.getTypeNames()[0],
161 | Transaction.AUTO_COMMIT);
162 |
163 | // Interface SimpleFeature:一个由固定列表值以已知顺序组成的SimpleFeatureType实例。
164 | SimpleFeature feature = writer.next();
165 | feature.setAttribute("name", "XXXX名称");
166 | feature.setAttribute("path", "c:/test");
167 | feature.setAttribute("the_geom", geometry);
168 | feature.setAttribute("id", 1010L);
169 | feature.setAttribute("des", "XXXX描述");
170 |
171 | System.out.println("========= 写入【"+geometry.getGeometryType()+"】成功 !=========");
172 |
173 | // 写入
174 | writer.write();
175 | // 关闭
176 | writer.close();
177 | // 释放资源
178 | ds.dispose();
179 | }
180 |
181 |
182 | /**
183 | * 将一个几何对象写进shapefile
184 | * @param shpInfo shp信息
185 | */
186 | public static ResponseResult writeShpByGeom(ShpInfo shpInfo) throws Exception{
187 |
188 | // 特殊字符串解析器
189 | StringTokenReader reader = new StringTokenReader();
190 | // 根据几何对象的wkt字符串,反解【解析】成Geometry对象
191 | Geometry geometry = reader.read(shpInfo.getGeom());
192 | // 拿到shp对象所在的目录【文件夹】
193 | String path = shpInfo.getPath();
194 | File file = new File(path);
195 | if(!file.exists()){
196 | file.mkdir();
197 | }
198 |
199 | if(!file.isDirectory()){
200 | return new ResponseResult(ResponseMessage.BAD_REQUEST,"path不是有效的文件夹" );
201 | }
202 |
203 | String filePath = shpInfo.getPath()+"/"+shpInfo.getName()+".shp";
204 | ShapefileDataStore ds = getshpDS(filePath, geometry);
205 | String typeName = ds.getTypeNames()[0];
206 | FeatureWriter writer ;
207 | if(shpInfo.isAppendWrite()){
208 | // 追加写几何对象
209 | writer = ds.getFeatureWriterAppend(typeName, Transaction.AUTO_COMMIT);
210 | }else{
211 | // 覆盖写几何对象
212 | writer = ds.getFeatureWriter(typeName, Transaction.AUTO_COMMIT);
213 | }
214 |
215 | // Interface SimpleFeature:一个由固定列表值以已知顺序组成的SimpleFeatureType实例。
216 | SimpleFeature feature = writer.next();
217 | feature.setAttribute("name", shpInfo.getName());
218 | feature.setAttribute("path", shpInfo.getPath());
219 | feature.setAttribute("the_geom", geometry);
220 | feature.setAttribute("id", shpInfo.getId());
221 | feature.setAttribute("des", shpInfo.getDes());
222 |
223 | System.out.println("========= 写入【"+geometry.getGeometryType()+"】成功 !=========");
224 |
225 | // 写入
226 | writer.write();
227 | // 关闭
228 | writer.close();
229 | // 释放资源
230 | ds.dispose();
231 | // 返回创建成功后的shp文件路径
232 | return new ResponseResult(ResponseMessage.OK,filePath);
233 |
234 | }
235 |
236 | /**
237 | * 拿到配置好的DataStore
238 | * @param filePath 文件路径
239 | * @param geometry 几何对象
240 | * @return ShapefileDataStore
241 | */
242 | private static ShapefileDataStore getshpDS(String filePath, Geometry geometry) throws IOException {
243 | // 1.创建shape文件对象
244 | File file = new File(filePath);
245 |
246 | Map params = new HashMap<>();
247 |
248 | // 2、用于捕获参数需求的数据类 URLP:url to the .shp file.
249 | params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
250 |
251 | // 3、创建一个新的数据存储【如果存在,则不创建】
252 | ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
253 |
254 | // 4、定义图形信息和属性信息 -- SimpleFeatureTypeBuilder 构造简单特性类型的构造器
255 | SimpleFeatureTypeBuilder tBuilder = new SimpleFeatureTypeBuilder();
256 |
257 | // 5、设置 -- WGS84:一个二维地理坐标参考系统,使用WGS84数据
258 | tBuilder.setCRS(DefaultGeographicCRS.WGS84);
259 | tBuilder.setName("shapefile");
260 |
261 | // 添加名称
262 | tBuilder.add("name", String.class);
263 | // 添加shp所在目录名称
264 | tBuilder.add("path", String.class);
265 | // 添加 一个几何对象
266 | tBuilder.add("the_geom", geometry.getClass());
267 | // 添加一个id
268 | tBuilder.add("id", Long.class);
269 | // 添加描述
270 | tBuilder.add("des", String.class);
271 |
272 | // 设置此数据存储的特征类型
273 | ds.createSchema(tBuilder.buildFeatureType());
274 | // 设置编码
275 | ds.setCharset(StandardCharsets.UTF_8);
276 | return ds;
277 | }
278 |
279 | /**
280 | * 打开shp文件,获取地图内容
281 | * @param filePath 文件路径
282 | * @param isOpenByChoose 是否自定义打开shp文件
283 | * @throws Exception
284 | */
285 | public static MapContent getMapContentByPath(String filePath,boolean isOpenByChoose,String color) throws Exception{
286 |
287 | File file;
288 | if(isOpenByChoose){
289 | // 1.1、 数据源选择 shp扩展类型的
290 | file = JFileDataStoreChooser.showOpenFile("shp", null);
291 | }else{
292 | // 1.2、根据路径拿到文件对象
293 | file = new File(filePath);
294 | }
295 |
296 | if(file==null){
297 | return null;
298 | }
299 | // 2、得到打开的文件的数据源
300 | FileDataStore store = FileDataStoreFinder.getDataStore(file);
301 |
302 | // 3、设置数据源的编码,防止中文乱码
303 | ((ShapefileDataStore)store).setCharset(Charset.forName("UTF-8"));
304 |
305 | /**
306 | * 使用FeatureSource管理要素数据
307 | * 使用Style(SLD)管理样式
308 | * 使用Layer管理显示
309 | * 使用MapContent管理所有地图相关信息
310 | */
311 |
312 | // 4、以java对象的方式访问地理信息 -- 简单地理要素
313 | SimpleFeatureSource featureSource = store.getFeatureSource();
314 |
315 | bounds = featureSource.getBounds();
316 |
317 | // 5、创建映射内容,并将我们的shapfile添加进去
318 | MapContent mapContent = new MapContent();
319 |
320 | // 6、设置容器的标题
321 | mapContent.setTitle("Appleyk's GeoTools");
322 | Color color1;
323 | if(color == null || "".equals(color.toLowerCase())){
324 | color1 = Color.BLACK;
325 | }else if("red".equals(color.toLowerCase())){
326 | color1 = Color.RED;
327 | }else if("green".equals(color.toLowerCase())){
328 | color1 = Color.GREEN;
329 | }else if("blue".equals(color.toLowerCase())){
330 | color1 = Color.BLUE;
331 | }else{
332 | color1 = Color.getColor(color);
333 | }
334 |
335 | // 7、创建简单样式 【颜色填充】
336 | Style style = SLD.createSimpleStyle(featureSource.getSchema(),color1);
337 |
338 | // 8、显示【shapfile地理信息+样式】
339 | Layer layer = new FeatureLayer(featureSource, style);
340 |
341 | // 9、将显示添加进map容器
342 | mapContent.addLayer(layer);
343 |
344 | return mapContent;
345 | }
346 |
347 | public static void showMap(MapContent mapContent){
348 | JMapFrame.showMap(mapContent);
349 | }
350 |
351 | /**
352 | * shp文件转Image【格式定png】
353 | * @param shpFilePath shp目标文件
354 | * @param destImagePath 转成图片的文件 == 如果没有,转成的图片写进response输出流里
355 | * @param response 响应流
356 | * @throws Exception
357 | */
358 | public static void shp2Image(String shpFilePath,String destImagePath,String color, HttpServletResponse response) throws Exception{
359 |
360 | // 流渲染器
361 | StreamingRenderer renderer = new StreamingRenderer();
362 | MapContent mapContent = getMapContentByPath(shpFilePath,false,color );
363 | renderer.setMapContent(mapContent);
364 | Rectangle imageBounds = new Rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
365 | BufferedImage dumpImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
366 | Graphics2D g2d = dumpImage.createGraphics();
367 | g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
368 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
369 | renderer.paint(g2d, imageBounds, bounds);
370 | g2d.dispose();
371 | if(destImagePath == null || "".equals(destImagePath)){
372 | ImageIO.write(dumpImage, "png", response.getOutputStream());
373 | }else{
374 | ImageIO.write(dumpImage, "png", new File(destImagePath));
375 | }
376 | }
377 |
378 | public static void main(String[] args) throws Exception{
379 |
380 | File file = ResourceUtils.getFile("classpath:static/shpTest[Point]/dp_tl.shp");
381 | // 从shp文件里面读取属性信息
382 | readShpByPath(file.getAbsolutePath(),10);
383 | System.out.println("=================下面开始往shp文件里面写几何对象===================");
384 |
385 | // 先创建文件夹test
386 | String filePath = "C:/test/test.shp";
387 |
388 | String pointWkt="POINT (120.76164848270959 31.22001141278534)";
389 | Point point = gCreator.createPointByWKT(pointWkt);
390 |
391 | // Polygon【面】
392 | String polygonWkt="POLYGON ((103.859188 34.695908, 103.85661 34.693788, 103.862027 34.69259, 103.863709 34.695078, 103.859188 34.695908))";
393 | Polygon polygon = gCreator.createPolygonByWKT(polygonWkt);
394 |
395 | // LineString【线】
396 | String linestringWkt="LINESTRING(113.511315990174 41.7274734296674,113.51492087909 41.7284983348307,113.516079593384 41.727649586406,113.515907932007 41.7262243043929,113.514019656861 41.7247989907606,113.512131381714 41.7250872589898,113.51138036319 41.7256637915682,113.511315990174 41.7274734296674)";
397 | LineString lineString = gCreator.createLineByWKT(linestringWkt);
398 |
399 | // MultiPolygon【多面】
400 | String multiPolyWkt = "MULTIPOLYGON(((101.870371 25.19228,101.873633 25.188183,101.880564 25.184416,101.886808 25.186028,101.892043 25.189969,101.896592 25.190163,101.903716 25.190785,101.905454 25.193464,101.899897 25.196202,101.894146 25.197911,101.891657 25.19826,101.886078 25.197658,101.884211145538 25.2007060137013,101.88172564506 25.1949712942389,101.87874 25.199619,101.874641 25.200998,101.868547 25.202415,101.863741 25.202415,101.85887 25.202842,101.854557 25.202182,101.852604 25.199736,101.852282 25.19628,101.854492 25.194183,101.855608 25.192668,101.863698 25.192105,101.870371 25.19228)))";
401 | MultiPolygon multiPolygon = gCreator.createMulPolygonByWKT(multiPolyWkt);
402 |
403 | // 几何对象的范围【矩形边界】
404 | Envelope envelope = polygon.getEnvelopeInternal();
405 | System.out.println(envelope);
406 |
407 | // 往shp文件里面写几何对象
408 | writeShpByGeom(filePath,point);
409 | }
410 |
411 | }
412 |
--------------------------------------------------------------------------------
/src/main/java/com/appleyk/pojos/ShpDatas.java:
--------------------------------------------------------------------------------
1 | package com.appleyk.pojos;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Map;
6 |
7 | /**
8 | * shp数据模型对象 -- 针对读
9 | * @author Appleyk
10 | * @blob https://blog.csdn.net/appleyk
11 | * @date Created on 下午 2018年10月24日16:31:30
12 | */
13 | public class ShpDatas {
14 |
15 | private String name;
16 |
17 | /** 属性【字段】集合*/
18 | private List