This commit is contained in:
현성필
2023-05-12 11:47:09 +09:00
parent ac5f4146f4
commit c47320f56c
24 changed files with 444 additions and 30 deletions
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -109,13 +110,9 @@ public class MockApiController {
}
} else if (condition.getType().equalsIgnoreCase("jsonpath")) {
try{
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(request.getBody());
boolean isMatch = JsonPath.parse(jsonNode).read(condition.getKey()+ '=' + condition.getValue());
if (!isMatch) {
return false;
}
} catch (JsonProcessingException e) {
Object value = JsonPath.read(request.getBody(), condition.getKey());
return value.toString().equals(condition.getValue());
}catch(PathNotFoundException e) {
return false;
}
}
@@ -47,7 +47,7 @@ public class MockRouteMgmtController {
public String createView(ModelMap model) {
MockRouteDTO defaultRoute = new MockRouteDTO();
MockResponseDTO defaultResponse = new MockResponseDTO();
defaultResponse.setDefaultResponse(true);
defaultResponse.setDefaultResponse("true");
defaultRoute.getResponses().add(defaultResponse);
model.addAttribute("mockRoute", defaultRoute);
return MOCK_ROUTE_EDIT;
@@ -15,7 +15,7 @@ public class MockResponseDTO {
private long delay = 0; //millisecond
private boolean defaultResponse = false;
private String defaultResponse;
private List<MockConditionDTO> conditions;
public int getStatusCode() {
@@ -58,11 +58,11 @@ public class MockResponseDTO {
this.conditions = conditions;
}
public boolean isDefaultResponse() {
public String getDefaultResponse() {
return defaultResponse;
}
public void setDefaultResponse(boolean defaultResponse) {
public void setDefaultResponse(String defaultResponse) {
this.defaultResponse = defaultResponse;
}
}
@@ -27,11 +27,24 @@ public abstract class MockRouteMapper {
public abstract MockRouteDTO map(MockRoute entity);
@Mapping(target = "headers", source = "headers", qualifiedByName = "mapHeadersToMap")
@Mapping(target ="defaultResponse", source = "defaultResponse", qualifiedByName = "mapEntityDefaultResponse")
public abstract MockResponse map(MockResponseDTO dto);
@Mapping(target = "headers", source = "headers", qualifiedByName = "mapHeadersToList")
@Mapping(target ="defaultResponse", source = "defaultResponse", qualifiedByName = "mapDTODefaultResponse")
public abstract MockResponseDTO map(MockResponse entity);
@Named("mapDTODefaultResponse")
public String map(boolean value) {
return value ? "true" : "false";
}
@Named("mapEntityDefaultResponse")
public boolean map(String value) {
if (value == null) return false;
return value.equals("true");
}
@Named("mapHeadersToList")
public List<MockHeaderDTO> mapHeadersToList(Map<String, String> headers) {
List<MockHeaderDTO> list = new ArrayList<>();
@@ -28,6 +28,11 @@ public class MockRouteService {
}
public void create(MockRoute mockRoute) {
if (!mockRoute.getPathPattern().startsWith("/")){
mockRoute.setPathPattern("/" + mockRoute.getPathPattern());
}
for (MockResponse response : mockRoute.getResponses()) {
response.setRoute(mockRoute);
@@ -53,6 +58,9 @@ public class MockRouteService {
route.setDescription(updated.getDescription());
route.setMethod(updated.getMethod());
route.setPathPattern(updated.getPathPattern());
if (!route.getPathPattern().startsWith("/")){
route.setPathPattern("/" + route.getPathPattern());
}
route.getResponses().addAll(updated.getResponses());
for (MockResponse response : route.getResponses()) {
@@ -0,0 +1,60 @@
package com.eactive.httpmockserver.client.entity;
import com.eactive.httpmockserver.user.entity.StaffUser;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "API_COLLECTION")
public class ApiCollection {
@Id
private String id; //uuid
private String name;
@ManyToOne
@JoinColumn(name = "USER_ID")
private StaffUser owner;
@ManyToMany
@JoinTable(
name = "API_COLLECTION_API_REQUEST_INFO",
joinColumns = @JoinColumn(name = "API_COLLECTION_ID"),
inverseJoinColumns = @JoinColumn(name = "API_REQUEST_INFO_ID")
)
private List<ApiRequestInfo> apis;
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 List<ApiRequestInfo> getApis() {
return apis;
}
public void setApis(List<ApiRequestInfo> apis) {
this.apis = apis;
}
public StaffUser getOwner() {
return owner;
}
public void setOwner(StaffUser owner) {
this.owner = owner;
}
}
@@ -0,0 +1,116 @@
package com.eactive.httpmockserver.client.entity;
import com.eactive.httpmockserver.user.entity.StaffUser;
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.time.LocalDateTime;
public class ApiRequestHistory {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ManyToOne
@JoinColumn(name = "SERVER_ID")
private Server server;
@ManyToOne
@JoinColumn(name = "USER_ID")
private StaffUser owner;
private String method;
private String uri;
private String requestHeaders;
private String requestBody;
private String responseBody;
private String responseHeaders;
@Type(type = "org.hibernate.type.LocalDateTimeType")
private LocalDateTime requestTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
}
public StaffUser getOwner() {
return owner;
}
public void setOwner(StaffUser owner) {
this.owner = owner;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getRequestHeaders() {
return requestHeaders;
}
public void setRequestHeaders(String requestHeaders) {
this.requestHeaders = requestHeaders;
}
public String getRequestBody() {
return requestBody;
}
public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}
public String getResponseBody() {
return responseBody;
}
public void setResponseBody(String responseBody) {
this.responseBody = responseBody;
}
public String getResponseHeaders() {
return responseHeaders;
}
public void setResponseHeaders(String responseHeaders) {
this.responseHeaders = responseHeaders;
}
public LocalDateTime getRequestTime() {
return requestTime;
}
public void setRequestTime(LocalDateTime requestTime) {
this.requestTime = requestTime;
}
}
@@ -0,0 +1,96 @@
package com.eactive.httpmockserver.client.entity;
import com.eactive.httpmockserver.user.entity.StaffUser;
import javax.persistence.*;
@Entity
@Table(name = "API_REQUEST_INFO")
public class ApiRequestInfo {
@Id
private String id; //uuid
@ManyToOne
@JoinColumn(name = "SERVER_ID")
private Server server;
@ManyToOne
@JoinColumn(name = "USER_ID")
private StaffUser owner;
private String method;
private String path;
private String headers;
private String queryParams;
private String requestBody;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
}
public StaffUser getOwner() {
return owner;
}
public void setOwner(StaffUser owner) {
this.owner = owner;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getHeaders() {
return headers;
}
public void setHeaders(String headers) {
this.headers = headers;
}
public String getQueryParams() {
return queryParams;
}
public void setQueryParams(String queryParams) {
this.queryParams = queryParams;
}
public String getRequestBody() {
return requestBody;
}
public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}
}
@@ -16,6 +16,8 @@ public class Server {
private String hostname;
private String basePath;
private int port;
public Long getId() {
@@ -50,6 +52,14 @@ public class Server {
this.hostname = hostname;
}
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public int getPort() {
return port;
}
@@ -60,6 +70,6 @@ public class Server {
@Transient
public String getHostAddress() {
return scheme + "://" + hostname + ":" + port;
return scheme + "://" + hostname;
}
}
@@ -0,0 +1,13 @@
package com.eactive.httpmockserver.client.repository;
import com.eactive.httpmockserver.client.entity.ApiCollection;
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 ApiCollectionRepository extends JpaRepository<ApiCollection, String>, JpaSpecificationExecutor<ApiCollection> {
List<ApiCollection> findAllByOwner(StaffUser owner);
}
@@ -0,0 +1,8 @@
package com.eactive.httpmockserver.client.repository;
import com.eactive.httpmockserver.client.entity.ApiRequestInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface ApiRequestRepository extends JpaRepository<ApiRequestInfo, String>, JpaSpecificationExecutor<ApiRequestInfo> {
}
@@ -0,0 +1,25 @@
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));
}
}
@@ -73,8 +73,13 @@ public class NettyApiClient {
content = Unpooled.EMPTY_BUFFER;
}
String basePath = server.getBasePath();
if(!apiRequest.getPath().startsWith("/")){
basePath = basePath + "/";
}
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(apiRequest.getMethod()),
apiRequest.getPath(), content);
(basePath + apiRequest.getPath()).replaceAll("//", "/"), content);
request.headers().set("Host", host);
request.headers().set("Connection", HttpHeaderValues.CLOSE);
@@ -17,7 +17,7 @@ public class PortalErrorController implements ErrorController {
if (status != null) {
model.addAttribute("status", status);
return "/error";
return "error";
}
return "redirect:/";
@@ -26,7 +26,7 @@ public class AccountController {
@GetMapping("/change_password.do")
public String changePassword(ModelMap model, @ModelAttribute("passwordChangeRequest") PasswordChangeRequestDTO passwordChangeRequestDTO) {
return "/apps/main/updatePw";
return "apps/main/updatePw";
}
@PostMapping(value = "/update_password.do")
@@ -51,7 +51,7 @@ public class AccountController {
model.addAttribute("resultMsg", resultMsg);
model.addAttribute("passwordChangeRequest", new PasswordChangeRequestDTO());
return "/apps/main/updatePw";
return "apps/main/updatePw";
}
@@ -0,0 +1,51 @@
package com.eactive.httpmockserver.user.entity;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "PT_USER_GROUP")
public class UserGroup {
@Id
private String id;
private String name;
private String description;
@OneToMany(mappedBy = "group", fetch = FetchType.LAZY)
private List<StaffUser> users;
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<StaffUser> getUsers() {
return users;
}
public void setUsers(List<StaffUser> users) {
this.users = users;
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ spring:
show-sql: false
database-platform: org.hibernate.dialect.H2Dialect
thymeleaf:
prefix: classpath:templates/
prefix: classpath:/templates/
check-template-location: true
suffix: .html
mode: HTML
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/api_tester_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/api_tester_layout}">
<body>
<section layout:fragment="contentFragment">
@@ -28,7 +28,7 @@
<div id="apiRequestTemplate" style="display: none;">
<div class="tab-pane fade mt-1">
<div class="d-flex align-items-center">
<div class="form-floating col-md-2 me-1">
<div class="form-floating col-md-1 me-1">
<select name="method" class="form-select method">
<option value="POST">POST</option>
<option value="GET">GET</option>
@@ -42,12 +42,18 @@
</select>
<label class="form-label must">Method</label>
</div>
<div class="form-floating col-md-3 me-1">
<div class="form-floating col-md-1 me-1">
<select class="form-select server" name="server">
<option th:each="server : ${servers}" th:value="${server.id}" th:text="${server.name}"></option>
<option th:each="server : ${servers}" th:value="${server.id}" th:text="${server.name}" th:data-path="${server.basePath}"></option>
</select>
<label class="form-label must">Server</label>
</div>
<div class="form-floating col-md-1 me-1">
<div class="form-floating col-md">
<input type="text" name="basePath" class="form-control" readonly>
<label class="must">base path</label>
</div>
</div>
<div class="input-group col-md">
<div class="form-floating col-md">
<input type="text" name="path" class="form-control path" placeholder="호출할 경로 (/부터 입력)"
@@ -351,9 +357,12 @@
});
model.server = target.find('select[name="server"]').val();
target.find('input[name="basePath"]').val(target.find('select[name="server"] option:selected').data('path'));
target.find('.server').on('change', function () {
target.find('select[name="server"]').on('change', function () {
model.server = $(this).val();
let selected = $(this).find('option:selected');
target.find('input[name="basePath"]').val(selected.data('path'));
});
target.find('.method').on('change', function () {
+1 -1
View File
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/base_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/base_layout}">
<body>
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/default_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
<body>
<section layout:fragment="contentFragment">
@@ -52,7 +52,7 @@
<input type="number" th:field="*{responses[__${status.index}__].statusCode}" required/>
<textarea th:field="*{responses[__${status.index}__].body}"></textarea>
<input type="number" th:field="*{responses[__${status.index}__].delay}" required/>
<input type="text" th:field="*{responses[__${status.index}__].defaultResponse}" />
<input type="hidden" th:field="*{responses[__${status.index}__].defaultResponse}" />
<ul class="response_conditions">
<li th:each="condition, status: *{responses[__${status.index}__].conditions}">
<select>
@@ -122,6 +122,7 @@
<div class="card-header">응답 내용</div>
<div class="card-body">
<div class="form-floating mt-1">
<input type="hidden" name="defaultResponse" required/>
<input class="form-control" type="number" name="statusCode" required/>
<label class="form-label must">Status</label>
</div>
@@ -319,10 +320,12 @@
nodeCopy.find('.btn_add_condition').attr("data-id", i);
nodeCopy.find('.btn_add_header').attr("data-id", i);
nodeCopy.find('input[name="statusCode"]').attr('name', 'responses[' + i + '].statusCode');
nodeCopy.find('input[name="defaultResponse"]').attr('name', 'responses[' + i + '].defaultResponse');
nodeCopy.find('input[name="delay"]').attr('name', 'responses[' + i + '].delay');
nodeCopy.find('textarea[name="body"]').attr('name', 'responses[' + i + '].body');
nodeCopy.find('input[name="responses[' + i + '].statusCode"]').val(model.responses[i].statusCode);
nodeCopy.find('input[name="responses[' + i + '].defaultResponse"]').val(model.responses[i].defaultResponse);
nodeCopy.find('input[name="responses[' + i + '].delay"]').val(model.responses[i].delay);
nodeCopy.find('textarea[name="responses[' + i + '].body"]').val(model.responses[i].body);
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/default_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
<body>
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/base_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/base_layout}">
<body>
<section layout:fragment="contentFragment">
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/default_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
<body>
<section layout:fragment="contentFragment">
@@ -1,6 +1,6 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/layout/default_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
<body>