This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var http = require('http'); | |
http.createServer(function (req, res) { | |
res.writeHead(200, {'Content-Type': 'text/plain'}); | |
res.end('Hello World\n'); | |
}).listen(1337, '127.0.0.1'); | |
console.log('Server running at http://127.0.0.1:1337/'); |
I thought that with something like this you can easily test your code without the burden of deploy it, and also saving some resources.
So I start looking if there is something similar in java and I found several projects to start a web server or a minimal server, but I decided to go with jetty www.eclipse.org/jetty, so I'm going to show you how to run some restful web services using jetty.
Also I'm going to use jersey jersey.java.net which simplifies the development of RESTful Web services and their clients in Java.
So you can download the jars from these projects or configure them through maven to your project to start using them, in these links www.eclipse.org/jetty , jersey.java.net you can check the instructions to do it.
So to create a web server with jetty is as easy as the following code:
If you run the code and check the http://localhost:8080/hello url you can see that your servlet is running, so basically in the code you create a Server object and set the port the Servlets and the servlets to run and that's it.
With jetty you can do much more than this, but for the purpose of this blog I will no go further, you can check the jetty documentation.
The following would be to create and deploy the RESTful web services, now we will use jersey to this.
The first thing to do is to create the services that we will deploy, for the example I will create two services one using JSON and other using XML, I will create two objects used to transfer the data.
The classes above use the standard Java EE specification for RESTful web services they use the @Path annotation at the top level to set the service path and each method use the @GET, @POST annotations to describe the type of service and the @Produces annotation to set the type of protocol to use.
The method getStudent of the class XMLStudentSvc has also the @Path("/student/{name}") this specifies a path for this method, also note that it receives a parameter named "name" through the path and this parameter will be mapped to the parameter of the method.
For more about how define RESTful web services check the specification https://jcp.org/en/jsr/detail?id=311
Another thing to notice is that both classes are in a package called "rest", so the following to do would be to deploy these services in jetty as long as the jersey configuration.
This is the class for the server:
See in the class above all what it needs to configure jersey, a ServletHolder object is created to set the parameters, note that is indicated the package where the services are located and jersey will automatically deploy them. The ServletHolder object is passed to a ServletContextHandler object, and that's it with this the services should be up and running.
The last thing to do is to create a client for our services, for the client I will use jersey to help.
This is the client for the JSON service:
The client will call two methods, the first will be to the GET method and it uses the url with the path specified for this method ("http://localhost:9999/employee/getEmployee"), this method returns a response in JSON, then this response is unmarshal to a object with the call to "response.getEntity(Employee.class)".
If the JSON response is needed instead of the actual object all what is need to do is change the type to String in the unmarshal "response.getEntity(Employee.class)".
The other method specified in this client is the POST method this call doesn't return a thing, it uses the url with the path specified for this method ("http://localhost:9999/employee/postEmployee") and it sends back the same object the client is receiving, you should see an output in the server since the service method is printing the object it is receiving.
This is the client for the XML service:
It is almost the same as the JSON client, the only difference is that a parameter is include in the url "http://localhost:9999/xmlServices/student/James", because the service is expecting it.
After running these examples I notice how easy and fast is to run the services and the few resources that required, I'm using at most 30Mb of memory.
So you can download the jars from these projects or configure them through maven to your project to start using them, in these links www.eclipse.org/jetty , jersey.java.net you can check the instructions to do it.
So to create a web server with jetty is as easy as the following code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example.server; | |
import java.io.IOException; | |
import javax.servlet.ServletException; | |
import javax.servlet.http.HttpServlet; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.eclipse.jetty.server.Server; | |
import org.eclipse.jetty.servlet.ServletHandler; | |
public class MinimalServer { | |
public static void main(String[] args) throws Exception { | |
Server server = new Server(8080); | |
ServletHandler handler = new ServletHandler(); | |
handler.addServletWithMapping(HelloServlet.class, "/hello");//Set the servlet to run. | |
server.setHandler(handler); | |
server.start(); | |
server.join(); | |
} | |
@SuppressWarnings("serial") | |
public static class HelloServlet extends HttpServlet { | |
@Override | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
response.setContentType("text/html"); | |
response.setStatus(HttpServletResponse.SC_OK); | |
response.getWriter().println("<h1>Hello SimpleServlet</h1>"); | |
} | |
} | |
} |
If you run the code and check the http://localhost:8080/hello url you can see that your servlet is running, so basically in the code you create a Server object and set the port the Servlets and the servlets to run and that's it.
With jetty you can do much more than this, but for the purpose of this blog I will no go further, you can check the jetty documentation.
The following would be to create and deploy the RESTful web services, now we will use jersey to this.
The first thing to do is to create the services that we will deploy, for the example I will create two services one using JSON and other using XML, I will create two objects used to transfer the data.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dto; | |
import javax.xml.bind.annotation.XmlElement; | |
import javax.xml.bind.annotation.XmlRootElement; | |
@XmlRootElement | |
public class Employee { | |
private String name = ""; | |
private int age = 0; | |
private String department = ""; | |
private Address address = null; | |
private double wage = 0; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public int getAge() { | |
return age; | |
} | |
public void setAge(int age) { | |
this.age = age; | |
} | |
public String getDepartment() { | |
return department; | |
} | |
public void setDeparment(String department) { | |
this.department = department; | |
} | |
public Address getAddress() { | |
return address; | |
} | |
public void setAddress(Address address) { | |
this.address = address; | |
} | |
public double getWage() { | |
return wage; | |
} | |
public void setWage(double wage) { | |
this.wage = wage; | |
} | |
@Override | |
public String toString() { | |
return "Employee [name=" + name + ", age=" + age + ", department=" | |
+ department + ", address=" + address + ", wage=" + wage | |
+ "]"; | |
} | |
} | |
package dto; | |
import javax.xml.bind.annotation.XmlElement; | |
import javax.xml.bind.annotation.XmlRootElement; | |
@XmlRootElement | |
public class Address { | |
private String street =""; | |
private String city =""; | |
private String state =""; | |
private int zip = 0; | |
public String getStreet() { | |
return street; | |
} | |
public void setStreet(String street) { | |
this.street = street; | |
} | |
public String getCity() { | |
return city; | |
} | |
public void setCity(String city) { | |
this.city = city; | |
} | |
public String getState() { | |
return state; | |
} | |
public void setState(String state) { | |
this.state = state; | |
} | |
public int getZip() { | |
return zip; | |
} | |
public void setZip(int zip) { | |
this.zip = zip; | |
} | |
@Override | |
public String toString() { | |
return "Address [street=" + street + ", city=" + city + ", state=" | |
+ state + ", zip=" + zip + "]"; | |
} | |
} | |
package dto; | |
import javax.xml.bind.annotation.XmlAttribute; | |
import javax.xml.bind.annotation.XmlElement; | |
import javax.xml.bind.annotation.XmlRootElement; | |
@XmlRootElement(name = "student") | |
public class Student { | |
private int id; | |
private String firstName; | |
private String lastName; | |
private int age; | |
public Student() { | |
} | |
public Student(String fname, String lname, int age, int id) { | |
this.firstName = fname; | |
this.lastName = lname; | |
this.age = age; | |
this.id = id; | |
} | |
@XmlElement | |
public void setFirstName(String fname) { | |
this.firstName = fname; | |
} | |
public String getFirstName() { | |
return this.firstName; | |
} | |
@XmlElement | |
public void setLastName(String lname) { | |
this.lastName = lname; | |
} | |
public String getLastName() { | |
return this.lastName; | |
} | |
@XmlElement | |
public void setAge(int age) { | |
this.age = age; | |
} | |
public int getAge() { | |
return this.age; | |
} | |
@XmlAttribute | |
public void setId(int id) { | |
this.id = id; | |
} | |
public int getId() { | |
return this.id; | |
} | |
@Override | |
public String toString() { | |
return new StringBuffer(" First Name : ").append(this.firstName) | |
.append(" Last Name : ").append(this.lastName) | |
.append(" Age : ").append(this.age).append(" ID : ") | |
.append(this.id).toString(); | |
} | |
} |
In the classes above you can see two classes Employee with a nested class Address and Student, the only thing to notice from these classes are the annotations @XmlRootElement and @XmlAttribute, these annotations are used to do the parsing from object to the protocol used (XML, JSON) and from protocol to object.
The following would be to create the classes for the services.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package rest; | |
import javax.ws.rs.GET; | |
import javax.ws.rs.POST; | |
import javax.ws.rs.Path; | |
import javax.ws.rs.Produces; | |
import javax.ws.rs.core.MediaType; | |
import dto.Address; | |
import dto.Employee; | |
@Path("/employee") | |
public class EmployeeSvc { | |
@GET | |
@Path("/getEmployee") | |
@Produces(MediaType.APPLICATION_JSON) | |
public Employee getEmployee() { | |
Employee employee = new Employee(); | |
employee.setName("John"); | |
employee.setAge(25); | |
employee.setDeparment("HR"); | |
employee.setWage(15000.00); | |
Address address = new Address(); | |
address.setCity("Massachusetts"); | |
address.setState("Springfield"); | |
address.setStreet("Evergreen"); | |
address.setZip(66450); | |
employee.setAddress(address); | |
return employee; | |
} | |
@POST | |
@Path("/postEmployee") | |
public void postEmployee(Employee employee) { | |
System.out.println("Output json server .... \n"); | |
System.out.println(employee); | |
} | |
} | |
package rest; | |
import javax.ws.rs.GET; | |
import javax.ws.rs.Path; | |
import javax.ws.rs.PathParam; | |
import javax.ws.rs.Produces; | |
import javax.ws.rs.core.MediaType; | |
import dto.Student; | |
@Path("/xmlServices") | |
public class XMLStudentSvc { | |
@GET | |
@Path("/student/{name}") | |
@Produces(MediaType.APPLICATION_XML) | |
public Student getStudent( @PathParam("name") String name ) { | |
Student st = new Student(name, "Smith", 22, 1); | |
return st; | |
} | |
} |
The method getStudent of the class XMLStudentSvc has also the @Path("/student/{name}") this specifies a path for this method, also note that it receives a parameter named "name" through the path and this parameter will be mapped to the parameter of the method.
For more about how define RESTful web services check the specification https://jcp.org/en/jsr/detail?id=311
Another thing to notice is that both classes are in a package called "rest", so the following to do would be to deploy these services in jetty as long as the jersey configuration.
This is the class for the server:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example.server; | |
import javax.ws.rs.GET; | |
import javax.ws.rs.Path; | |
import org.eclipse.jetty.server.Server; | |
import org.eclipse.jetty.servlet.ServletContextHandler; | |
import org.eclipse.jetty.servlet.ServletHolder; | |
import com.sun.jersey.api.client.Client; | |
import com.sun.jersey.api.client.WebResource; | |
import com.sun.jersey.spi.container.servlet.ServletContainer; | |
public class MinimalServerRest { | |
public static void main(String[] args) throws Exception { | |
ServletHolder sh = new ServletHolder(ServletContainer.class); | |
sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass", "com.sun.jersey.api.core.PackagesResourceConfig"); | |
sh.setInitParameter("com.sun.jersey.config.property.packages", "rest");//Set the package where the services reside | |
sh.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true"); | |
Server server = new Server(9999); | |
ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); | |
context.addServlet(sh, "/*"); | |
server.start(); | |
server.join(); | |
} | |
} |
See in the class above all what it needs to configure jersey, a ServletHolder object is created to set the parameters, note that is indicated the package where the services are located and jersey will automatically deploy them. The ServletHolder object is passed to a ServletContextHandler object, and that's it with this the services should be up and running.
The last thing to do is to create a client for our services, for the client I will use jersey to help.
This is the client for the JSON service:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package rest.client; | |
import com.sun.jersey.api.client.Client; | |
import com.sun.jersey.api.client.ClientResponse; | |
import com.sun.jersey.api.client.WebResource; | |
import dto.Employee; | |
public class JsonClient { | |
public static void main(String[] args) { | |
Client client = Client.create(); | |
//Get | |
WebResource webResource = client.resource("http://localhost:9999/employee/getEmployee"); | |
ClientResponse response = webResource.accept("application/json").get(ClientResponse.class); | |
if (response.getStatus() != 200) { | |
throw new RuntimeException("Failed : HTTP error code : " | |
+ response.getStatus()); | |
} | |
// String output = response.getEntity(String.class); | |
Employee output = response.getEntity(Employee.class);//Get the object from the response | |
System.out.println("Output json client .... \n"); | |
System.out.println(output); | |
//Post | |
webResource = client.resource("http://localhost:9999/employee/postEmployee"); | |
webResource.accept("application/json").post(ClientResponse.class, output); | |
} | |
} |
The client will call two methods, the first will be to the GET method and it uses the url with the path specified for this method ("http://localhost:9999/employee/getEmployee"), this method returns a response in JSON, then this response is unmarshal to a object with the call to "response.getEntity(Employee.class)".
If the JSON response is needed instead of the actual object all what is need to do is change the type to String in the unmarshal "response.getEntity(Employee.class)".
The other method specified in this client is the POST method this call doesn't return a thing, it uses the url with the path specified for this method ("http://localhost:9999/employee/postEmployee") and it sends back the same object the client is receiving, you should see an output in the server since the service method is printing the object it is receiving.
This is the client for the XML service:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package rest.client; | |
import com.sun.jersey.api.client.Client; | |
import com.sun.jersey.api.client.ClientResponse; | |
import com.sun.jersey.api.client.WebResource; | |
import dto.Student; | |
public class XMLClient { | |
public static void main(String[] args) { | |
Client client = Client.create(); | |
WebResource webResource = client.resource("http://localhost:9999/xmlServices/student/James"); | |
ClientResponse response = webResource.accept("application/xml").get(ClientResponse.class); | |
if (response.getStatus() != 200) { | |
throw new RuntimeException("Failed : HTTP error code : " | |
+ response.getStatus()); | |
} | |
//String output = response.getEntity(String.class); | |
Student output = response.getEntity(Student.class); //Get the object from the response | |
System.out.println("Output xml client .... \n"); | |
System.out.println(output); | |
} | |
} |
It is almost the same as the JSON client, the only difference is that a parameter is include in the url "http://localhost:9999/xmlServices/student/James", because the service is expecting it.
After running these examples I notice how easy and fast is to run the services and the few resources that required, I'm using at most 30Mb of memory.