Java class for visualising Graphs

Hello, everyone!
While studying graph algorithms I created a class that helps visualise what your algorithm is doing. That’s helpful for debugging and helps learn the way the algorithm works.

ezgif.com-crop
DFS algorithm in action

You can plug any graph algorithm, the important part is to notify the JPanel whenever you want to repaint.

Here is the code:


package com.algos;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;
public class GraphPanel extends JPanel {
private static final long serialVersionUID = 7148504528835036003L;
private List<GraphNode> graph = new ArrayList<>();
public static class GraphNode {
public static final double radius = 30;
public Point point;
public int index;
public List<GraphNode> children;
public boolean currentlyVisited = false;
public GraphNode(int index, Point point) {
this.point = point;
this.index = index;
children = new ArrayList<>();
}
public void draw(Graphics g) {
if (this.currentlyVisited) {
g.setColor(Color.GREEN);
g.fillOval(this.point.x, this.point.y, (int)radius * 2, (int)radius * 2);
} else {
g.setColor(Color.BLACK);
g.drawOval(this.point.x, this.point.y, (int)radius * 2, (int)radius * 2);
}
g.setColor(Color.BLACK);
g.drawChars(new char[]{Character.forDigit(this.index, 10)}, 0, 1, this.point.x, this.point.y);
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (GraphNode gf : graph) {
gf.draw(g);
for (GraphNode child : gf.children) {
g.drawLine(gf.point.x + (int) GraphNode.radius, gf.point.y + (int) GraphNode.radius, child.point.x + (int) GraphNode.radius, child.point.y + (int) GraphNode.radius);
}
}
}
public void addNodes(GraphNode… nodes) {
this.graph.addAll(Arrays.asList(nodes));
}
}

view raw

GraphPanel.java

hosted with ❤ by GitHub

And here is how you might use it.


package com.algos;
import com.algos.GraphPanel.GraphNode;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.util.ArrayDeque;
import java.util.Queue;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* A panel maintaining a picture of a Do Not Enter sign.
*/
public class GraphsGraphics {
private static boolean[] visited = new boolean[100];
private static Queue<GraphNode> queue = new ArrayDeque<>();
public static void DFS(GraphNode currentNode, GraphNode searchedNode, JPanel panel) {
System.out.println("Currently we are visiting node " + currentNode.index);
currentNode.currentlyVisited = true;
panel.updateUI();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
currentNode.currentlyVisited = false;
panel.updateUI();
if (currentNode.index == searchedNode.index) {
System.out.println("Node found: " + searchedNode.index);
return;
}
if (visited[currentNode.index]) {
return;
}
visited[currentNode.index] = true;
for (GraphNode child : currentNode.children) {
DFS(child, searchedNode, panel);
}
}
public static void BFS(GraphNode currentNode, GraphNode searchedNode, JPanel panel) {
currentNode.currentlyVisited = true;
panel.updateUI();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
currentNode.currentlyVisited = false;
panel.updateUI();
if (currentNode.index == searchedNode.index) {
System.out.println("Node found: " + searchedNode.index);
return;
}
if (visited[currentNode.index]) {
return;
}
System.out.println("Currently visiting node " + currentNode.index);
visited[currentNode.index] = true;
for (GraphNode child : currentNode.children) {
queue.add(child);
}
if (!queue.isEmpty()) {
BFS(queue.poll(), searchedNode, panel);
}
}
/**
* A little driver in case you want a stand-alone application.
*/
public static void main(String[] args) {
GraphNode rootNode = new GraphNode(0, new Point(300, 20));
GraphNode node1 = new GraphNode(1, new Point(200, 100));
GraphNode node2 = new GraphNode(2, new Point(400, 100));
GraphNode node3 = new GraphNode(3, new Point(500, 200));
GraphNode node4 = new GraphNode(4, new Point(100, 200));
GraphNode node5 = new GraphNode(5, new Point(40, 300));
GraphNode node6 = new GraphNode(6, new Point(200, 300));
rootNode.children.add(node1);
rootNode.children.add(node2);
node1.children.add(node4);
node2.children.add(node3);
node4.children.add(node5);
node4.children.add(node6);
GraphPanel panel = new GraphPanel();
panel.addNodes(rootNode, node1, node2, node3, node4, node5, node6);
SwingUtilities.invokeLater(() -> {
panel.setBackground(Color.GRAY.darker());
JFrame frame = new JFrame("A simple graphics program");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setVisible(true);
});
BFS(rootNode, node6, panel);
}
}

view raw

Main.java

hosted with ❤ by GitHub

Happy learning!

Spring – How to store uploaded file on the server

A common task that might pop-up (hopefully just once and then abstract) in the life of a software engineer is to handle a file upload from the client and store it in a folder on the server machine.

 

If you are using Spring that can be done really easy, even easier if you are willing to add some third party libraries in your project that would make writing the file on the server easier and more terse.

Let’s check our Controller, or in other words, the method that is called when a request comes to the server for specific URL + HTTP METHOD combination.

@RequestMapping(
    path = "/process",
    method = RequestMethod.POST,
    consumes={"multipart/form-data"},
    produces= {"application/zip"}
)
public FileSystemResource process(@RequestParam("file_upload") MultipartFile file, HttpServletResponse response) {

The important parts here are the “consumes” property. The value is a specific Mime Type which is a great format for uploading files or binary data. Which basically means “Hey, I eat only sliced bread”. This format specifies a boundary, or a term that is more familiar, a separator for each of the fields in the form, so we get something like a map at the end and we need to get the file. The way that we tell Spring that we want a specific value from this map is with the @RequestParam annotation.

Where this map comes from originally?

On the client we construct it. For that, we use the FormData class.

An example of a function that encodes an uploaded file (that which comes from the input with type=””file”) to FormData:

public fileToObjectData(file: File) {
  let formData: FormData = new FormData();

  formData.append('file_upload', file, file.name);

  return formData;
}

We use the key “file_upload” so at the other end, on the server we use the same key to fetch the File (not really a file, as you will learn soon…)

As we can see from above, the type of the file is MultipartFile. In order to save it on the file system we need to convert it to the Java’s File class.

public File convert(MultipartFile multipartFile) throws IOException { 
  File convFile = new File(buildFilePathName(multipartFile));
  convFile.createNewFile(); 
  FileOutputStream fos = new FileOutputStream(convFile); 
  fos.write(multipartFile.getBytes());
  fos.close(); 
  return convFile;
}

Let’s go through the lines one by one.

1. A “magic” method that takes the filename and appends in on the output folder path to create File’s path.
2. We create empty file on the file system, only if it does not exist yet.
3. Create a FileOutputStream in order to write to the file we created.
4. Write the byte data from the MultipartFile instance.
5. Closing the resource so it’s free to use by other threads and to free the references.
6. You know that one…

And that’s it!