Web Dev in HTML/CSS/JS • Client-side JS • Server-side Java • JSON fetching with Gson • Google Cloud APIs
Client-side JS + Server-side Java
A client is whatever I'm using to interact with the internet (eg. web browsers, phone web browser). They run "locally", meaning that it happens on my device (eg. laptop, phone). Servers serve content based on requests - it's the computer my browser is talking to when browsers ask for specific URLs. Servlets are a Java class that run when a client requests a URL. @WebServlet("/URL") tells the server which URL the servlet maps to. doGet() runs every time a client sends a GET request. Not a servlet, but click the button to get a random fact about me:
This date servlet uses the JS fetch() function to request content from servers. fetch() is useful for requesting dynamic content. When I navigate to /date, my browser sends a request for the URL, and the server routes the request to DateServlet.java. The doGet() function writes the current date to the response, and my browser renders that response. In script.js, fetch() runs asynchronously, sending the request in the background while the rest of the code keeps running. That's why async (function will call async function) and await (tells JS to wait for response rather than sending request in background) are used. Click here or this button to see the server's current date:
We usually want to return multiple values from a server, so formats like XML, key-value pairs, and JS Object Notation (JSON) are popular choices. JSON is useful since JS can parse it without external libraries. Formatting JSON data can be tedious and error-prone - Gson is an open-source Java library that formats Java objects as JSON strings (need to add dependency to pom.xml to use Gson). Once JSON is created in server, json() function can be used in JS to parse response into JSON objects. Click here to see an example of server JSON. Click the button to see the parsed server-side JSON:
The contact form below demonstrates client to server communication. GET requests get data from the server, while POST requests let you send data to the server. A common way to send POST requests is by HTML <form> tags. Adding action="/URL" to the form tag connects the form to the servlet. When the form is submitted, it sends a POST request to the URL in the action attribute. The server looks for a servlet that maps to the URL, and then runs its doPost() function. The System.out.println() JS function prints the user's input in server logs (in Google Cloud's Logs Explorer, type `std out` in search bar). The Logs Explorer shows information about each request sent to the server, including any logs printed. Lastly, the user is redirected to another URL through response.sendRedirect("/messages-list.html");.
The form above uses a NoSQL database called Datastore to store messages permanently (need to add dependency to pom.xml). Persistent storage stores data safely and prevents the chance of erased data (eg. when you have more data than fits memory, when server restarts, or when App Engine automatically scales server up/down). To get an instance of the Datastore class, the DatastoreOptions.getDefaultInstance().getService() function is ran. Data in Datastore is represented by entities - similar to an instance of a class in Java. Each entitity has an associated key, and a key has a kind (like a class name). Entities also have properties, with each having a key and value (.set() function is called to set properties). The entity is then stored by passing it in the datastore.put() function. To load entities from Datastore, a Query instance is first created. This Query is passed into the datastore.run() function, which gives a QueryResults instance that contains all the entities in Datastore with that kind. The hasNext() and next() functions are used to iterate thorugh the entities. Lastly, entity.getTYPE() is ran to get the properties from Datastore.
This image uploader uses Google Cloud Storage. POST requests will work for data like strings/numbers, but to store binary data like files, Cloud Storage can be used. In the HTML <form> tag, the enctype="multipart/form-data" attribute is required for file uploads and the <input> tag includes name="image" to accept files (lets users choose file from hard drive). ImageServlet.java's doPost() function gets the inputted image and uploads it to Cloud Storage, which then returns the image's URL as a string. The doGet() function gets the URL of every image uploaded and uses them to build a HTML page (can also return URLs as JSON and build HTML using JS). Issues can happen where the uploaded files have the same name; to fix this, the current time can be added to the name or the UUID class can be used to generate a unique ID. Click here to see all of the uploaded images, or try uploading a file below.