diff --git a/src/main/java/com/eactive/httpmockserver/api/controller/MockRouteMgmtController.java b/src/main/java/com/eactive/httpmockserver/api/controller/MockRouteMgmtController.java index 13dccfa..083dd3d 100644 --- a/src/main/java/com/eactive/httpmockserver/api/controller/MockRouteMgmtController.java +++ b/src/main/java/com/eactive/httpmockserver/api/controller/MockRouteMgmtController.java @@ -1,8 +1,9 @@ package com.eactive.httpmockserver.api.controller; import com.eactive.httpmockserver.api.dto.MockResponseDTO; -import com.eactive.httpmockserver.api.dto.MockRouteDTO; +import com.eactive.httpmockserver.api.dto.MockRouteRegisterDTO; import com.eactive.httpmockserver.api.dto.MockRouteSearch; +import com.eactive.httpmockserver.api.dto.MockRouteUpdateDTO; import com.eactive.httpmockserver.api.entity.MockRoute; import com.eactive.httpmockserver.api.mapper.MockRouteMapper; import com.eactive.httpmockserver.api.service.MockRouteService; @@ -14,6 +15,7 @@ import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Validator; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; import javax.annotation.PostConstruct; import java.util.List; @@ -48,37 +50,51 @@ public class MockRouteMgmtController { public static final String MOCK_ROUTE_LIST_VIEW = "redirect:/mgmt/routes/list_view.do"; @GetMapping("/list_view.do") - public String listView(@ModelAttribute("mockRouteSearch") MockRouteSearch mockRouteSearch, ModelMap model, Pageable pageable) { - + public ModelAndView listView(@ModelAttribute("mockRouteSearch") MockRouteSearch mockRouteSearch, Pageable pageable) { + ModelAndView mav = new ModelAndView("page/routes/mockRouteList"); Page page = mockRouteService.findAll(mockRouteSearch.buildSpecification(), pageable); - model.addAttribute("page", page); - model.addAttribute("pageable", pageable); - model.addAttribute("modelSearch", mockRouteSearch); + mav.addObject("page", page); + mav.addObject("pageable", pageable); + mav.addObject("modelSearch", mockRouteSearch); - return "page/routes/mockRouteList"; + return mav; } @GetMapping("/create_view.do") - public String createView(ModelMap model) { - MockRouteDTO defaultRoute = new MockRouteDTO(); + public ModelAndView createView() { + ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT); + MockRouteRegisterDTO defaultRoute = new MockRouteRegisterDTO(); MockResponseDTO defaultResponse = new MockResponseDTO(); defaultResponse.setDefaultResponse("true"); defaultRoute.getResponses().add(defaultResponse); - model.addAttribute(MOCK_ROUTE, defaultRoute); - return MOCK_ROUTE_EDIT; + mav.addObject(MOCK_ROUTE, defaultRoute); + return mav; } @GetMapping("/update_view.do") - public String updateView(ModelMap model, @RequestParam("id") Long id) { + public ModelAndView updateView(@RequestParam("id") Long id) { + ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT); MockRoute found = mockRouteService.findById(id); + mav.addObject(MOCK_ROUTE, mockRouteMapper.map(found)); - model.addAttribute(MOCK_ROUTE, mockRouteMapper.map(found)); - return MOCK_ROUTE_EDIT; + return mav; + } + + @PostMapping("/clone_view.do") + public ModelAndView cloneView(@RequestParam("id") Long id) { + + ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT); + MockRoute found = mockRouteService.findById(id); + MockRouteRegisterDTO dto = mockRouteMapper.map(found); + dto.setId(null); + mav.addObject(MOCK_ROUTE, dto); + + return mav; } @PostMapping("/register.do") - public String register(@ModelAttribute("mockRoute") MockRouteDTO dto, BindingResult bindingResult, ModelMap model) { + public String register(@ModelAttribute("mockRoute") MockRouteRegisterDTO dto, BindingResult bindingResult, ModelMap model) { if (dto == null) { return "redirect:/mgmt/routes/create_view.do"; @@ -101,7 +117,7 @@ public class MockRouteMgmtController { @PostMapping("/update.do") public String update(@RequestParam("id") String id, - @ModelAttribute("mockRoute") MockRouteDTO dto, + @ModelAttribute("mockRoute") MockRouteUpdateDTO dto, BindingResult bindingResult, ModelMap model) { if (StringUtils.isEmpty(id)) { diff --git a/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteRegisterDTO.java b/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteRegisterDTO.java new file mode 100644 index 0000000..8c75d86 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteRegisterDTO.java @@ -0,0 +1,76 @@ +package com.eactive.httpmockserver.api.dto; + +import com.eactive.httpmockserver.common.validator.UniqueRoute; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@UniqueRoute(path = "pathPattern", method = "method") +public class MockRouteRegisterDTO { + + private Long id; + + @NotEmpty + private String method; + + @NotEmpty + private String pathPattern; + + @NotEmpty + private String name; + + private String description; + + @Size(min = 1, message = "Response must have at least one item") + private List responses = new ArrayList<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getPathPattern() { + return pathPattern; + } + + public void setPathPattern(String pathPattern) { + this.pathPattern = pathPattern; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getResponses() { + return responses; + } + + public void setResponses(List responses) { + this.responses = responses; + } +} diff --git a/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteDTO.java b/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteUpdateDTO.java similarity index 93% rename from src/main/java/com/eactive/httpmockserver/api/dto/MockRouteDTO.java rename to src/main/java/com/eactive/httpmockserver/api/dto/MockRouteUpdateDTO.java index 2a2bc7a..191e905 100644 --- a/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteDTO.java +++ b/src/main/java/com/eactive/httpmockserver/api/dto/MockRouteUpdateDTO.java @@ -1,11 +1,13 @@ package com.eactive.httpmockserver.api.dto; +import com.eactive.httpmockserver.common.validator.UniqueRoute; + import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; -public class MockRouteDTO { +public class MockRouteUpdateDTO { private Long id; diff --git a/src/main/java/com/eactive/httpmockserver/api/mapper/MockRouteMapper.java b/src/main/java/com/eactive/httpmockserver/api/mapper/MockRouteMapper.java index 88545a1..3e0af86 100644 --- a/src/main/java/com/eactive/httpmockserver/api/mapper/MockRouteMapper.java +++ b/src/main/java/com/eactive/httpmockserver/api/mapper/MockRouteMapper.java @@ -2,7 +2,8 @@ package com.eactive.httpmockserver.api.mapper; import com.eactive.httpmockserver.api.dto.MockHeaderDTO; import com.eactive.httpmockserver.api.dto.MockResponseDTO; -import com.eactive.httpmockserver.api.dto.MockRouteDTO; +import com.eactive.httpmockserver.api.dto.MockRouteRegisterDTO; +import com.eactive.httpmockserver.api.dto.MockRouteUpdateDTO; import com.eactive.httpmockserver.api.entity.MockResponse; import com.eactive.httpmockserver.api.entity.MockRoute; import com.eactive.httpmockserver.common.mapper.CommonMapper; @@ -34,10 +35,11 @@ public abstract class MockRouteMapper { XML_ESCAPE_MAP.put("'", "'"); } - public abstract MockRoute map(MockRouteDTO dto); + public abstract MockRoute map(MockRouteRegisterDTO dto); + public abstract MockRoute map(MockRouteUpdateDTO dto); - public abstract MockRouteDTO map(MockRoute entity); + public abstract MockRouteRegisterDTO map(MockRoute entity); @Mapping(target = "headers", source = "headers", qualifiedByName = "mapHeadersToMap") @Mapping(target = "defaultResponse", source = "defaultResponse", qualifiedByName = "mapEntityDefaultResponse") diff --git a/src/main/java/com/eactive/httpmockserver/api/repository/MockRouteRepository.java b/src/main/java/com/eactive/httpmockserver/api/repository/MockRouteRepository.java index 95aac22..823d72e 100644 --- a/src/main/java/com/eactive/httpmockserver/api/repository/MockRouteRepository.java +++ b/src/main/java/com/eactive/httpmockserver/api/repository/MockRouteRepository.java @@ -5,4 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface MockRouteRepository extends JpaRepository, JpaSpecificationExecutor { + + long countByMethodAndPathPattern(String method, String pathPattern); } diff --git a/src/main/java/com/eactive/httpmockserver/api/service/MockRouteService.java b/src/main/java/com/eactive/httpmockserver/api/service/MockRouteService.java index 9c3f467..49d95eb 100644 --- a/src/main/java/com/eactive/httpmockserver/api/service/MockRouteService.java +++ b/src/main/java/com/eactive/httpmockserver/api/service/MockRouteService.java @@ -74,8 +74,8 @@ public class MockRouteService { route.setName(updated.getName()); route.setDescription(updated.getDescription()); - route.setMethod(updated.getMethod()); - route.setPathPattern(updated.getPathPattern()); +// route.setMethod(updated.getMethod()); +// route.setPathPattern(updated.getPathPattern()); if (!route.getPathPattern().startsWith("/")) { route.setPathPattern("/" + route.getPathPattern()); } diff --git a/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRoute.java b/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRoute.java new file mode 100644 index 0000000..0ef55a2 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRoute.java @@ -0,0 +1,22 @@ +package com.eactive.httpmockserver.common.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Constraint(validatedBy = UniqueRouteValidator.class) +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UniqueRoute { + String message() default "등록된 API가 존재합니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; + + String path(); + + String method(); + +} diff --git a/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRouteValidator.java b/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRouteValidator.java new file mode 100644 index 0000000..4fb8215 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/common/validator/UniqueRouteValidator.java @@ -0,0 +1,53 @@ +package com.eactive.httpmockserver.common.validator; + +import com.eactive.httpmockserver.api.repository.MockRouteRepository; +import com.eactive.httpmockserver.common.exception.UserNotFoundException; +import com.eactive.httpmockserver.common.util.ApplicationContextUtil; +import com.eactive.httpmockserver.user.service.UserService; +import org.apache.commons.beanutils.PropertyUtils; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class UniqueRouteValidator implements ConstraintValidator { + + private String method; + + private String path; + + @Override + public void initialize(UniqueRoute constraintAnnotation) { + ConstraintValidator.super.initialize(constraintAnnotation); + this.method = constraintAnnotation.method(); + this.path = constraintAnnotation.path(); + } + + @Override + public boolean isValid(Object value, ConstraintValidatorContext context) { + String methodValue; + String pathValue; + try { + methodValue = (String) PropertyUtils.getProperty(value, this.method); + pathValue = (String) PropertyUtils.getProperty(value, this.path); + } catch (Exception e) { + return false; + } + MockRouteRepository mockRouteRepository = ApplicationContextUtil.getContext().getBean(MockRouteRepository.class); + long found = mockRouteRepository.countByMethodAndPathPattern(methodValue, pathValue); + + String message = "등록된 API가 존재합니다."; + + if (found > 0L){ + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message) + .addPropertyNode(this.path) + .addConstraintViolation(); + + return false; + } + + return true; + } +} diff --git a/src/main/resources/templates/page/routes/mockRouteEdit.html b/src/main/resources/templates/page/routes/mockRouteEdit.html index db807c6..da50e6f 100644 --- a/src/main/resources/templates/page/routes/mockRouteEdit.html +++ b/src/main/resources/templates/page/routes/mockRouteEdit.html @@ -29,7 +29,7 @@
-
+
+ + +
+
+
diff --git a/src/main/resources/templates/page/routes/mockRouteList.html b/src/main/resources/templates/page/routes/mockRouteList.html index 9731f7a..353eeb8 100644 --- a/src/main/resources/templates/page/routes/mockRouteList.html +++ b/src/main/resources/templates/page/routes/mockRouteList.html @@ -90,6 +90,9 @@ +
@@ -100,6 +103,9 @@ +
+ +