새 컬렉션 추가, 로딩, 새 요청 추가
This commit is contained in:
+2
-13
@@ -2,13 +2,9 @@ package com.eactive.httpmockserver.client.controller;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.entity.Server;
|
||||
import com.eactive.httpmockserver.client.repository.ServerRepository;
|
||||
import com.eactive.httpmockserver.client.service.ApiTesterService;
|
||||
import com.eactive.httpmockserver.client.service.NettyApiClient;
|
||||
import com.eactive.httpmockserver.common.security.CurrentUser;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
@@ -25,13 +21,10 @@ public class ApiClientController {
|
||||
@Autowired
|
||||
private ServerRepository serverRepository;
|
||||
|
||||
@Autowired
|
||||
private ApiTesterService apiTesterService;
|
||||
|
||||
@Autowired
|
||||
private NettyApiClient nettyApiClient;
|
||||
|
||||
@PostMapping("/api/test.do")
|
||||
@PostMapping("/mgmt/api/test.do")
|
||||
@ResponseBody
|
||||
public ApiResponse handleApiRequest(@RequestBody ApiRequestDTO request) {
|
||||
|
||||
@@ -43,14 +36,10 @@ public class ApiClientController {
|
||||
}
|
||||
|
||||
@GetMapping("/mgmt/api_tester.do")
|
||||
public String testView(ModelMap model,
|
||||
@CurrentUser StaffUser user) {
|
||||
public String testView(ModelMap model) {
|
||||
|
||||
List<Server> servers = serverRepository.findAll();
|
||||
List<ApiCollection> collections = apiTesterService.findMyCollections(user.getEsntlId());
|
||||
|
||||
model.addAttribute("servers", servers);
|
||||
model.addAttribute("collections", collections);
|
||||
|
||||
return "page/apiTester";
|
||||
}
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.eactive.httpmockserver.client.controller;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiCollectionDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.entity.ApiRequestInfo;
|
||||
import com.eactive.httpmockserver.client.mapper.ApiRequestMapper;
|
||||
import com.eactive.httpmockserver.client.service.ApiRequestMgmtService;
|
||||
import com.eactive.httpmockserver.common.security.CurrentUser;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
public class ApiRequestMgmtController {
|
||||
|
||||
@Autowired
|
||||
ApiRequestMgmtService apiRequestMgmtService;
|
||||
|
||||
@Autowired
|
||||
ApiRequestMapper apiRequestMapper;
|
||||
|
||||
@GetMapping("/mgmt/collections/list.do")
|
||||
public ResponseEntity<List<ApiCollectionDTO>> listApiRequests(@CurrentUser StaffUser user) {
|
||||
List<ApiCollection> collections = apiRequestMgmtService.getMyApis(user);
|
||||
return ResponseEntity.ok(apiRequestMapper.mapCollections(collections));
|
||||
}
|
||||
|
||||
@PostMapping("/mgmt/collections/create.do")
|
||||
public ResponseEntity<String> createApiCollection(
|
||||
@CurrentUser StaffUser user,
|
||||
@RequestBody ApiCollectionDTO dto) {
|
||||
|
||||
ApiCollection collection = apiRequestMapper.map(dto);
|
||||
collection.setOwner(user);
|
||||
|
||||
apiRequestMgmtService.createNewApiCollection(collection);
|
||||
return ResponseEntity.ok("success");
|
||||
}
|
||||
|
||||
|
||||
@PutMapping("/mgmt/collections/update.do")
|
||||
public ResponseEntity<String> updateApiCollection(@RequestBody ApiCollectionDTO dto) {
|
||||
ApiCollection updated = apiRequestMapper.map(dto);
|
||||
apiRequestMgmtService.updateApiCollection(updated.getId(), updated);
|
||||
return ResponseEntity.ok("success");
|
||||
}
|
||||
|
||||
@PostMapping("/mgmt/collections/delete.do")
|
||||
public ResponseEntity<String> deleteApiCollection(@RequestBody ApiCollectionDTO dto) {
|
||||
apiRequestMgmtService.deleteApiCollection(dto.getId());
|
||||
return ResponseEntity.ok("success");
|
||||
}
|
||||
|
||||
@PostMapping("/mgmt/collections/{id}/apis/save.do")
|
||||
public ResponseEntity<String> addApiToCollection(@PathVariable(name = "id") String id,
|
||||
@RequestBody ApiRequestDTO dto,
|
||||
@CurrentUser StaffUser user) {
|
||||
ApiRequestInfo apiRequestInfo = apiRequestMapper.map(dto);
|
||||
apiRequestInfo.setOwner(user);
|
||||
String apiId = apiRequestMgmtService.saveApiToCollection(id, apiRequestInfo);
|
||||
return ResponseEntity.ok(apiId);
|
||||
}
|
||||
|
||||
@PostMapping("/mgmt/collections/{id}/apis/delete.do")
|
||||
public ResponseEntity<String> removeApiFromCollection(@PathVariable(name = "id") String id,
|
||||
@RequestBody ApiRequestDTO dto) {
|
||||
apiRequestMgmtService.removeApiFromCollection(id, dto.getId());
|
||||
return ResponseEntity.ok("success");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ApiCollectionDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
private List<ApiRequestDTO> apis = new ArrayList<>();
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setApis(List<ApiRequestDTO> apis) {
|
||||
this.apis = apis;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<ApiRequestDTO> getApis() {
|
||||
return apis;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,40 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ApiRequestDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String path;
|
||||
private String method;
|
||||
|
||||
private Long server;
|
||||
|
||||
private List<ApiHeaderDTO> headers;
|
||||
private List<ApiRequestKeyValueDTO> headers = new ArrayList<>();
|
||||
|
||||
private List<ApiRequestKeyValueDTO> queryParams = new ArrayList<>();
|
||||
private String requestBody;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
@@ -36,14 +59,22 @@ public class ApiRequestDTO {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> getHeaders() {
|
||||
public List<ApiRequestKeyValueDTO> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(List<ApiHeaderDTO> headers) {
|
||||
public void setHeaders(List<ApiRequestKeyValueDTO> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public List<ApiRequestKeyValueDTO> getQueryParams() {
|
||||
return queryParams;
|
||||
}
|
||||
|
||||
public void setQueryParams(List<ApiRequestKeyValueDTO> queryParams) {
|
||||
this.queryParams = queryParams;
|
||||
}
|
||||
|
||||
public String getRequestBody() {
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
public class ApiHeaderDTO {
|
||||
public class ApiRequestKeyValueDTO {
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
@@ -30,4 +30,8 @@ public class ApiHeaderDTO {
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (enabled?"//":"")+ key + "=" + value;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ public class ApiResponse {
|
||||
|
||||
private int status;
|
||||
|
||||
private List<ApiHeaderDTO> headers;
|
||||
private List<ApiRequestKeyValueDTO> headers;
|
||||
|
||||
private String body;
|
||||
|
||||
@@ -20,11 +20,11 @@ public class ApiResponse {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> getHeaders() {
|
||||
public List<ApiRequestKeyValueDTO> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(List<ApiHeaderDTO> headers) {
|
||||
public void setHeaders(List<ApiRequestKeyValueDTO> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eactive.httpmockserver.client.entity;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@@ -20,11 +21,11 @@ public class ApiCollection {
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "API_COLLECTION_API_REQUEST_INFO",
|
||||
joinColumns = @JoinColumn(name = "API_COLLECTION_ID"),
|
||||
inverseJoinColumns = @JoinColumn(name = "API_REQUEST_INFO_ID")
|
||||
name = "API_COLLECTION_API_REQUEST_INFO",
|
||||
joinColumns = @JoinColumn(name = "API_COLLECTION_ID"),
|
||||
inverseJoinColumns = @JoinColumn(name = "API_REQUEST_INFO_ID")
|
||||
)
|
||||
private List<ApiRequestInfo> apis;
|
||||
private List<ApiRequestInfo> apis = new ArrayList<>();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eactive.httpmockserver.client.entity;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@Entity
|
||||
@@ -20,6 +21,8 @@ public class ApiRequestInfo {
|
||||
@JoinColumn(name = "USER_ID")
|
||||
private StaffUser owner;
|
||||
|
||||
private String name;
|
||||
|
||||
private String method;
|
||||
|
||||
private String path;
|
||||
@@ -30,6 +33,14 @@ public class ApiRequestInfo {
|
||||
|
||||
private String requestBody;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -93,4 +104,26 @@ public class ApiRequestInfo {
|
||||
public void setRequestBody(String requestBody) {
|
||||
this.requestBody = requestBody;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ApiRequestInfo that = (ApiRequestInfo) o;
|
||||
return Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, server, owner, method, path, headers, queryParams, requestBody);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ApiRequestInfo a= new ApiRequestInfo();
|
||||
a.setId("a");
|
||||
ApiRequestInfo b = new ApiRequestInfo();
|
||||
a.setId("a");
|
||||
|
||||
System.out.println(a.equals(b));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.eactive.httpmockserver.client.mapper;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiCollectionDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestKeyValueDTO;
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.entity.ApiRequestInfo;
|
||||
import com.eactive.httpmockserver.common.mapper.CommonMapper;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mapper(componentModel = "spring",
|
||||
uses = {CommonMapper.class, ServerMapper.class},
|
||||
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
@Component
|
||||
public interface ApiRequestMapper {
|
||||
ApiCollection map(ApiCollectionDTO dto);
|
||||
|
||||
ApiRequestInfo map(ApiRequestDTO dto);
|
||||
|
||||
|
||||
ApiRequestDTO map(ApiRequestInfo entity);
|
||||
|
||||
|
||||
|
||||
List<ApiRequestInfo> mapApis(List<ApiRequestDTO> apis);
|
||||
|
||||
List<ApiCollectionDTO> mapCollections(List<ApiCollection> apis);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.eactive.httpmockserver.client.mapper;
|
||||
|
||||
|
||||
import com.eactive.httpmockserver.client.entity.Server;
|
||||
import com.eactive.httpmockserver.client.repository.ServerRepository;
|
||||
import com.eactive.httpmockserver.common.exception.NotFoundException;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Mapper(componentModel = "spring",
|
||||
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
@Component
|
||||
public class ServerMapper {
|
||||
|
||||
@Autowired
|
||||
ServerRepository serverRepository;
|
||||
|
||||
Server map(Long id) {
|
||||
if (id == null) return null;
|
||||
return serverRepository.findById(id).orElseThrow(() -> new NotFoundException("Server[" + id + "] not found"));
|
||||
}
|
||||
|
||||
Long map(Server server) {
|
||||
if (server == null) return null;
|
||||
return server.getId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
package com.eactive.httpmockserver.client.repository;
|
||||
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.entity.ApiRequestInfo;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApiRequestRepository extends JpaRepository<ApiRequestInfo, String>, JpaSpecificationExecutor<ApiRequestInfo> {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.entity.ApiRequestInfo;
|
||||
import com.eactive.httpmockserver.client.repository.ApiCollectionRepository;
|
||||
import com.eactive.httpmockserver.client.repository.ApiRequestRepository;
|
||||
import com.eactive.httpmockserver.common.exception.NotFoundException;
|
||||
import com.eactive.httpmockserver.user.entity.StaffUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thymeleaf.util.StringUtils;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiRequestMgmtService {
|
||||
|
||||
@Autowired
|
||||
ApiCollectionRepository apiCollectionRepository;
|
||||
|
||||
@Autowired
|
||||
ApiRequestRepository apiRequestRepository;
|
||||
|
||||
|
||||
public List<ApiCollection> getMyApis(StaffUser user) {
|
||||
return apiCollectionRepository.findAllByOwner(user);
|
||||
}
|
||||
|
||||
public void deleteApiCollection(String id) {
|
||||
apiCollectionRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public void createNewApiCollection(ApiCollection collection) {
|
||||
collection.setId(UUID.randomUUID().toString());
|
||||
apiCollectionRepository.save(collection);
|
||||
}
|
||||
|
||||
public void updateApiCollection(String id, ApiCollection updated) {
|
||||
ApiCollection collection = apiCollectionRepository.findById(id).orElseThrow(() -> new NotFoundException("api collection[" + id + "] not found"));
|
||||
collection.setName(updated.getName());
|
||||
apiCollectionRepository.save(collection);
|
||||
}
|
||||
|
||||
public String saveApiToCollection(String id, ApiRequestInfo api) {
|
||||
ApiCollection collection = apiCollectionRepository.findById(id).orElseThrow(() -> new NotFoundException("api collection[" + id + "] not found"));
|
||||
|
||||
if (StringUtils.isEmpty(api.getId())) {
|
||||
api.setId(UUID.randomUUID().toString());
|
||||
apiRequestRepository.save(api);
|
||||
} else {
|
||||
String apiId = api.getId();
|
||||
ApiRequestInfo existing = apiRequestRepository.findById(apiId).orElseThrow(() -> new NotFoundException("api[" + apiId + "] not found"));
|
||||
existing.setName(api.getName());
|
||||
existing.setMethod(api.getMethod());
|
||||
existing.setPath(api.getPath());
|
||||
existing.setHeaders(api.getHeaders());
|
||||
existing.setQueryParams(api.getQueryParams());
|
||||
existing.setServer(api.getServer());
|
||||
existing.setRequestBody(api.getRequestBody());
|
||||
apiRequestRepository.save(existing);
|
||||
api = existing;
|
||||
}
|
||||
|
||||
|
||||
if (!collection.getApis().contains(api)) {
|
||||
collection.getApis().add(api);
|
||||
apiCollectionRepository.save(collection);
|
||||
}
|
||||
|
||||
return api.getId();
|
||||
}
|
||||
|
||||
public void removeApiFromCollection(String id, String apiId) {
|
||||
ApiCollection collection = apiCollectionRepository.findById(id).orElseThrow(() -> new NotFoundException("api collection[" + id + "] not found"));
|
||||
ApiRequestInfo api = apiRequestRepository.findById(apiId).orElseThrow(() -> new NotFoundException("api[" + apiId + "] not found"));
|
||||
|
||||
collection.getApis().remove(api);
|
||||
apiCollectionRepository.save(collection);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.entity.ApiCollection;
|
||||
import com.eactive.httpmockserver.client.repository.ApiCollectionRepository;
|
||||
import com.eactive.httpmockserver.user.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiTesterService {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
ApiCollectionRepository apiCollectionRepository;
|
||||
|
||||
public List<ApiCollection> findMyCollections(String esntlId) {
|
||||
return apiCollectionRepository.findAllByOwner(userService.findByEsntlId(esntlId));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiHeaderDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestKeyValueDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
@@ -49,10 +49,10 @@ public class HttptHandler extends SimpleChannelInboundHandler<FullHttpResponse>
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> convertHttpHeadersToList(HttpHeaders headers) {
|
||||
List<ApiHeaderDTO> headerList = new ArrayList<>();
|
||||
public List<ApiRequestKeyValueDTO> convertHttpHeadersToList(HttpHeaders headers) {
|
||||
List<ApiRequestKeyValueDTO> headerList = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entry : headers.entries()) {
|
||||
ApiHeaderDTO header = new ApiHeaderDTO();
|
||||
ApiRequestKeyValueDTO header = new ApiRequestKeyValueDTO();
|
||||
header.setKey(entry.getKey());
|
||||
header.setValue(entry.getValue());
|
||||
headerList.add(header);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiHeaderDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestKeyValueDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
||||
import com.eactive.httpmockserver.client.entity.Server;
|
||||
@@ -91,7 +91,7 @@ public class NettyApiClient {
|
||||
|
||||
if (apiRequest.getHeaders().size() > 0) {
|
||||
HttpHeaders customHeaders = new DefaultHttpHeaders();
|
||||
apiRequest.getHeaders().stream().filter(ApiHeaderDTO::isEnabled).forEach((header) -> {
|
||||
apiRequest.getHeaders().stream().filter(ApiRequestKeyValueDTO::isEnabled).forEach((header) -> {
|
||||
if(StringUtils.isNotEmpty(header.getKey()) && StringUtils.isNotEmpty(header.getValue())){
|
||||
customHeaders.set(header.getKey(), header.getValue());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.eactive.httpmockserver.common.exception;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CustomErrorResponse {
|
||||
|
||||
private LocalDateTime timestamp;
|
||||
private String error;
|
||||
private int status;
|
||||
|
||||
public LocalDateTime getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(LocalDateTime timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.eactive.httpmockserver.common.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<CustomErrorResponse> customHandleNotFound(Exception ex, WebRequest request) {
|
||||
CustomErrorResponse errors = new CustomErrorResponse();
|
||||
errors.setTimestamp(LocalDateTime.now());
|
||||
errors.setError(ex.getMessage());
|
||||
errors.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return new ResponseEntity<>(errors, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.eactive.httpmockserver.common.mapper;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestKeyValueDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Named;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
@@ -41,4 +42,40 @@ public class CommonMapper {
|
||||
|
||||
return grantedAuthorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String mapKeyValue(List<ApiRequestKeyValueDTO> list) {
|
||||
if (list == null) return "";
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (ApiRequestKeyValueDTO dto : list) {
|
||||
result.append(dto.toString()).append("||");
|
||||
}
|
||||
if (result.length() > 0) {
|
||||
result.setLength(result.length() - 2); // Remove the last "||"
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public List<ApiRequestKeyValueDTO> keyValueToList(String keyValue) {
|
||||
List<ApiRequestKeyValueDTO> list = new ArrayList<>();
|
||||
|
||||
if (!StringUtils.hasLength(keyValue)) return list;
|
||||
|
||||
String[] pairs = keyValue.split("\\|\\|");
|
||||
for (String pair : pairs) {
|
||||
ApiRequestKeyValueDTO dto = new ApiRequestKeyValueDTO();
|
||||
if (pair.startsWith("//")) {
|
||||
dto.setEnabled(false);
|
||||
pair = pair.substring(2);
|
||||
} else {
|
||||
dto.setEnabled(true);
|
||||
}
|
||||
String[] keyValueArray = pair.split("=");
|
||||
if (keyValueArray.length == 2) {
|
||||
dto.setKey(keyValueArray[0]);
|
||||
dto.setValue(keyValueArray[1]);
|
||||
list.add(dto);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
<div class="d-flex" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item" sec:authorize="isAuthenticated()">
|
||||
<a class="nav-link" href="/mgmt/routes/list_view.do">API 관리</a>
|
||||
<a class="nav-link" href="/mgmt/routes/list_view.do">응답 관리</a>
|
||||
</li>
|
||||
<li class="nav-item" sec:authorize="isAuthenticated()">
|
||||
<a class="nav-link" href="/mgmt/api_tester.do">API Tester</a>
|
||||
<a class="nav-link" href="/mgmt/api_tester.do">Tester</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN')">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="mgmtDropDown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
관리
|
||||
시스템 관리
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="mgmtDropDown">
|
||||
<li><a class="dropdown-item" href="/mgmt/users/list_view.do">사용자 관리</a></li>
|
||||
|
||||
@@ -15,35 +15,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- new collection button -->
|
||||
<div class="pt-new-collection p-1">
|
||||
<div class="p-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="new_collection"><i class="fa fa-plus"></i>새 컬렉션</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="new_request"><i class="fa fa-plus"></i>새 요청</button>
|
||||
</div>
|
||||
<div class="collapse pt-links" id="side_menubar" aria-label="sidebar menu">
|
||||
<ul class="list-unstyled mb-0 py-3 pt-md-1">
|
||||
<li th:each="collection, status: *{collections}">
|
||||
<a href="#" class="d-inline-flex align-items-center rounded">기본</a>
|
||||
</li>
|
||||
<div class="collapse pt-links" aria-label="sidebar menu">
|
||||
<ul class="list-unstyled mb-0 py-3 pt-md-1" id="side_menubar">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal fade" id="new_collection_modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal fade" id="new_collection_modal" tabindex="-1" aria-labelledby="new_collection_modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">새로운 컬렉션 추가</h5>
|
||||
<h5 class="modal-title">새로운 컬렉션 추가</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="text" class="form-control" placeholder="이름을 입력하세요" aria-label="이름을 입력하세요" aria-describedby="button-addon2" name="collection_name"/>
|
||||
<input type="text" class="form-control" placeholder="이름을 입력하세요" aria-label="이름을 입력하세요" aria-describedby="button-addon2" name="collection_name" required/>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-primary">저장</button>
|
||||
<button type="button" class="btn btn-primary save">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
|
||||
<!-- menu script -->
|
||||
@@ -51,7 +47,8 @@
|
||||
<script th:inline="javascript">
|
||||
$(function () {
|
||||
//when new_collection button clicked show modal popup for entering name
|
||||
$('#new_collection').click(function () {
|
||||
$('#new_collection').on('click', function () {
|
||||
$('#new_collection_modal').find('input').val('');
|
||||
$('#new_collection_modal').modal('show');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,6 +25,23 @@
|
||||
<div class="tab-content" id="apiRequestTabContent">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="new_api_request_modal" tabindex="-1" aria-labelledby="new_api_request_modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">새로운 API 추가</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<select class="form-select" id="modal_collection"></select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-primary add_new_request">추가</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="apiRequestTemplate" style="display: none;">
|
||||
<div class="tab-pane fade mt-1">
|
||||
<div class="d-flex align-items-center">
|
||||
@@ -208,6 +225,26 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<ul id="collectionTemplate" style="display: none;">
|
||||
<li>
|
||||
<div class="d-flex justify-content-between">
|
||||
<button class="btn d-inline-flex align-items-center rounded new_collection" data-bs-toggle="collapse"
|
||||
data-bs-target="" aria-expanded="false" aria-current="false">컬렉션
|
||||
</button>
|
||||
<button class="p-1 hover:text-white delete_collection"><i class="fa fa-trash-can"></i></button>
|
||||
</div>
|
||||
<div class="collapse">
|
||||
<ul class="list-unstyled fw-normal pb-1 small">
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul id="collectionApiTemplate" style="display: none;">
|
||||
<li class="d-flex justify-content-between">
|
||||
<a href="#" class="d-inline-flex align-items-center rounded"></a>
|
||||
<button class="p-1 hover:text-white delete_api_request"><i class="fa fa-trash-can"></i></button>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
@@ -216,12 +253,14 @@
|
||||
$(function () {
|
||||
|
||||
let apiRequests = [];
|
||||
let collections = [];
|
||||
|
||||
let view = {
|
||||
currentIdx: 0,
|
||||
responses: [],
|
||||
requests: [],
|
||||
init: function () {
|
||||
|
||||
$("#cancel-ajax").on("click", function () {
|
||||
if (controller.currentAjaxRequest) {
|
||||
controller.currentAjaxRequest.abort();
|
||||
@@ -230,12 +269,19 @@
|
||||
});
|
||||
|
||||
$('#new_request').on('click', function () {
|
||||
controller.addAPIRequest();
|
||||
$('#new_api_request_modal').modal('show');
|
||||
});
|
||||
|
||||
if (apiRequests.length === 0)
|
||||
controller.addAPIRequest();
|
||||
// this.render();
|
||||
$('#new_api_request_modal').find('.add_new_request').on('click', function () {
|
||||
controller.addAPIRequest($('#new_api_request_modal').find('select').val());
|
||||
|
||||
});
|
||||
|
||||
$('#new_collection_modal').find('.save').on('click', function () {
|
||||
controller.addCollection($('#new_collection_modal').find('input').val());
|
||||
});
|
||||
|
||||
controller.loadCollections();
|
||||
},
|
||||
renderParam: function (tabIdx) {
|
||||
let target = $('#api_request_' + tabIdx);
|
||||
@@ -397,7 +443,7 @@
|
||||
target.find('.send').click(function () {
|
||||
controller.send(idx);
|
||||
});
|
||||
var me = this;
|
||||
let me = this;
|
||||
|
||||
require(['vs/editor/editor.main'], function() {
|
||||
let requestBodyEditor = monaco.editor.create(target.find(".request_body")[0], {
|
||||
@@ -470,6 +516,38 @@
|
||||
target.find(".response_status").text("status: " + model.responseModel.status);
|
||||
target.find(".response_time").text("time: " + model.responseModel.time + "ms");
|
||||
target.find(".response_size").text("size: " + model.responseModel.size + "bytes");
|
||||
},
|
||||
renderCollections: function(){
|
||||
let select = $('#modal_collection');
|
||||
let sidemenu = $('#side_menubar');
|
||||
select.empty();
|
||||
sidemenu.empty();
|
||||
|
||||
for (let i = 0; i < collections.length; i++) {
|
||||
let template = $('#collectionTemplate').children().clone();
|
||||
template.find('button.new_collection').text(collections[i].name);
|
||||
template.find('button').attr('data-bs-target', '#collection_' + i);
|
||||
template.find('.collapse').attr('id', 'collection_' +i);
|
||||
|
||||
for (let j = 0; j < collections[i].apis.length; j++) {
|
||||
let collectionApiTemplate = $('#collectionApiTemplate').children().clone();
|
||||
let link = collectionApiTemplate.find('a');
|
||||
link.text(collections[i].apis[j].name);
|
||||
link.attr('data-collection', collections[i].id);
|
||||
link.attr('data-id', collections[i].apis[j].id);
|
||||
link.on('click', function(){
|
||||
controller.openApiRequest($(this).attr('data-collection'),$(this).attr('data-id'));
|
||||
})
|
||||
template.find('.collapse ul').append(collectionApiTemplate);
|
||||
}
|
||||
|
||||
let option = $('<option>');
|
||||
option.attr('value', collections[i].id);
|
||||
option.text(collections[i].name);
|
||||
|
||||
select.append(option);
|
||||
sidemenu.append(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +609,25 @@
|
||||
hideLoadingOverlay: function () {
|
||||
$("#loading-overlay").hide();
|
||||
},
|
||||
openApiRequest: function(collectionId, apiId) {
|
||||
let selectedApi = collections.filter(function (collection) {
|
||||
return collection.id === collectionId;
|
||||
})[0].apis.filter(function (api) {
|
||||
return api.id === apiId;
|
||||
})[0];
|
||||
if (selectedApi !== undefined){
|
||||
let tab = apiRequests.filter(function(api){
|
||||
return api.id === selectedApi.id;
|
||||
})[0];
|
||||
|
||||
if (tab === undefined){
|
||||
apiRequests.push(selectedApi);
|
||||
view.currentIdx = apiRequests.length - 1;
|
||||
view.renderTabHeader();
|
||||
view.renderTabContent(view.currentIdx);
|
||||
}
|
||||
}
|
||||
},
|
||||
send: function (tabIdx) {
|
||||
let model = apiRequests[tabIdx];
|
||||
let target = $('#api_request_' + tabIdx);
|
||||
@@ -541,7 +638,7 @@
|
||||
if (model.path !== '') {
|
||||
controller.showLoadingOverlay();
|
||||
this.currentAjaxRequest = $.ajax({
|
||||
url: '/api/test.do',
|
||||
url: '/mgmt/api/test.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(model),
|
||||
@@ -564,15 +661,68 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
addCollection: function () {
|
||||
|
||||
loadCollections: function(){
|
||||
controller.showLoadingOverlay();
|
||||
this.currentAjaxRequest = $.ajax({
|
||||
url: '/mgmt/collections/list.do',
|
||||
type: 'GET',
|
||||
contentType: 'application/json',
|
||||
success: function (data) {
|
||||
collections = data;
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
console.error(textStatus, errorThrown);
|
||||
controller.hideLoadingOverlay();
|
||||
},
|
||||
complete: function () {
|
||||
view.renderCollections();
|
||||
controller.hideLoadingOverlay();
|
||||
}
|
||||
});
|
||||
},
|
||||
removeCollection: function () {
|
||||
|
||||
addCollection: function (collection) {
|
||||
controller.showLoadingOverlay();
|
||||
this.currentAjaxRequest = $.ajax({
|
||||
url: '/mgmt/collections/create.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({name: collection}),
|
||||
success: function (data) {
|
||||
$('#new_collection_modal').modal('hide');
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
console.error(textStatus, errorThrown);
|
||||
controller.hideLoadingOverlay();
|
||||
},
|
||||
complete: function () {
|
||||
controller.loadCollections();
|
||||
controller.hideLoadingOverlay();
|
||||
}
|
||||
});
|
||||
},
|
||||
addAPIRequest: function () {
|
||||
let name = 'New Request ' + (apiRequests.length + 1);
|
||||
apiRequests.push({
|
||||
removeCollection: function (id) {
|
||||
controller.showLoadingOverlay();
|
||||
this.currentAjaxRequest = $.ajax({
|
||||
url: '/mgmt/collections/delete.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({id: id}),
|
||||
success: function () {
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
console.error(textStatus, errorThrown);
|
||||
controller.hideLoadingOverlay();
|
||||
},
|
||||
complete: function () {
|
||||
controller.loadCollections();
|
||||
controller.hideLoadingOverlay();
|
||||
}
|
||||
});
|
||||
},
|
||||
addAPIRequest: function (collectionId) {
|
||||
let name = 'New Request';
|
||||
let newApi = {
|
||||
id : '',
|
||||
server: null,
|
||||
method: 'GET',
|
||||
name: name,
|
||||
@@ -587,10 +737,34 @@
|
||||
headers: [],
|
||||
body: ''
|
||||
}
|
||||
};
|
||||
|
||||
this.currentAjaxRequest = $.ajax({
|
||||
url: '/mgmt/collections/{id}/apis/save.do'.replace('{id}', collectionId),
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(newApi),
|
||||
success: function (data) {
|
||||
console.log(data);
|
||||
newApi.id = data.id;
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
console.error(textStatus, errorThrown);
|
||||
controller.hideLoadingOverlay();
|
||||
},
|
||||
complete: function () {
|
||||
controller.loadCollections();
|
||||
controller.hideLoadingOverlay();
|
||||
apiRequests.push(newApi);
|
||||
view.currentIdx = apiRequests.length - 1;
|
||||
|
||||
view.renderTabHeader();
|
||||
view.renderTabContent(view.currentIdx);
|
||||
|
||||
$('#new_api_request_modal').modal('hide');
|
||||
controller.loadCollections();
|
||||
}
|
||||
});
|
||||
view.currentIdx = apiRequests.length - 1;
|
||||
view.renderTabHeader();
|
||||
view.renderTabContent(view.currentIdx);
|
||||
},
|
||||
removeAPIRequest: function (idx) {
|
||||
apiRequests.splice(idx, 1);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="container">
|
||||
<div class="card mt-1">
|
||||
<div class="card-header">
|
||||
<h1>API 목록</h1>
|
||||
<h1>응답 API 목록</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
Reference in New Issue
Block a user