--- title: "Programar tu aplicación" url: https://docs.catalyst.zoho.com/es/tutorials/alien-city-appsail/springboot/code-app/ description: "Crea una aplicación y hospédala en Catalyst AppSail con Catalyst Data Store, que te permite reportar o buscar encuentros con alienígenas en una ciudad." last_updated: 2026-11-04T10:10:44Z service: All Services type: tutorial related_links: - name: "Catalyst SDK for AppSail" url: /es/cli/v1/initialize-resources/introduction/ --- # Programar tu aplicación En el directorio `aliencity/src/main/java/com/catalyst/appsail/aliencity/`, crea un archivo de código Java y nómbralo `AlienCity.java`. Este archivo de código contendrá la lógica del backend de tu aplicación. En el directorio `aliencity/src/main/resources/static`, crea los siguientes archivos: - `index.html`: El archivo que contiene el código HTML para el front-end de la aplicación. - `main.js`: El archivo que contiene el código JavaScript que conecta el front-end y el backend. La estructura final del directorio del proyecto **Spring Boot - JAR** de `aliencity/` se muestra a continuación: ![catalyst_alcity_appsail_spring_complete](https://catalyst-docs-development.zohostratus.in/images/tutorials/alien-city-appsail-express/catalyst_alcity_appsail_spring_complete.webp) Programarás los archivos `AlienCity.java`, `AliencityApplication.java`, `index.html` y `main.js`. También actualizarás los archivos `app-config.json` y `pom.xml`. > **Nota:** Por favor, revisa el código en esta sección para asegurarte de que lo comprendes completamente. Copia el código a continuación y pégalo en los archivos correspondientes de tu proyecto usando un IDE y guarda los archivos: **AlienCity.java** ```java package com.catalyst.appsail.aliencity; import org.springframework.web.bind.annotation.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.zc.auth.CatalystSDK; import com.zc.component.object.ZCObject; import com.zc.component.object.ZCRowObject; import com.zc.component.zcql.ZCQL; import org.springframework.http.ResponseEntity; import org.apache.commons.logging.Log; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @RestController public class AlienCity { Map<String, String> responseMap = new HashMap<>(); private int getAlienCountFromCatalystDataStore(String cityName) throws Exception { String query = "Select * from AlienCity where CityName = '" + cityName + "'"; Logger.getLogger(AlienCity.class.getName()).info("Query: " + query); ArrayList<ZCRowObject> rowList = ZCQL.getInstance().executeQuery(query); return rowList.size(); } @GetMapping("/alien") public ResponseEntity<String> getAlienEncounter(@RequestParam String city_name, HttpServletRequest request, HttpServletResponse response) throws Exception { CatalystSDK.init(request); try { int length = getAlienCountFromCatalystDataStore(city_name); if (length == 0) { responseMap.put("message", "Hurray! No alien encounters in this city yet!"); responseMap.put("signal", "negative"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } else { responseMap.put("message", "Uh oh! Looks like there are aliens in this city!"); responseMap.put("signal", "positive"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } } catch (Exception e) { e.printStackTrace(); responseMap.put("message", "Internal Server Error"); responseMap.put("signal", "error"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } } @PostMapping("/alien") public ResponseEntity<String> postAlienEncounter(HttpServletRequest request, HttpServletResponse response, @RequestBody String requestBody) throws Exception { CatalystSDK.init(request); JSONParser jsonParser = new JSONParser(); JSONObject jsonObject = (JSONObject) jsonParser.parse(requestBody); String cityname = (String) jsonObject.get("city_name"); try { int length = getAlienCountFromCatalystDataStore(cityname); if (length > 0) { responseMap.put("message", "Looks like you are not the first person to encounter aliens in this city! Someone has already reported an alien encounter here!"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } else { ZCRowObject row = ZCRowObject.getInstance(); row.set("CityName", cityname); ZCObject.getInstance().getTableInstance("AlienCity").insertRow(row); responseMap.put("message", "Thanks for reporting!"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } } catch (Exception e) { e.printStackTrace(); responseMap.put("message", "Internal Server Error"); String jsonResponse = new ObjectMapper().writeValueAsString(responseMap); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse); } } } ``` **AliencityApplication.java** ```java package com.catalyst.appsail.aliencity; import java.util.Collections; import javax.servlet.http.HttpServlet; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AliencityApplication extends HttpServlet { public static void main(String[] args) { String port = System.getenv().getOrDefault("X_ZOHO_CATALYST_LISTEN_PORT","3000"); SpringApplication app = new SpringApplication(AliencityApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port",port)); app.run(args); } } ``` **index.html** ```xml <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AlientCityAppClient</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" media="screen" href="main.css" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"> </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"> </script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"> </script> <script src="/main.js"> </script> </head> <body> <br> <br> <center> <h1>ALIEN CITY</h1> </center> <div class="container"> <ul class="nav nav-tabs" id="myTab" role="tablist"> <li class="nav-item"> <a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab" aria-controls="check" aria-selected="true">Check My City</a> </li> <li class="nav-item"> <a class="nav-link" id="report-tab" data-toggle="tab" href="#report" role="tab" aria-controls="report" aria-selected="false">Report Alien Encounter</a> </li> </ul> <div class="tab-content" id="myTabContent"> <div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab"> <br> <br> <form> <div class="form-group"> <label for="city-get-input"> <b>Check if your city has aliens:</b> </label> <input type="text" class="form-control" id="city-get-input" aria-describedby="checkCity" placeholder="Enter City Name"> </div> <button type="submit" class="btn btn-primary" onclick="getAlienEncounter();return false;">Check</button> </form> <br> <br> <div id="result-container"> <div id="result-text"> </div> <br> <div id="result-image"> </div> </div> <div id="loader" style="display: none;"> <div class="spinner-border" role="status"> <span class="sr-only">Loading...</span> </div> </div> </div> <div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab"> <br> <br> <form> <div class="form-group"> <div class="city-post-input"> <label for="exampleInputEmail1"> <b>Enter the name of the city where you encountered an alien:</b> </label> <input type="text" class="form-control" id="city-post-input" aria-describedby="cityPost" placeholder="Enter City Name"> </div> </div> <button type="submit" class="btn btn-primary" onclick="postAlienEncounter();return false;">Report</button> </form> </div> </div> </div> </body> </html> ``` **main.js** ```javascript function postAlienEncounter() { debugger; var city = $("#city-post-input").val(); $.ajax({ url: "/alien", type: "post", contentType: "application/json", data: JSON.stringify({ "city_name": city }), success: function (data) { alert(data.message); }, error: function (error) { alert(error.message); } }); } function getAlienEncounter() { debugger showLoader(); var positive = "https://media.giphy.com/media/Y1GYiLui9NHcxVKhdo/giphy.gif"; var negative = "https://media.giphy.com/media/fsPcMdeXPxSP6zKxCA/giphy.gif"; var city = $("#city-get-input").val(); $.ajax({ url: "/alien?city_name=" + city, type: "get", success: function (data) { console.log(data); $("#result-text").text(""); $("#result-text").text(data.message); var imagesrc = negative; if (data.signal == 'positive') { imagesrc = positive; } $("#result-image").html(""); $("#result-image").html("<img src='" + imagesrc + "' />"); hideLoader(); }, error: function (error) { alert(error.message); } }); } function showLoader() { $("#result-container").hide(); $("#loader").show(); } function hideLoader() { $("#loader").hide(); $("#result-container").show(); } ``` **pom.xml** ```xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.10</version> <!-- Cambia la versión a este valor --> <relativePath /> </parent> <groupId>com.catalyst.appsail</groupId> <artifactId>aliencity</artifactId> <version>0.0.1-SNAPSHOT</version> <name>aliencity</name> <packaging>jar</packaging> <!-- Incluye esto --> <description>learning Catalyst AppSail~</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.zoho.catalyst</groupId> <artifactId>java-sdk</artifactId> <version>0.0.1</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.9.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.3</version> <scope>compile</scope> </dependency> <!-- API de Servlet para HttpServlet --> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.1</version> <!-- Usa la versión compatible con tu proyecto --> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <!--Instala los repositorios requeridos--> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> </repository> <repository> <id>java-sdk</id> <url>https://maven.zohodl.com</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> </project> ``` > **Nota:** No cambies la versión en la línea **14**. Solo puedes hospedar tu aplicación en AppSail si la versión es `2.7.10` o menor. **app-config.json** ```json { "command": "java -jar aliencity-0.0.1-SNAPSHOT.jar", "buildPath": "./target/", "stack": "java17", "env_variables": {}, "memory": 256, "scripts": { "preserve": "mvn clean package", "predeploy": "mvn clean package" }, "platform": "javase" } ``` > **Nota:** Asegúrate de proporcionar el valor correcto para la clave `buildpath`. Repasemos rápidamente el funcionamiento de la aplicación: 1. **Operación GET** - Cuando ingresas el nombre de una ciudad en la aplicación para verificar si hay un registro de encuentros previos con alienígenas, el evento onClick del botón **Check** en `index.html` activa la función `getAlienEncounter()` definida en `main.js`. - Esto realiza una llamada Ajax a la ruta URL definida en la función `AlienCity.java`. - La **GET API** definida en `AlienCity.java` luego invoca la función `getAlienCountFromCatalystDataStore()` y pasa la consulta de la solicitud. - Esta función busca los datos en la tabla **Alien City** en el *Data Store* ejecutando una consulta ZCQL. - Si se encuentra un registro que coincide con el nombre de la ciudad en la tabla, se envía una señal *positiva* como respuesta. De lo contrario, se envía una señal *negativa* como respuesta. - El client luego muestra el mensaje que coincide con la respuesta. También se muestra un GIF que coincide con la respuesta definida en `main.js`. 2. **Operación POST** - Cuando ingresas el nombre de una ciudad en el client para reportar un encuentro con alienígenas, el evento onClick del botón **Report** en `index.html` activa la función `postAlienEncounter()` definida en `main.js`. - Esto realiza una llamada Ajax a la ruta URL definida en la función `AlienCity.java`. La POST API definida en `AlienCity.java` luego invoca la función `getAlienCountFromCatalystDataStore()` y pasa una consulta de solicitud para verificar si ya existe un registro con el mismo nombre de ciudad. - Esta función busca los datos en la tabla **Alien City** en el *Data Store* ejecutando una consulta ZCQL. Si el registro ya existe, se envía una respuesta que permite a la aplicación mostrar un mensaje de que el nombre de la ciudad ya fue agregado. - Si no hay registros para el nombre de la ciudad, se crea una nueva fila en la tabla **Alien City** para el nombre de la ciudad ingresado por el usuario. Se muestra un cuadro emergente en el client confirmando la inserción del registro en el *Data Store*. También se envía un mensaje apropiado a los logs que se puede verificar desde el componente [*Logs*](https://docs.catalyst.zoho.com/es/devops/help/logs/introduction/) presente en el servicio [Catalyst DevOps](https://docs.catalyst.zoho.com/es/devops/).