diff --git a/pom.xml b/pom.xml
index 32f6df1..5348ee9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,11 +101,14 @@
org.springframework.boot
spring-boot-starter-data-jpa
-
- com.h2database
- h2
+
+
+
+ com.h2database
+ h2
+ 1.4.200
runtime
-
+
diff --git a/src/main/java/osm/surveyor/task/city/CityService.java b/src/main/java/osm/surveyor/task/city/CityService.java
index a705409..b24916e 100644
--- a/src/main/java/osm/surveyor/task/city/CityService.java
+++ b/src/main/java/osm/surveyor/task/city/CityService.java
@@ -8,8 +8,9 @@
import org.springframework.transaction.annotation.Transactional;
import osm.surveyor.task.city.model.City;
-import osm.surveyor.task.city.model.Citymesh;
import osm.surveyor.task.city.model.Status;
+import osm.surveyor.task.mesh.CitymeshRepository;
+import osm.surveyor.task.mesh.model.Citymesh;
@Service
@Transactional // メソッド開始時にトランザクションを開始、終了時にコミットする
diff --git a/src/main/java/osm/surveyor/task/city/CitymeshController.java b/src/main/java/osm/surveyor/task/city/CitymeshController.java
deleted file mode 100644
index ed61e5a..0000000
--- a/src/main/java/osm/surveyor/task/city/CitymeshController.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package osm.surveyor.task.city;
-
-import java.util.List;
-
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-
-import lombok.RequiredArgsConstructor;
-import osm.surveyor.task.city.model.City;
-import osm.surveyor.task.city.model.Citymesh;
-
-@RequiredArgsConstructor
-@Controller
-public class CitymeshController {
- private final CitymeshRepository meshRepository;
- private final CityRepository cityRepository;
-
- @GetMapping("/mesh/{citycode}")
- public String showList(@PathVariable String citycode, Model model) {
- City city = cityRepository.findByCitycode(citycode);
- List tasks = meshRepository.findByCitycode(citycode);
- model.addAttribute("city", city);
- model.addAttribute("meshes", tasks);
- return "meshes";
- }
-
-}
diff --git a/src/main/java/osm/surveyor/task/city/CitymeshRepository.java b/src/main/java/osm/surveyor/task/city/CitymeshRepository.java
deleted file mode 100644
index abb7a41..0000000
--- a/src/main/java/osm/surveyor/task/city/CitymeshRepository.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package osm.surveyor.task.city;
-
-import java.util.List;
-
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-
-import osm.surveyor.task.city.model.Citymesh;
-import osm.surveyor.task.city.model.CitymeshPK;
-
-public interface CitymeshRepository extends JpaRepository {
-
- @Query("SELECT m FROM Citymesh m WHERE m.citycode = :citycode AND m.meshcode = :meshcode")
- Citymesh findOne(@Param("citycode")String citycode, @Param("meshcode")String meshcode);
-
- List findByCitycode(String citycode);
-
- @Query("SELECT m FROM Citymesh m WHERE m.username = :username order by citycode,meshcode")
- List serchByUser(@Param("username")String username);
-}
diff --git a/src/main/java/osm/surveyor/task/city/ConflictException.java b/src/main/java/osm/surveyor/task/city/ConflictException.java
index a634dc5..b525620 100644
--- a/src/main/java/osm/surveyor/task/city/ConflictException.java
+++ b/src/main/java/osm/surveyor/task/city/ConflictException.java
@@ -1,5 +1,7 @@
package osm.surveyor.task.city;
+import osm.surveyor.task.task.TaskException;
+
/**
* 409 Conflict
* "タスクが変更されたため更新できません"
diff --git a/src/main/java/osm/surveyor/task/city/DataLoader.java b/src/main/java/osm/surveyor/task/city/DataLoader.java
index c3ba91b..de04bb2 100644
--- a/src/main/java/osm/surveyor/task/city/DataLoader.java
+++ b/src/main/java/osm/surveyor/task/city/DataLoader.java
@@ -16,9 +16,11 @@
import osm.surveyor.task.city.model.CitiesJson;
import osm.surveyor.task.city.model.City;
import osm.surveyor.task.city.model.CityJson;
-import osm.surveyor.task.city.model.Citymesh;
import osm.surveyor.task.city.model.Status;
-import osm.surveyor.task.city.model.TaskEntity;
+import osm.surveyor.task.mesh.CitymeshRepository;
+import osm.surveyor.task.mesh.model.Citymesh;
+import osm.surveyor.task.task.TaskService;
+import osm.surveyor.task.task.model.TaskEntity;
import osm.surveyor.task.util.Geojson;
import osm.surveyor.task.util.JsonFeature;
import osm.surveyor.task.util.JsonGeometryLine;
diff --git a/src/main/java/osm/surveyor/task/city/NotAcceptableException.java b/src/main/java/osm/surveyor/task/city/NotAcceptableException.java
index 3daeb07..35b9e38 100644
--- a/src/main/java/osm/surveyor/task/city/NotAcceptableException.java
+++ b/src/main/java/osm/surveyor/task/city/NotAcceptableException.java
@@ -1,5 +1,7 @@
package osm.surveyor.task.city;
+import osm.surveyor.task.task.TaskException;
+
/**
* 406 Not Acceptable
* "ACCEPTIONGではないため予約できません"
diff --git a/src/main/java/osm/surveyor/task/city/TaskController.java b/src/main/java/osm/surveyor/task/city/TaskController.java
deleted file mode 100644
index d0fe3ea..0000000
--- a/src/main/java/osm/surveyor/task/city/TaskController.java
+++ /dev/null
@@ -1,300 +0,0 @@
-package osm.surveyor.task.city;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.UUID;
-
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.validation.BindingResult;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import lombok.RequiredArgsConstructor;
-import osm.surveyor.task.city.model.City;
-import osm.surveyor.task.city.model.Citymesh;
-import osm.surveyor.task.city.model.CitymeshPK;
-import osm.surveyor.task.city.model.Operation;
-import osm.surveyor.task.city.model.Status;
-import osm.surveyor.task.city.model.TaskEntity;
-
-@RequiredArgsConstructor
-@Controller
-public class TaskController {
- private final CityRepository cityRepository;
- private final CitymeshRepository meshRepository;
- private final TaskRepository taskRepository;
-
- @Autowired
- private TaskService service;
-
- @Autowired
- private CityService cityService;
-
- /**
- * ログインユーザーが関係しているTASKリスト
- * @param model
- * @return
- */
- @GetMapping("/tasks")
- public String showList(Model model,
- @RequestParam(name="citycode") String citycode,
- @RequestParam(name="meshcode") String meshcode)
- {
- City city = cityRepository.findByCitycode(citycode);
- model.addAttribute("citycode", citycode);
- model.addAttribute("cityname", city.getCityname());
- model.addAttribute("meshcode", meshcode);
- model.addAttribute("site", city.getSite());
-
- Citymesh mesh = meshRepository.findOne(citycode,meshcode);
- model.addAttribute("mesh", mesh);
-
- String meshstr = "{}";
- try {
- ObjectMapper objectMapper = new ObjectMapper();
- meshstr = objectMapper.writeValueAsString(mesh);
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
- model.addAttribute("meshstr", meshstr);
-
- model.addAttribute("mesh", mesh);
-
- String citystr = "{}";
- try {
- ObjectMapper objectMapper = new ObjectMapper();
- citystr = objectMapper.writeValueAsString(city);
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
- model.addAttribute("citystr", citystr);
-
- List tasks = taskRepository.serchByMesh(citycode, meshcode);
- model.addAttribute("tasks", tasks);
- return "tasks";
- }
-
- /**
- * 「タスク操作」
- * @param citycode
- * @param meshcode
- * @param task
- * @return
- */
- @GetMapping("/task/add")
- public String addTask(Model model,
- @RequestParam(name="op") String op,
- @RequestParam(name="citycode") String citycode,
- @RequestParam(name="meshcode") String meshcode)
- {
- String next = "task";
- Operation operation = Operation.NOP;
- Status nextStatus = Status.ACCEPTING;
- if (op.equals(Operation.RESERVE.toString())) {
- model.addAttribute("command", "編集者登録");
- operation = Operation.RESERVE;
- nextStatus = Status.RESERVED;
- }
- else if (op.equals(Operation.CANCEL.toString())) {
- model.addAttribute("command", "編集取消");
- operation = Operation.CANCEL;
- nextStatus = Status.ACCEPTING;
- }
- else if (op.equals(Operation.OK.toString())) {
- model.addAttribute("command", "編集完了");
- operation = Operation.OK;
- nextStatus = Status.OK;
- next = "task_done";
- }
- else if (op.equals(Operation.NG.toString())) {
- model.addAttribute("command", "編集(NG)");
- operation = Operation.NG;
- nextStatus = Status.ACCEPTING;
- }
-
- City city = cityRepository.getById(citycode);
- model.addAttribute("citycode", citycode);
- model.addAttribute("cityname", city.getCityname());
- model.addAttribute("meshcode", meshcode);
-
- CitymeshPK pk = new CitymeshPK();
- pk.setCitycode(citycode);
- pk.setMeshcode(meshcode);
- Citymesh mesh = meshRepository.getById(pk);
-
- TaskEntity pre = service.getTaskByMesh(citycode, meshcode);
- if (pre != null) {
- pre.setOperation(operation);
- pre.setStatus(nextStatus);
- model.addAttribute("task", pre);
- return next;
- }
- else {
- // 既存Taskが無い場合は生成する
- String uuid = UUID.randomUUID().toString();
- TaskEntity task = new TaskEntity();
- task.setCurrentId(uuid);
- task.setPreId(uuid);
- task.setCitycode(citycode);
- task.setMeshcode(meshcode);
- task.setMesh(mesh);
- task.setStatus(nextStatus);
- task.setUsername("");
- task.setOperation(operation);
- model.addAttribute("task", task);
- return next;
- }
- }
-
- @PostMapping("/task/process")
- public String process(@Validated @ModelAttribute TaskEntity task,
- BindingResult result)
- {
- if (result.hasErrors()) {
- // エラーがある場合
- return nextPage(task);
- }
- service.add(task);
- cityService.updateStatus(task.getCitycode());
-
- return "redirect:/tasks?citycode="+ task.getCitycode() +"&meshcode="+ task.getMeshcode();
- }
-
- @GetMapping("/admin")
- public String admin()
- {
- return "admin";
- }
-
- @PostMapping("/admin/download")
- public String download(HttpServletResponse response) {
- try (OutputStream os = response.getOutputStream();) {
- List list = taskRepository.findAll();
- StringBuffer sb = new StringBuffer();
- boolean c1 = false;
- sb.append("[");
- sb.append(System.lineSeparator());
- for (TaskEntity task : list) {
- if (c1) {
- sb.append(",");
- }
- else {
- c1 = true;
- }
- sb.append(task.toString());
- sb.append(System.lineSeparator());
- }
- sb.append("]");
- byte[] fb1 = String.valueOf(sb).getBytes();
-
- response.setContentType("application/octet-stream");
- response.setHeader("Content-Disposition", "attachment; filename="+ "task-bldg.json");
- response.setContentLength(fb1.length);
- os.write(fb1);
- os.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 400 Bad Request
- *
- * @param e
- * @param model
- * @param citycode
- * @param meshcode
- * @return
- */
- @ExceptionHandler(TaskException.class)
- public String taskExceptionHandler(TaskException e, Model model)
- {
- model.addAttribute("error", "400 Bad Request");
- model.addAttribute("message", e.getMessage());
- model.addAttribute("status", HttpStatus.BAD_REQUEST);
- return exceptionHandler(e.getTask(), model);
- }
-
- /**
- * 406 Not Acceptable
- * "ACCEPTIONGではないため予約できません"
- *
- * @param e
- * @param model
- * @param citycode
- * @param meshcode
- * @return
- */
- @ExceptionHandler(NotAcceptableException.class)
- public String notAcceptableExceptionHandler(NotAcceptableException e, Model model)
- {
- model.addAttribute("error", "406 Not Acceptable");
- model.addAttribute("message", e.getMessage());
- model.addAttribute("status", HttpStatus.NOT_ACCEPTABLE);
- return exceptionHandler(e.getTask(), model);
- }
-
- /**
- * 409 Conflict
- * "タスクが変更されたため更新できません"
- *
- * @param e
- * @param model
- * @param citycode
- * @param meshcode
- * @return
- */
- @ExceptionHandler(ConflictException.class)
- public String conflictExceptionHandler(ConflictException e, Model model)
- {
- model.addAttribute("error", "409 Conflict");
- model.addAttribute("message", e.getMessage());
- model.addAttribute("status", HttpStatus.CONFLICT);
- return exceptionHandler(e.getTask(), model);
- }
-
- private String exceptionHandler(TaskEntity task, Model model) {
- if (task == null) {
- return "error";
- }
-
- if (task.getOperation() == Operation.RESERVE) {
- model.addAttribute("command", "タスク予約");
- }
- else if (task.getOperation() == Operation.CANCEL) {
- model.addAttribute("command", "タスク予約取消");
- }
- else if (task.getOperation() == Operation.OK) {
- model.addAttribute("command", "編集済み");
- }
- else if (task.getOperation() == Operation.NG) {
- model.addAttribute("command", "編集(NG)");
- }
- model.addAttribute("citycode", task.getCitycode());
- model.addAttribute("meshcode", task.getMeshcode());
- model.addAttribute("task", task);
-
- return nextPage(task);
- }
-
- private String nextPage(TaskEntity task) {
- if (task.getOperation() == Operation.OK) {
- return "task_done";
- }
- return "task";
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/TaskException.java b/src/main/java/osm/surveyor/task/city/TaskException.java
deleted file mode 100644
index 1796ee1..0000000
--- a/src/main/java/osm/surveyor/task/city/TaskException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package osm.surveyor.task.city;
-
-import lombok.Getter;
-import lombok.Setter;
-import osm.surveyor.task.city.model.TaskEntity;
-
-@Setter
-@Getter
-public class TaskException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- private TaskEntity task;
-
- public TaskException(String errorMessage) {
- super(errorMessage);
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/TaskRepository.java b/src/main/java/osm/surveyor/task/city/TaskRepository.java
deleted file mode 100644
index 0af0f5a..0000000
--- a/src/main/java/osm/surveyor/task/city/TaskRepository.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package osm.surveyor.task.city;
-
-import java.util.List;
-
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-import osm.surveyor.task.city.model.TaskEntity;
-
-public interface TaskRepository extends JpaRepository {
-
- @Query("SELECT t FROM TaskEntity t WHERE t.citycode = :citycode AND t.meshcode = :meshcode order by update_time DESC")
- List serchByMesh(@Param("citycode")String citycode, @Param("meshcode")String meshcode);
-
-}
diff --git a/src/main/java/osm/surveyor/task/city/TaskService.java b/src/main/java/osm/surveyor/task/city/TaskService.java
deleted file mode 100644
index 34bcf13..0000000
--- a/src/main/java/osm/surveyor/task/city/TaskService.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package osm.surveyor.task.city;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import osm.surveyor.task.city.model.Citymesh;
-import osm.surveyor.task.city.model.CitymeshPK;
-import osm.surveyor.task.city.model.Operation;
-import osm.surveyor.task.city.model.Status;
-import osm.surveyor.task.city.model.TaskEntity;
-
-import javax.transaction.Transactional;
-
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-@Service
-@Transactional // メソッド開始時にトランザクションを開始、終了時にコミットする
-public class TaskService {
-
- @Autowired
- TaskRepository repository;
-
- @Autowired
- CitymeshRepository meshRepository;
-
- public void add(TaskEntity task) {
- if (task.getOperation() == Operation.RESERVE) {
- task.setStatus(Status.RESERVED);
- }
- else if (task.getOperation() == Operation.CANCEL) {
- task.setStatus(Status.PREPARATION);
- }
- else if (task.getOperation() == Operation.NG) {
- task.setStatus(Status.NG);
- }
- else if (task.getOperation() == Operation.OK) {
- task.setStatus(Status.OK);
- }
- else {
- NotAcceptableException e = new NotAcceptableException("未サポートのオペレーションです: "+ task.getOperation());
- e.setTask(task);
- throw e;
- }
-
- String uuid = UUID.randomUUID().toString();
-
- CitymeshPK pk = new CitymeshPK();
- pk.setCitycode(task.getCitycode());
- pk.setMeshcode(task.getMeshcode());
- Citymesh mesh = meshRepository.getById(pk);
-
- TaskEntity ctask = getTaskByMesh(task.getCitycode(), task.getMeshcode());
- if (ctask == null) {
- task.setPreId(uuid);
- task.setCurrentId(uuid);
- }
- else {
- if (!ctask.getCurrentId().equals(task.getCurrentId())) {
- ConflictException e = new ConflictException("他のスレッドによってタスクが変更されたため更新できませんでした。");
- e.setTask(task);
- throw e;
- }
- if (task.getOperation() == Operation.CANCEL) {
- if (ctask.getStatus() != Status.RESERVED) {
- NotAcceptableException e = new NotAcceptableException("タスクが'編集中'ではないため'編集取消'できませんでした : "+ task.getOperation());
- e.setTask(task);
- throw e;
- }
- }
- else if (task.getOperation() == Operation.OK) {
- // タスク予約していなくてもインポートできる
- // 他のマッパーが予約していてもインポート可能
- String username = task.getUsername();
- if (username == null) {
- TaskException e = new TaskException("編集者が入力されていません");
- e.setTask(task);
- throw e;
- }
- else if (username.isEmpty()) {
- TaskException e = new TaskException("編集者が入力されていません");
- e.setTask(task);
- throw e;
- }
-
- String changeset = task.getChangeSet();
- if (changeset == null) {
- TaskException e = new TaskException("変更セットNoが入力されていません");
- e.setTask(task);
- throw e;
- }
- else if (changeset.isEmpty()) {
- TaskException e = new TaskException("変更セットNoが入力されていません");
- e.setTask(task);
- throw e;
- }
- else {
- try {
- Long.parseLong(changeset);
- }
- catch (NumberFormatException nfe) {
- TaskException e = new TaskException("変更セットNoに数字以外の文字が入っています");
- e.setTask(task);
- throw e;
- }
- }
- }
- else if (task.getOperation() == Operation.NG) {
- String username = task.getUsername();
- if (username == null) {
- TaskException e = new TaskException("編集者が入力されていません");
- e.setTask(task);
- throw e;
- }
- else if (username.isEmpty()) {
- TaskException e = new TaskException("編集者が入力されていません");
- e.setTask(task);
- throw e;
- }
-
- String comment = task.getComment();
- if (comment == null || comment.isEmpty()) {
- TaskException e = new TaskException("コメントが入力されていません");
- e.setTask(task);
- throw e;
- }
- }
- task.setPreId(ctask.getCurrentId());
- task.setCurrentId(uuid);
- }
-
- task.setUpdateTime(new Date());
- mesh.setStatus(task.getStatus());
- mesh.setUsername(task.getUsername());
-
- // データベースに格納
- repository.save(task);
- meshRepository.save(mesh);
- }
-
- public TaskEntity getTaskByMesh(String citycode, String meshcode) {
- List tasks = repository.serchByMesh(citycode, meshcode);
- for (TaskEntity t : tasks) {
- return t;
- }
- return null;
- }
-
- public List getTasks() {
- return repository.findAll();
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/Citymesh.java b/src/main/java/osm/surveyor/task/city/model/Citymesh.java
deleted file mode 100644
index 033bfbb..0000000
--- a/src/main/java/osm/surveyor/task/city/model/Citymesh.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.Id;
-import javax.persistence.IdClass;
-import javax.persistence.ManyToOne;
-import javax.validation.constraints.NotBlank;
-
-import org.springframework.format.annotation.NumberFormat;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonInclude;
-
-import lombok.Data;
-import osm.surveyor.task.util.JsonGeometryLine;
-import osm.surveyor.task.util.Point;
-
-@JsonInclude(JsonInclude.Include.NON_NULL)
-@Data
-@Entity
-@IdClass(CitymeshPK.class)
-public class Citymesh {
-
- @Id
- @NumberFormat(pattern="#####")
- private String citycode; // CitymeshPK.citycode
-
- @Id
- @NumberFormat
- private String meshcode; // CitymeshPK.meshcode
-
- @ManyToOne
- @JsonIgnore
- City city; // リレーション: to City 多対1
-
- @NotBlank
- @NumberFormat
- private String lng;
-
- @NotBlank
- @NumberFormat
- private String lat;
-
- private String version;
-
- private String surveyYear;
-
- private String path;
-
- private String line;
-
- @JsonIgnore
- public void setPoint(Point p) {
- setLng(p.getLng());
- setLat(p.getLat());
- }
-
- public void setLine(JsonGeometryLine p) {
- this.line = p.toString();
- }
-
- /**
- * ステータス
- */
- @Enumerated(EnumType.ORDINAL)
- private Status status = Status.PREPARATION;
-
- /**
- * 編集者
- */
- private String username;
-
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/CitymeshPK.java b/src/main/java/osm/surveyor/task/city/model/CitymeshPK.java
deleted file mode 100644
index 2fde21d..0000000
--- a/src/main/java/osm/surveyor/task/city/model/CitymeshPK.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import java.io.Serializable;
-
-import javax.persistence.Embeddable;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@SuppressWarnings("serial")
-@Getter
-@Setter
-@Embeddable
-public class CitymeshPK implements Serializable {
- private String citycode;
- private String meshcode;
-
- public CitymeshPK() {
- }
-
- public boolean equals(Object obj) {
- if (obj instanceof CitymeshPK) {
- if (((CitymeshPK)obj).getCitycode().equals(this.citycode)) {
- if (((CitymeshPK)obj).getMeshcode().equals(this.meshcode)) {
- return true;
- }
- }
- }
- return false;
- }
-
- public int hashCode() {
- String s = this.citycode + this.meshcode;
- return s.hashCode();
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/TaskEntity.java b/src/main/java/osm/surveyor/task/city/model/TaskEntity.java
deleted file mode 100644
index 5a6d031..0000000
--- a/src/main/java/osm/surveyor/task/city/model/TaskEntity.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import java.util.Date;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.Id;
-import javax.persistence.ManyToOne;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
-import javax.validation.constraints.NotBlank;
-
-import org.springframework.format.annotation.NumberFormat;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import osm.surveyor.task.util.JsonTemple;
-
-@Data
-@EqualsAndHashCode(callSuper=false)
-@Entity
-public class TaskEntity extends JsonTemple {
-
- @Id
- @Column(name = "current_id")
- private String currentId;
-
- @NotBlank
- @Column(name = "pre_id")
- private String preId;
-
- @NumberFormat
- private String citycode; // CitymeshPK.citycode
-
- @NumberFormat
- private String meshcode; // CitymeshPK.meshcode
-
- @ManyToOne
- Citymesh mesh; // リレーション: to Citymesh 多対1
-
- /**
- * ステータス
- */
- @Enumerated(EnumType.STRING)
- private Status status = Status.PREPARATION;
-
- /**
- * 編集者
- */
- private String username;
-
- /**
- * 変更セットNo
- */
- @NumberFormat
- @Column(name = "changeset")
- private String changeSet;
-
- /**
- * コメント
- */
- private String comment;
-
- /**
- * 操作内容
- */
- @Enumerated(EnumType.ORDINAL)
- private Operation operation = Operation.NOP;
-
- /**
- * 更新日時
- */
- @Temporal(TemporalType.TIMESTAMP)
- Date updateTime;
-
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- boolean c1 = false;
- sb.append("{");
- c1 = outStr(c1, sb, "currentId", this.getCurrentId());
- c1 = outStr(c1, sb, "preId", this.getPreId());
- c1 = outStr(c1, sb, "citycode", this.getCitycode());
- c1 = outStr(c1, sb, "meshcode", this.getMeshcode());
- c1 = outStr(c1, sb, "status", this.getStatus().toString());
- c1 = outStr(c1, sb, "username", this.getUsername());
- c1 = outStr(c1, sb, "changeSet", this.getChangeSet());
- c1 = outStr(c1, sb, "comment", this.getComment());
- c1 = outStr(c1, sb, "operation", this.getOperation().toString());
- c1 = outStr(c1, sb, "updateTime", (this.getUpdateTime() == null ? "" : this.getUpdateTime().toString()));
- sb.append("}");
- return sb.toString();
- }
-
- @Override
- public void parse(JsonNode node) {
- // TODO
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/TaskPK.java b/src/main/java/osm/surveyor/task/city/model/TaskPK.java
deleted file mode 100644
index b9076ac..0000000
--- a/src/main/java/osm/surveyor/task/city/model/TaskPK.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import java.io.Serializable;
-
-import javax.persistence.Embeddable;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@SuppressWarnings("serial")
-@Getter
-@Setter
-@Embeddable
-public class TaskPK implements Serializable {
- private String currentId;
-
- public TaskPK() {
- }
-
- public boolean equals(Object obj) {
- if (obj instanceof TaskPK) {
- if (((TaskPK)obj).getCurrentId().equals(this.currentId)) {
- return true;
- }
- }
- return false;
- }
-
- public int hashCode() {
- String s = this.currentId;
- return s.hashCode();
- }
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/TaskStatusEntity.java b/src/main/java/osm/surveyor/task/city/model/TaskStatusEntity.java
deleted file mode 100644
index 06880bd..0000000
--- a/src/main/java/osm/surveyor/task/city/model/TaskStatusEntity.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-@Getter
-@NoArgsConstructor
-@AllArgsConstructor
-@Entity
-@Table(name = "task_status")
-public class TaskStatusEntity {
-
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)
- private Integer status_code;
-
- @Column(name = "status", nullable = false)
- private String status;
-
- @Column(name = "is_reserve", nullable = false)
- private Boolean isReserve;
-
- @Column(name = "is_reserve_cancel", nullable = false)
- private Boolean isReserveCancel;
-
- @Column(name = "is_edit_ok", nullable = false)
- private Boolean isEditOk;
-
- @Column(name = "is_edit_ng", nullable = false)
- private Boolean isEditNg;
-
-}
diff --git a/src/main/java/osm/surveyor/task/city/model/Tasks.java b/src/main/java/osm/surveyor/task/city/model/Tasks.java
deleted file mode 100644
index c001f85..0000000
--- a/src/main/java/osm/surveyor/task/city/model/Tasks.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package osm.surveyor.task.city.model;
-
-import java.util.List;
-
-import lombok.Builder;
-import lombok.Getter;
-
-/**
- * レスポンス用クラス。
- */
-@Getter
-@Builder
-public class Tasks {
-
- private Result result; // 処理結果
-
- private List tasks; // データ
-
- @Getter
- @Builder
- public static class Result {
- private String message; // 処理結果メッセージ
- private int count; // データ件数
- }
-}
diff --git a/src/main/java/osm/surveyor/task/mesh/CitymeshController.java b/src/main/java/osm/surveyor/task/mesh/CitymeshController.java
new file mode 100644
index 0000000..2e828c8
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/mesh/CitymeshController.java
@@ -0,0 +1,30 @@
+package osm.surveyor.task.mesh;
+
+import java.util.List;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import lombok.RequiredArgsConstructor;
+import osm.surveyor.task.city.CityRepository;
+import osm.surveyor.task.city.model.City;
+import osm.surveyor.task.mesh.model.Citymesh;
+
+@RequiredArgsConstructor
+@Controller
+public class CitymeshController {
+ private final CitymeshRepository meshRepository;
+ private final CityRepository cityRepository;
+
+ @GetMapping("/mesh/{citycode}")
+ public String showList(@PathVariable String citycode, Model model) {
+ City city = cityRepository.findByCitycode(citycode);
+ List tasks = meshRepository.findByCitycode(citycode);
+ model.addAttribute("city", city);
+ model.addAttribute("meshes", tasks);
+ return "meshes";
+ }
+
+}
diff --git a/src/main/java/osm/surveyor/task/mesh/CitymeshRepository.java b/src/main/java/osm/surveyor/task/mesh/CitymeshRepository.java
new file mode 100644
index 0000000..535f27d
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/mesh/CitymeshRepository.java
@@ -0,0 +1,21 @@
+package osm.surveyor.task.mesh;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import osm.surveyor.task.mesh.model.Citymesh;
+import osm.surveyor.task.mesh.model.CitymeshPK;
+
+public interface CitymeshRepository extends JpaRepository {
+
+ @Query("SELECT m FROM Citymesh m WHERE m.citycode = :citycode AND m.meshcode = :meshcode")
+ Citymesh findOne(@Param("citycode")String citycode, @Param("meshcode")String meshcode);
+
+ List findByCitycode(String citycode);
+
+ @Query("SELECT m FROM Citymesh m WHERE m.username = :username order by citycode,meshcode")
+ List serchByUser(@Param("username")String username);
+}
diff --git a/src/main/java/osm/surveyor/task/mesh/CitymeshService.java b/src/main/java/osm/surveyor/task/mesh/CitymeshService.java
new file mode 100644
index 0000000..114ec99
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/mesh/CitymeshService.java
@@ -0,0 +1,14 @@
+package osm.surveyor.task.mesh;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional // メソッド開始時にトランザクションを開始、終了時にコミットする
+public class CitymeshService {
+
+ @Autowired
+ CitymeshRepository meshRepository;
+
+}
diff --git a/src/main/java/osm/surveyor/task/mesh/model/Citymesh.java b/src/main/java/osm/surveyor/task/mesh/model/Citymesh.java
new file mode 100644
index 0000000..ef0f96c
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/mesh/model/Citymesh.java
@@ -0,0 +1,77 @@
+package osm.surveyor.task.mesh.model;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.ManyToOne;
+import javax.validation.constraints.NotBlank;
+
+import org.springframework.format.annotation.NumberFormat;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import lombok.Data;
+import osm.surveyor.task.city.model.City;
+import osm.surveyor.task.city.model.Status;
+import osm.surveyor.task.util.JsonGeometryLine;
+import osm.surveyor.task.util.Point;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Data
+@Entity
+@IdClass(CitymeshPK.class)
+public class Citymesh {
+
+ @Id
+ @NumberFormat(pattern="#####")
+ private String citycode; // CitymeshPK.citycode
+
+ @Id
+ @NumberFormat
+ private String meshcode; // CitymeshPK.meshcode
+
+ @ManyToOne
+ @JsonIgnore
+ City city; // リレーション: to City 多対1
+
+ @NotBlank
+ @NumberFormat
+ private String lng;
+
+ @NotBlank
+ @NumberFormat
+ private String lat;
+
+ private String version;
+
+ private String surveyYear;
+
+ private String path;
+
+ private String line;
+
+ @JsonIgnore
+ public void setPoint(Point p) {
+ setLng(p.getLng());
+ setLat(p.getLat());
+ }
+
+ public void setLine(JsonGeometryLine p) {
+ this.line = p.toString();
+ }
+
+ /**
+ * ステータス
+ */
+ @Enumerated(EnumType.ORDINAL)
+ private Status status = Status.PREPARATION;
+
+ /**
+ * 編集者
+ */
+ private String username;
+
+}
diff --git a/src/main/java/osm/surveyor/task/mesh/model/CitymeshPK.java b/src/main/java/osm/surveyor/task/mesh/model/CitymeshPK.java
new file mode 100644
index 0000000..ed5145a
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/mesh/model/CitymeshPK.java
@@ -0,0 +1,36 @@
+package osm.surveyor.task.mesh.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Embeddable;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@SuppressWarnings("serial")
+@Getter
+@Setter
+@Embeddable
+public class CitymeshPK implements Serializable {
+ private String citycode;
+ private String meshcode;
+
+ public CitymeshPK() {
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof CitymeshPK) {
+ if (((CitymeshPK)obj).getCitycode().equals(this.citycode)) {
+ if (((CitymeshPK)obj).getMeshcode().equals(this.meshcode)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ String s = this.citycode + this.meshcode;
+ return s.hashCode();
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/TaskController.java b/src/main/java/osm/surveyor/task/task/TaskController.java
new file mode 100644
index 0000000..ad39933
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/TaskController.java
@@ -0,0 +1,305 @@
+package osm.surveyor.task.task;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.UUID;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import lombok.RequiredArgsConstructor;
+import osm.surveyor.task.city.CityRepository;
+import osm.surveyor.task.city.CityService;
+import osm.surveyor.task.city.ConflictException;
+import osm.surveyor.task.city.NotAcceptableException;
+import osm.surveyor.task.city.model.City;
+import osm.surveyor.task.city.model.Operation;
+import osm.surveyor.task.city.model.Status;
+import osm.surveyor.task.mesh.CitymeshRepository;
+import osm.surveyor.task.mesh.model.Citymesh;
+import osm.surveyor.task.mesh.model.CitymeshPK;
+import osm.surveyor.task.task.model.TaskEntity;
+
+@RequiredArgsConstructor
+@Controller
+public class TaskController {
+ private final CityRepository cityRepository;
+ private final CitymeshRepository meshRepository;
+ private final TaskRepository taskRepository;
+
+ @Autowired
+ private TaskService service;
+
+ @Autowired
+ private CityService cityService;
+
+ /**
+ * ログインユーザーが関係しているTASKリスト
+ * @param model
+ * @return
+ */
+ @GetMapping("/tasks")
+ public String showList(Model model,
+ @RequestParam(name="citycode") String citycode,
+ @RequestParam(name="meshcode") String meshcode)
+ {
+ City city = cityRepository.findByCitycode(citycode);
+ model.addAttribute("citycode", citycode);
+ model.addAttribute("cityname", city.getCityname());
+ model.addAttribute("meshcode", meshcode);
+ model.addAttribute("site", city.getSite());
+
+ Citymesh mesh = meshRepository.findOne(citycode,meshcode);
+ model.addAttribute("mesh", mesh);
+
+ String meshstr = "{}";
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ meshstr = objectMapper.writeValueAsString(mesh);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ model.addAttribute("meshstr", meshstr);
+
+ model.addAttribute("mesh", mesh);
+
+ String citystr = "{}";
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ citystr = objectMapper.writeValueAsString(city);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ model.addAttribute("citystr", citystr);
+
+ List tasks = taskRepository.serchByMesh(citycode, meshcode);
+ model.addAttribute("tasks", tasks);
+ return "tasks";
+ }
+
+ /**
+ * 「タスク操作」
+ * @param citycode
+ * @param meshcode
+ * @param task
+ * @return
+ */
+ @GetMapping("/task/add")
+ public String addTask(Model model,
+ @RequestParam(name="op") String op,
+ @RequestParam(name="citycode") String citycode,
+ @RequestParam(name="meshcode") String meshcode)
+ {
+ String next = "task";
+ Operation operation = Operation.NOP;
+ Status nextStatus = Status.ACCEPTING;
+ if (op.equals(Operation.RESERVE.toString())) {
+ model.addAttribute("command", "編集者登録");
+ operation = Operation.RESERVE;
+ nextStatus = Status.RESERVED;
+ }
+ else if (op.equals(Operation.CANCEL.toString())) {
+ model.addAttribute("command", "編集取消");
+ operation = Operation.CANCEL;
+ nextStatus = Status.ACCEPTING;
+ }
+ else if (op.equals(Operation.OK.toString())) {
+ model.addAttribute("command", "編集完了");
+ operation = Operation.OK;
+ nextStatus = Status.OK;
+ next = "task_done";
+ }
+ else if (op.equals(Operation.NG.toString())) {
+ model.addAttribute("command", "編集(NG)");
+ operation = Operation.NG;
+ nextStatus = Status.ACCEPTING;
+ }
+
+ City city = cityRepository.getReferenceById(citycode);
+ model.addAttribute("citycode", citycode);
+ model.addAttribute("cityname", city.getCityname());
+ model.addAttribute("meshcode", meshcode);
+
+ CitymeshPK pk = new CitymeshPK();
+ pk.setCitycode(citycode);
+ pk.setMeshcode(meshcode);
+ Citymesh mesh = meshRepository.getReferenceById(pk);
+
+ TaskEntity pre = service.getTaskByMesh(citycode, meshcode);
+ if (pre != null) {
+ pre.setOperation(operation);
+ pre.setStatus(nextStatus);
+ model.addAttribute("task", pre);
+ return next;
+ }
+ else {
+ // 既存Taskが無い場合は生成する
+ String uuid = UUID.randomUUID().toString();
+ TaskEntity task = new TaskEntity();
+ task.setCurrentId(uuid);
+ task.setPreId(uuid);
+ task.setCitycode(citycode);
+ task.setMeshcode(meshcode);
+ task.setMesh(mesh);
+ task.setStatus(nextStatus);
+ task.setUsername("");
+ task.setOperation(operation);
+ model.addAttribute("task", task);
+ return next;
+ }
+ }
+
+ @PostMapping("/task/process")
+ public String process(@Validated @ModelAttribute TaskEntity task,
+ BindingResult result)
+ {
+ if (result.hasErrors()) {
+ // エラーがある場合
+ return nextPage(task);
+ }
+ service.add(task);
+ cityService.updateStatus(task.getCitycode());
+
+ return "redirect:/tasks?citycode="+ task.getCitycode() +"&meshcode="+ task.getMeshcode();
+ }
+
+ @GetMapping("/admin")
+ public String admin()
+ {
+ return "admin";
+ }
+
+ @PostMapping("/admin/download")
+ public String download(HttpServletResponse response) {
+ try (OutputStream os = response.getOutputStream();) {
+ List list = taskRepository.findAll();
+ StringBuffer sb = new StringBuffer();
+ boolean c1 = false;
+ sb.append("[");
+ sb.append(System.lineSeparator());
+ for (TaskEntity task : list) {
+ if (c1) {
+ sb.append(",");
+ }
+ else {
+ c1 = true;
+ }
+ sb.append(task.toString());
+ sb.append(System.lineSeparator());
+ }
+ sb.append("]");
+ byte[] fb1 = String.valueOf(sb).getBytes();
+
+ response.setContentType("application/octet-stream");
+ response.setHeader("Content-Disposition", "attachment; filename="+ "task-bldg.json");
+ response.setContentLength(fb1.length);
+ os.write(fb1);
+ os.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 400 Bad Request
+ *
+ * @param e
+ * @param model
+ * @param citycode
+ * @param meshcode
+ * @return
+ */
+ @ExceptionHandler(TaskException.class)
+ public String taskExceptionHandler(TaskException e, Model model)
+ {
+ model.addAttribute("error", "400 Bad Request");
+ model.addAttribute("message", e.getMessage());
+ model.addAttribute("status", HttpStatus.BAD_REQUEST);
+ return exceptionHandler(e.getTask(), model);
+ }
+
+ /**
+ * 406 Not Acceptable
+ * "ACCEPTIONGではないため予約できません"
+ *
+ * @param e
+ * @param model
+ * @param citycode
+ * @param meshcode
+ * @return
+ */
+ @ExceptionHandler(NotAcceptableException.class)
+ public String notAcceptableExceptionHandler(NotAcceptableException e, Model model)
+ {
+ model.addAttribute("error", "406 Not Acceptable");
+ model.addAttribute("message", e.getMessage());
+ model.addAttribute("status", HttpStatus.NOT_ACCEPTABLE);
+ return exceptionHandler(e.getTask(), model);
+ }
+
+ /**
+ * 409 Conflict
+ * "タスクが変更されたため更新できません"
+ *
+ * @param e
+ * @param model
+ * @param citycode
+ * @param meshcode
+ * @return
+ */
+ @ExceptionHandler(ConflictException.class)
+ public String conflictExceptionHandler(ConflictException e, Model model)
+ {
+ model.addAttribute("error", "409 Conflict");
+ model.addAttribute("message", e.getMessage());
+ model.addAttribute("status", HttpStatus.CONFLICT);
+ return exceptionHandler(e.getTask(), model);
+ }
+
+ private String exceptionHandler(TaskEntity task, Model model) {
+ if (task == null) {
+ return "error";
+ }
+
+ if (task.getOperation() == Operation.RESERVE) {
+ model.addAttribute("command", "タスク予約");
+ }
+ else if (task.getOperation() == Operation.CANCEL) {
+ model.addAttribute("command", "タスク予約取消");
+ }
+ else if (task.getOperation() == Operation.OK) {
+ model.addAttribute("command", "編集済み");
+ }
+ else if (task.getOperation() == Operation.NG) {
+ model.addAttribute("command", "編集(NG)");
+ }
+ model.addAttribute("citycode", task.getCitycode());
+ model.addAttribute("meshcode", task.getMeshcode());
+ model.addAttribute("task", task);
+
+ return nextPage(task);
+ }
+
+ private String nextPage(TaskEntity task) {
+ if (task.getOperation() == Operation.OK) {
+ return "task_done";
+ }
+ return "task";
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/TaskException.java b/src/main/java/osm/surveyor/task/task/TaskException.java
new file mode 100644
index 0000000..dca8e2c
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/TaskException.java
@@ -0,0 +1,17 @@
+package osm.surveyor.task.task;
+
+import lombok.Getter;
+import lombok.Setter;
+import osm.surveyor.task.task.model.TaskEntity;
+
+@Setter
+@Getter
+public class TaskException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ private TaskEntity task;
+
+ public TaskException(String errorMessage) {
+ super(errorMessage);
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/TaskRepository.java b/src/main/java/osm/surveyor/task/task/TaskRepository.java
new file mode 100644
index 0000000..0addd84
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/TaskRepository.java
@@ -0,0 +1,16 @@
+package osm.surveyor.task.task;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import osm.surveyor.task.task.model.TaskEntity;
+
+public interface TaskRepository extends JpaRepository {
+
+ @Query("SELECT t FROM TaskEntity t WHERE t.citycode = :citycode AND t.meshcode = :meshcode order by update_time DESC")
+ List serchByMesh(@Param("citycode")String citycode, @Param("meshcode")String meshcode);
+
+}
diff --git a/src/main/java/osm/surveyor/task/task/TaskService.java b/src/main/java/osm/surveyor/task/task/TaskService.java
new file mode 100644
index 0000000..35d2d96
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/TaskService.java
@@ -0,0 +1,156 @@
+package osm.surveyor.task.task;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import osm.surveyor.task.city.ConflictException;
+import osm.surveyor.task.city.NotAcceptableException;
+import osm.surveyor.task.city.model.Operation;
+import osm.surveyor.task.city.model.Status;
+import osm.surveyor.task.mesh.CitymeshRepository;
+import osm.surveyor.task.mesh.model.Citymesh;
+import osm.surveyor.task.mesh.model.CitymeshPK;
+import osm.surveyor.task.task.model.TaskEntity;
+
+import javax.transaction.Transactional;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@Transactional // メソッド開始時にトランザクションを開始、終了時にコミットする
+public class TaskService {
+
+ @Autowired
+ TaskRepository repository;
+
+ @Autowired
+ CitymeshRepository meshRepository;
+
+ public void add(TaskEntity task) {
+ if (task.getOperation() == Operation.RESERVE) {
+ task.setStatus(Status.RESERVED);
+ }
+ else if (task.getOperation() == Operation.CANCEL) {
+ task.setStatus(Status.PREPARATION);
+ }
+ else if (task.getOperation() == Operation.NG) {
+ task.setStatus(Status.NG);
+ }
+ else if (task.getOperation() == Operation.OK) {
+ task.setStatus(Status.OK);
+ }
+ else {
+ NotAcceptableException e = new NotAcceptableException("未サポートのオペレーションです: "+ task.getOperation());
+ e.setTask(task);
+ throw e;
+ }
+
+ String uuid = UUID.randomUUID().toString();
+
+ CitymeshPK pk = new CitymeshPK();
+ pk.setCitycode(task.getCitycode());
+ pk.setMeshcode(task.getMeshcode());
+ Citymesh mesh = meshRepository.getReferenceById(pk);
+
+ TaskEntity ctask = getTaskByMesh(task.getCitycode(), task.getMeshcode());
+ if (ctask == null) {
+ task.setPreId(uuid);
+ task.setCurrentId(uuid);
+ }
+ else {
+ if (!ctask.getCurrentId().equals(task.getCurrentId())) {
+ ConflictException e = new ConflictException("他のスレッドによってタスクが変更されたため更新できませんでした。");
+ e.setTask(task);
+ throw e;
+ }
+ if (task.getOperation() == Operation.CANCEL) {
+ if (ctask.getStatus() != Status.RESERVED) {
+ NotAcceptableException e = new NotAcceptableException("タスクが'編集中'ではないため'編集取消'できませんでした : "+ task.getOperation());
+ e.setTask(task);
+ throw e;
+ }
+ }
+ else if (task.getOperation() == Operation.OK) {
+ // タスク予約していなくてもインポートできる
+ // 他のマッパーが予約していてもインポート可能
+ String username = task.getUsername();
+ if (username == null) {
+ TaskException e = new TaskException("編集者が入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+ else if (username.isEmpty()) {
+ TaskException e = new TaskException("編集者が入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+
+ String changeset = task.getChangeSet();
+ if (changeset == null) {
+ TaskException e = new TaskException("変更セットNoが入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+ else if (changeset.isEmpty()) {
+ TaskException e = new TaskException("変更セットNoが入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+ else {
+ try {
+ Long.parseLong(changeset);
+ }
+ catch (NumberFormatException nfe) {
+ TaskException e = new TaskException("変更セットNoに数字以外の文字が入っています");
+ e.setTask(task);
+ throw e;
+ }
+ }
+ }
+ else if (task.getOperation() == Operation.NG) {
+ String username = task.getUsername();
+ if (username == null) {
+ TaskException e = new TaskException("編集者が入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+ else if (username.isEmpty()) {
+ TaskException e = new TaskException("編集者が入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+
+ String comment = task.getComment();
+ if (comment == null || comment.isEmpty()) {
+ TaskException e = new TaskException("コメントが入力されていません");
+ e.setTask(task);
+ throw e;
+ }
+ }
+ task.setPreId(ctask.getCurrentId());
+ task.setCurrentId(uuid);
+ }
+
+ task.setUpdateTime(new Date());
+ mesh.setStatus(task.getStatus());
+ mesh.setUsername(task.getUsername());
+
+ // データベースに格納
+ repository.save(task);
+ meshRepository.save(mesh);
+ }
+
+ public TaskEntity getTaskByMesh(String citycode, String meshcode) {
+ List tasks = repository.serchByMesh(citycode, meshcode);
+ for (TaskEntity t : tasks) {
+ return t;
+ }
+ return null;
+ }
+
+ public List getTasks() {
+ return repository.findAll();
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/model/TaskEntity.java b/src/main/java/osm/surveyor/task/task/model/TaskEntity.java
new file mode 100644
index 0000000..bcc4bb4
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/model/TaskEntity.java
@@ -0,0 +1,106 @@
+package osm.surveyor.task.task.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.NotBlank;
+
+import org.springframework.format.annotation.NumberFormat;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import osm.surveyor.task.city.model.Operation;
+import osm.surveyor.task.city.model.Status;
+import osm.surveyor.task.mesh.model.Citymesh;
+import osm.surveyor.task.util.JsonTemple;
+
+@Data
+@EqualsAndHashCode(callSuper=false)
+@Entity
+public class TaskEntity extends JsonTemple {
+
+ @Id
+ @Column(name = "current_id")
+ private String currentId;
+
+ @NotBlank
+ @Column(name = "pre_id")
+ private String preId;
+
+ @NumberFormat
+ private String citycode; // CitymeshPK.citycode
+
+ @NumberFormat
+ private String meshcode; // CitymeshPK.meshcode
+
+ @ManyToOne
+ Citymesh mesh; // リレーション: to Citymesh 多対1
+
+ /**
+ * ステータス
+ */
+ @Enumerated(EnumType.STRING)
+ private Status status = Status.PREPARATION;
+
+ /**
+ * 編集者
+ */
+ private String username;
+
+ /**
+ * 変更セットNo
+ */
+ @NumberFormat
+ @Column(name = "changeset")
+ private String changeSet;
+
+ /**
+ * コメント
+ */
+ private String comment;
+
+ /**
+ * 操作内容
+ */
+ @Enumerated(EnumType.ORDINAL)
+ private Operation operation = Operation.NOP;
+
+ /**
+ * 更新日時
+ */
+ @Temporal(TemporalType.TIMESTAMP)
+ Date updateTime;
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ boolean c1 = false;
+ sb.append("{");
+ c1 = outStr(c1, sb, "currentId", this.getCurrentId());
+ c1 = outStr(c1, sb, "preId", this.getPreId());
+ c1 = outStr(c1, sb, "citycode", this.getCitycode());
+ c1 = outStr(c1, sb, "meshcode", this.getMeshcode());
+ c1 = outStr(c1, sb, "status", this.getStatus().toString());
+ c1 = outStr(c1, sb, "username", this.getUsername());
+ c1 = outStr(c1, sb, "changeSet", this.getChangeSet());
+ c1 = outStr(c1, sb, "comment", this.getComment());
+ c1 = outStr(c1, sb, "operation", this.getOperation().toString());
+ c1 = outStr(c1, sb, "updateTime", (this.getUpdateTime() == null ? "" : this.getUpdateTime().toString()));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public void parse(JsonNode node) {
+ // TODO
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/model/TaskPK.java b/src/main/java/osm/surveyor/task/task/model/TaskPK.java
new file mode 100644
index 0000000..a712fea
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/model/TaskPK.java
@@ -0,0 +1,33 @@
+package osm.surveyor.task.task.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Embeddable;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@SuppressWarnings("serial")
+@Getter
+@Setter
+@Embeddable
+public class TaskPK implements Serializable {
+ private String currentId;
+
+ public TaskPK() {
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof TaskPK) {
+ if (((TaskPK)obj).getCurrentId().equals(this.currentId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ String s = this.currentId;
+ return s.hashCode();
+ }
+}
diff --git a/src/main/java/osm/surveyor/task/task/model/TaskStatusEntity.java b/src/main/java/osm/surveyor/task/task/model/TaskStatusEntity.java
new file mode 100644
index 0000000..15bf4a7
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/model/TaskStatusEntity.java
@@ -0,0 +1,40 @@
+package osm.surveyor.task.task.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "task_status")
+public class TaskStatusEntity {
+
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ private Integer status_code;
+
+ @Column(name = "status", nullable = false)
+ private String status;
+
+ @Column(name = "is_reserve", nullable = false)
+ private Boolean isReserve;
+
+ @Column(name = "is_reserve_cancel", nullable = false)
+ private Boolean isReserveCancel;
+
+ @Column(name = "is_edit_ok", nullable = false)
+ private Boolean isEditOk;
+
+ @Column(name = "is_edit_ng", nullable = false)
+ private Boolean isEditNg;
+
+}
diff --git a/src/main/java/osm/surveyor/task/task/model/Tasks.java b/src/main/java/osm/surveyor/task/task/model/Tasks.java
new file mode 100644
index 0000000..6a4cbfb
--- /dev/null
+++ b/src/main/java/osm/surveyor/task/task/model/Tasks.java
@@ -0,0 +1,25 @@
+package osm.surveyor.task.task.model;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Getter;
+
+/**
+ * レスポンス用クラス。
+ */
+@Getter
+@Builder
+public class Tasks {
+
+ private Result result; // 処理結果
+
+ private List tasks; // データ
+
+ @Getter
+ @Builder
+ public static class Result {
+ private String message; // 処理結果メッセージ
+ private int count; // データ件数
+ }
+}