APITester 기본 기능 완료
This commit is contained in:
+33
-5
@@ -1,28 +1,56 @@
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/mgmt")
|
||||
public class ApiClientController {
|
||||
|
||||
@Autowired
|
||||
ServerRepository serverRepository;
|
||||
private ServerRepository serverRepository;
|
||||
|
||||
@GetMapping("/api_tester.do")
|
||||
public String testView(ModelMap model){
|
||||
@Autowired
|
||||
private ApiTesterService apiTesterService;
|
||||
|
||||
@Autowired
|
||||
private NettyApiClient nettyApiClient;
|
||||
|
||||
@PostMapping("/api/test.do")
|
||||
@ResponseBody
|
||||
public ApiResponse handleApiRequest(@RequestBody ApiRequestDTO request) {
|
||||
|
||||
try {
|
||||
return nettyApiClient.handleRequest(request).get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/mgmt/api_tester.do")
|
||||
public String testView(ModelMap model,
|
||||
@CurrentUser StaffUser user) {
|
||||
|
||||
List<Server> servers = serverRepository.findAll();
|
||||
List<ApiCollection> collections = apiTesterService.findMyCollections(user.getEsntlId());
|
||||
|
||||
model.addAttribute("servers", servers);
|
||||
model.addAttribute("collections", collections);
|
||||
|
||||
return "page/apiTester";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
public class ApiHeaderDTO {
|
||||
|
||||
private String key;
|
||||
private String value;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
public class ApiRequest {
|
||||
|
||||
private String uri;
|
||||
private String method;
|
||||
|
||||
private String body;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ApiRequestDTO {
|
||||
|
||||
private String path;
|
||||
private String method;
|
||||
|
||||
private Long server;
|
||||
|
||||
private List<ApiHeaderDTO> headers;
|
||||
private String body;
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Long getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Long server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(List<ApiHeaderDTO> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,46 @@
|
||||
package com.eactive.httpmockserver.client.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ApiResponse {
|
||||
|
||||
private int status;
|
||||
|
||||
private List<ApiHeaderDTO> headers;
|
||||
|
||||
private String body;
|
||||
|
||||
private int size;
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(List<ApiHeaderDTO> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiHeaderDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class HttptHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
|
||||
|
||||
private final CompletableFuture<ApiResponse> responseFuture;
|
||||
|
||||
public HttptHandler(CompletableFuture<ApiResponse> responseFuture) {
|
||||
this.responseFuture = responseFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
|
||||
|
||||
ApiResponse apiResponse = new ApiResponse();
|
||||
apiResponse.setStatus(response.status().code());
|
||||
apiResponse.setHeaders(convertHttpHeadersToList(response.headers()));
|
||||
apiResponse.setBody(response.content().toString(CharsetUtil.UTF_8));
|
||||
|
||||
int headerSize = calculateHeaderSize(response.headers());
|
||||
int contentSize = response.content().readableBytes();
|
||||
int totalSize = headerSize + contentSize;
|
||||
apiResponse.setSize(totalSize);
|
||||
|
||||
responseFuture.complete(apiResponse);
|
||||
}
|
||||
|
||||
private int calculateHeaderSize(HttpHeaders headers) {
|
||||
int headerSize = 0;
|
||||
for (Map.Entry<String, String> entry : headers.entries()) {
|
||||
headerSize += entry.getKey().length() + entry.getValue().length() + 4; // Add 2 for ': ' and 2 for '\r\n'
|
||||
}
|
||||
|
||||
// Add 2 for the final '\r\n' after the headers
|
||||
headerSize += 2;
|
||||
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
public List<ApiHeaderDTO> convertHttpHeadersToList(HttpHeaders headers) {
|
||||
List<ApiHeaderDTO> headerList = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entry : headers.entries()) {
|
||||
ApiHeaderDTO header = new ApiHeaderDTO();
|
||||
header.setKey(entry.getKey());
|
||||
header.setValue(entry.getValue());
|
||||
headerList.add(header);
|
||||
}
|
||||
|
||||
return headerList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
responseFuture.completeExceptionally(cause);
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.eactive.httpmockserver.client.service;
|
||||
|
||||
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
||||
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
||||
import com.eactive.httpmockserver.client.entity.Server;
|
||||
import com.eactive.httpmockserver.client.repository.ServerRepository;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Service
|
||||
public class NettyApiClient {
|
||||
|
||||
@Autowired
|
||||
ServerRepository serverRepository;
|
||||
|
||||
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO apiRequest) throws Exception {
|
||||
|
||||
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new Exception("Server not found"));
|
||||
String host = server.getHostname();
|
||||
int port = server.getPort();
|
||||
|
||||
CompletableFuture<ApiResponse> responseFuture = new CompletableFuture<>();
|
||||
EventLoopGroup group = new NioEventLoopGroup();
|
||||
try {
|
||||
Bootstrap b = new Bootstrap()
|
||||
.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.handler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
public void initChannel(Channel ch) {
|
||||
ch.pipeline().addLast(new HttpClientCodec());
|
||||
ch.pipeline().addLast(new HttpObjectAggregator(65536));
|
||||
ch.pipeline().addLast(new HttpContentDecompressor());
|
||||
ch.pipeline().addLast(new HttptHandler(responseFuture));
|
||||
}
|
||||
});
|
||||
|
||||
Channel ch = b.connect(host, port).sync().channel();
|
||||
|
||||
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(apiRequest.getMethod()),
|
||||
apiRequest.getPath(), Unpooled.EMPTY_BUFFER);
|
||||
|
||||
request.headers().set("Host", host);
|
||||
request.headers().set("Connection", "close");
|
||||
request.headers().set("Accept-Encoding", "gzip");
|
||||
|
||||
ch.writeAndFlush(request);
|
||||
ch.closeFuture().sync();
|
||||
} finally {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
|
||||
return responseFuture;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user