diff --git a/README.md b/README.md index 4cf1226..ce0a1de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Spaceship :rocket: -![v1.4.0](https://github.com/sebastian4j/spaceship/blob/main/images/v1.4.0.png?raw=true) +![v1.5.0](https://github.com/sebastian4j/spaceship/blob/main/images/v1.5.0.png?raw=true) - Es una aplicación escrita en Java 17, JavaFX y compilable con GraalVM para una ejecución nativa. - Permite hacer peticiones a urls y visualizar la respuesta. @@ -17,6 +17,7 @@ - guardar el response obtenido - ver los milisegundos y bytes transferidos - muestra el código de estado http obtenido + - guardar el response directo a un archivo sin mostrar el contenido - Compilar la app: ``` @@ -25,10 +26,10 @@ mvn clean package - Lanzar la app: ``` linux: -java --module-path target/spaceship-1.4.0.jar:target/lib/ --module com.github.sebastian4j.spaceship/com.github.sebastian4j.spaceship.Spaceship +java --module-path target/spaceship-1.5.0.jar:target/lib/ --module com.github.sebastian4j.spaceship/com.github.sebastian4j.spaceship.Spaceship windows: -java --module-path target/spaceship-1.4.0.jar;target/lib/ --module com.github.sebastian4j.spaceship/com.github.sebastian4j.spaceship.Spaceship +java --module-path target/spaceship-1.5.0.jar;target/lib/ --module com.github.sebastian4j.spaceship/com.github.sebastian4j.spaceship.Spaceship ``` - Para compilarlo en forma nativa: - descargar graalvm-ce-java17-22.1.0 (me imagino que funciona con versiones posteriores) diff --git a/images/v1.5.0.png b/images/v1.5.0.png new file mode 100644 index 0000000..8893d5e Binary files /dev/null and b/images/v1.5.0.png differ diff --git a/pom.xml b/pom.xml index 504afcd..6238fb9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.github.sebastian4j spaceship - 1.4.0 + 1.5.0 UTF-8 17 @@ -111,6 +111,7 @@ javafx.scene.control.MenuItem impl.jfxtras.styles.jmetro.FluentButtonSkin impl.jfxtras.styles.jmetro.TextFieldSkin + javafx.scene.control.Alert com.github.sebastian4j.spaceship.fxml.RequestController com.github.sebastian4j.spaceship.fxml.RequestTabController com.github.sebastian4j.spaceship.dto.GUIRequest diff --git a/src/main/java/com/github/sebastian4j/spaceship/dto/RequestResponse.java b/src/main/java/com/github/sebastian4j/spaceship/dto/RequestResponse.java index 42c4d8b..8c8dc4d 100644 --- a/src/main/java/com/github/sebastian4j/spaceship/dto/RequestResponse.java +++ b/src/main/java/com/github/sebastian4j/spaceship/dto/RequestResponse.java @@ -3,5 +3,5 @@ import java.util.List; import java.util.Map; -public record RequestResponse(String body, Map> headers, long bytes, String statusCode) { +public record RequestResponse(String body, Map> headers, long bytes, String statusCode, byte[] response) { } diff --git a/src/main/java/com/github/sebastian4j/spaceship/fxml/RequestTabController.java b/src/main/java/com/github/sebastian4j/spaceship/fxml/RequestTabController.java index 6b11e7f..f614680 100644 --- a/src/main/java/com/github/sebastian4j/spaceship/fxml/RequestTabController.java +++ b/src/main/java/com/github/sebastian4j/spaceship/fxml/RequestTabController.java @@ -30,62 +30,48 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; public class RequestTabController implements Initializable, FileLoader { private static final System.Logger LOGGER = System.getLogger(RequestTabController.class.getName()); @FXML private FlowPane a; - @FXML private Button addHeader; - @FXML private TextArea bodyresult; - @FXML private VBox containerHeader; - @FXML private VBox containerHeaderResponse; - @FXML private ComboBox methods; - @FXML private TextArea requestbody; - @FXML private ScrollPane scrollHeaders; - @FXML private Button send; - @FXML private Tab tab1; - @FXML private Tab tab2; - @FXML private Text textFlowPaneResponse; - @FXML private TextField url; - @FXML private VBox vboxurl; - @FXML private HBox hboxResponse; - @FXML private VBox vboxResultResponse; - @FXML private BorderPane contenedor; - @FXML private TabPane tabsContainer; + @FXML + private CheckBox onlySave; private ResourceBundle rb; private File last; @@ -94,6 +80,7 @@ public class RequestTabController implements Initializable, FileLoader { private Task runningTask; private Future future; private RequestResponseUtils requestResponseUtils = new RequestResponseUtils(); + private File saveResponse = null; @FXML void addHeader(ActionEvent event) { addHeader(null, null); @@ -147,48 +134,70 @@ private void calculateHeaderResponseWidth(TextField tfk, TextField tfv) { tfv.setPrefWidth(widthVal); } + private File fileToSaveRequest() { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle(rb.getString("file.chooser.save")); + fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter(rb.getString("file.chooser.all.files"), "*.*")); + return fileChooser.showSaveDialog(null); + } + private void sendRequest() { + saveResponse = null; + var toFile = onlySave.isSelected(); + var send = new AtomicBoolean(true); + if (toFile) { + saveResponse = fileToSaveRequest(); + if (saveResponse == null) { + send.set(false); + FXMLUtils.showWarningAlert(rb.getString("only.save.error.title"), rb.getString("only.save.error.text")); + } + } + runningTask = new Task<>() { @Override protected Void call() { try { - LOGGER.log(System.Logger.Level.INFO, "enviando request"); - var ini = System.currentTimeMillis(); - var result = requestResponseUtils.sendRequest( - url.getText(), FXMLUtils.headers(containerHeader), - HttpMethods.hasBody(methods.getSelectionModel().getSelectedItem()), requestbody.getText()); - var res = System.currentTimeMillis() - ini; - Platform.runLater(() -> { - textFlowPaneResponse.setText( - rb.getString("milis") + ": " + res + - " bytes: " + result.bytes() + - " status: " + result.statusCode()); - VBox vb = new VBox(); - containerHeaderResponse.getChildren().clear(); - result.headers().forEach((a, b) -> { - for (var val : b) { - var key = new TextField(a); - key.setMinWidth(300); - var value = new TextField(val); - value.setMinWidth(400); - var hbox = new HBox(key, value); - hbox.setSpacing(2); - hbox.setAlignment(Pos.CENTER); - vb.getChildren().add(hbox); - calculateHeaderResponseWidth(key, value); - stage.widthProperty().addListener((observableValue, number, t1) -> - calculateHeaderResponseWidth(key, value) - ); - } + if (send.get()) { + LOGGER.log(System.Logger.Level.INFO, "enviando request"); + var ini = System.currentTimeMillis(); + var result = requestResponseUtils.sendRequest( + url.getText(), FXMLUtils.headers(containerHeader), + HttpMethods.hasBody(methods.getSelectionModel().getSelectedItem()), requestbody.getText(), + saveResponse); + + var res = System.currentTimeMillis() - ini; + Platform.runLater(() -> { + textFlowPaneResponse.setText( + rb.getString("milis") + ": " + res + + " bytes: " + result.bytes() + + " status: " + result.statusCode()); + VBox vb = new VBox(); + containerHeaderResponse.getChildren().clear(); + result.headers().forEach((a, b) -> { + for (var val : b) { + var key = new TextField(a); + key.setMinWidth(300); + var value = new TextField(val); + value.setMinWidth(400); + var hbox = new HBox(key, value); + hbox.setSpacing(2); + hbox.setAlignment(Pos.CENTER); + vb.getChildren().add(hbox); + calculateHeaderResponseWidth(key, value); + stage.widthProperty().addListener((observableValue, number, t1) -> + calculateHeaderResponseWidth(key, value) + ); + } + }); + var sp = new HBox(); + sp.setMinHeight(50); // espacio al final + vb.getChildren().add(sp); + containerHeaderResponse.getChildren().add(vb); + bodyresult.setText(result.body()); + tabsContainer.getSelectionModel().select(tab2); }); - var sp = new HBox(); - sp.setMinHeight(50); // espacio al final - vb.getChildren().add(sp); - containerHeaderResponse.getChildren().add(vb); - bodyresult.setText(result.body()); - tabsContainer.getSelectionModel().select(tab2); - }); - LOGGER.log(System.Logger.Level.INFO, "request finalizado"); + LOGGER.log(System.Logger.Level.INFO, "request finalizado"); + } } catch (Exception e) { LOGGER.log(System.Logger.Level.ERROR, "error al enviar request", e); } @@ -254,10 +263,11 @@ public void initialize(URL url, ResourceBundle rb) { scrollHeaders.widthProperty().addListener(cl -> { containerHeader.setMinWidth(scrollHeaders.getWidth()); containerHeaderResponse.setMinWidth(scrollHeaders.getWidth()); - this.url.setMinWidth(scrollHeaders.getWidth() - send.getWidth() - methods.getWidth() - 50); + this.url.setMinWidth(scrollHeaders.getWidth() - send.getWidth() - methods.getWidth() - 100); }); vboxResultResponse.heightProperty().addListener((observableValue, number, t1) -> resize()); resize(); + onlySave.setTooltip(new Tooltip(rb.getString("only.save"))); } private void resize() { diff --git a/src/main/java/com/github/sebastian4j/spaceship/utils/FXMLUtils.java b/src/main/java/com/github/sebastian4j/spaceship/utils/FXMLUtils.java index c7e1a42..f05a0ee 100644 --- a/src/main/java/com/github/sebastian4j/spaceship/utils/FXMLUtils.java +++ b/src/main/java/com/github/sebastian4j/spaceship/utils/FXMLUtils.java @@ -3,6 +3,7 @@ import com.github.sebastian4j.spaceship.dto.GUIRequest; import com.github.sebastian4j.spaceship.dto.Header; import javafx.scene.Node; +import javafx.scene.control.Alert; import javafx.scene.control.TextField; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; @@ -68,4 +69,11 @@ public static Map headers(VBox container) { }); return headers; } + + public static void showWarningAlert(String title, String text) { + var alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle(title); + alert.setContentText(text); + alert.show(); + } } diff --git a/src/main/java/com/github/sebastian4j/spaceship/utils/RequestResponseUtils.java b/src/main/java/com/github/sebastian4j/spaceship/utils/RequestResponseUtils.java index 7c0d1ec..49b4a06 100644 --- a/src/main/java/com/github/sebastian4j/spaceship/utils/RequestResponseUtils.java +++ b/src/main/java/com/github/sebastian4j/spaceship/utils/RequestResponseUtils.java @@ -2,6 +2,8 @@ import com.github.sebastian4j.spaceship.dto.RequestResponse; +import java.io.File; +import java.io.FileOutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -33,7 +35,8 @@ public void kill() { } } - public RequestResponse sendRequest(final String url, Map headers, boolean withBody, final String body) { + public RequestResponse sendRequest(final String url, Map headers, boolean withBody, + final String body, File toFile) { String result = ""; final var sb = new StringBuilder(); final var bytes = new AtomicLong(); @@ -56,11 +59,20 @@ public RequestResponse sendRequest(final String url, Map headers String res = ""; int lee; LOGGER.log(System.Logger.Level.INFO, "leyendo en thread"); - while ((lee = is.read()) != -1) { - sb.append((char) lee); + if (toFile == null) { // retornar la salida + while ((lee = is.read()) != -1) { + sb.append((char) lee); + } + res = sb.toString(); + bytes.set(res.getBytes(StandardCharsets.UTF_8).length); + } else { // guardar en archivo la salida + try (var os = new FileOutputStream(toFile)) { + var br = is.readAllBytes(); + os.write(br); + bytes.set(br.length); + } } - res = sb.toString(); - bytes.set(res.getBytes(StandardCharsets.UTF_8).length); + } hr.putAll(con.getHeaderFields()); } catch (Exception e) { @@ -79,7 +91,7 @@ public RequestResponse sendRequest(final String url, Map headers LOGGER.log(System.Logger.Level.ERROR, "error al enviar request", e); result = e.getMessage() + " ~ " + readError(); } - return new RequestResponse(result, hr, bytes.get(), statusCode[0]); + return new RequestResponse(result, hr, bytes.get(), statusCode[0], new byte[]{}); } private String readError() { diff --git a/src/main/resources/label.properties b/src/main/resources/label.properties index 5a25fd5..fe9a477 100644 --- a/src/main/resources/label.properties +++ b/src/main/resources/label.properties @@ -21,4 +21,8 @@ milis=miliseconds cancel.send=Cancel no.name=Default file.extension=spc -file.quick.save=Save \ No newline at end of file +file.quick.save=Save +only.save=response to file +only.save.error.title=Unable to save response +only.save.error.text=Select the destination file +only.save.response=save \ No newline at end of file diff --git a/src/main/resources/requestTab.fxml b/src/main/resources/requestTab.fxml index 7f615d4..f42f9f2 100644 --- a/src/main/resources/requestTab.fxml +++ b/src/main/resources/requestTab.fxml @@ -3,6 +3,7 @@ + @@ -14,8 +15,13 @@ - +