Jakarta Faces 4 (JSF) with Mature Microservice as Backend DataAccess Example

This example demonstrates the usage of the j-framework in creating a project that communicates with a Mature microservice backend.

Prerequisites:

  1. You should have JDK 17+ Installed. (Click Here).

  2. You should have a mature microservice running first. (Click Here).

  3. You should create a Maven Project.

  4. You should enable snapshot versions. (Click Here).

Project Content:

This section contains what you should add to your code structure for this example.

  1. Maven Project with pom.xml that has the following contents:

<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>com.jalalkiswani</groupId>
		<artifactId>j-app-web</artifactId>
		<version>7.0.0-SNAPSHOT</version>
	</parent>
	<artifactId>j-framework-web-microservice-mature-client-example</artifactId>
	<packaging>war</packaging>

</project>
  1. Service configurations file located at src/main/resources/config.properties that has the following content:

app.services.persons.url=http://localhost:8080/app/persons
  1. Java Model class is located at src/main/java/com/app/person/Model.java that has the following content:

package com.app.person;

import java.io.Serializable;

public class Model implements Serializable {
	private Integer id;
	private String nationalId;
	private String name;
	private String email;
	private String address;

	public void setId(Integer id){
	  this.id=id;
	}

	public Integer getId(){
	 return this.id;
	}

	public void setNationalId(String nationalId){
	  this.nationalId=nationalId;
	}

	public String getNationalId(){
	 return this.nationalId;
	}

	public void setName(String name){
	  this.name=name;
	}

	public String getName(){
	 return this.name;
	}

	public void setEmail(String email){
	  this.email=email;
	}

	public String getEmail(){
	 return this.email;
	}

	public void setAddress(String address){
	  this.address=address;
	}

	public String getAddress(){
	 return this.address;
	}


	@Override
	public boolean equals(Object obj) {
	  if (obj == null) {
		return false;
	  }
	  return this.getId().equals(((Model) obj).getId());
	}

	@Override
	public int hashCode() {
	  if(this.id==null) {
	    return toString().hashCode();
	   }
	  return this.id.hashCode();
	}

	@Override
	public String toString(){
	  StringBuffer buf=new StringBuffer();
	  buf.append(this.id).append(",");
	  buf.append(this.nationalId).append(",");
	  buf.append(this.name).append(",");
	  buf.append(this.email).append(",");
	  buf.append(this.address).append(",");
	  return buf.toString();
	}
}
  1. Faces Controller located at src/main/java/com/app/person/Controller.java which contains the following:

package com.app.person;

import java.util.List;
import java.util.Vector;

import com.jk.web.faces.controllers.JKWebController;

import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;

@Named("controller")
@ViewScoped
public class Controller extends JKWebController {
	ServiceClient client = new ServiceClient();
	Model model;
	List<Model> modelList;
	List<Model> filterList;

	public boolean isAllowAdd() {
		return getModel().getId() == null;
	}

	public String add() {
		client.insert(model);
		refresh();
		success("Added Successfully");
		return null;
	}

	public boolean isAllowUpdate() {
		return getModel().getId() != null;
	}

	public String update() {
		client.update(model);
		int id = getModel().getId();
		success("Updated Successfully");
		refresh();
		// to ensure getting updated version from DB
		this.model = client.find(id + "");
		return null;
	}

	public boolean isAllowDelete() {
		return getModel().getId() != null;
	}

	public String delete() {
		client.delete(getModel().getId());
		success("Deleted Successfully");
		refresh();
		return null;
	}

	public String reset() {
		setModel(null);
		return null;
	}

	public Model getModel() {
		if (model == null) {
			model = new Model();
		}
		return model;
	}

	public void setModel(Model model) {
		this.model = model;
	}

	public List<Model> getModelList() {
		if (modelList == null) {
			modelList = client.getAll();
		}
		return modelList;
	}

	public List<Model> getFilterList() {
		return filterList;
	}

	public void setFilterList(Vector<Model> filterList) {
		this.filterList = filterList;
	}

	protected void refresh() {
		this.modelList = null;
		setModel(null);
	}
}
  1. Faces View located at src/main/webapp/index.xhtml which contains the following:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:jk="http://jalalkiswani.com/jsf"
	xmlns:p="http://primefaces.org/ui"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
	xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
	xmlns:f="http://xmlns.jcp.org/jsf/core"
	xmlns:of="http://omnifaces.org/ui">
<ui:composition template="/WEB-INF/templates/default.xhtml">
	<ui:define name="page-title">Person Page</ui:define>
	<ui:define name="contents">
		<h:form id="frmPerson">
			<p:autoUpdate />
			<p:growl/>
			<p:panelGrid columns="4" style="margin:auto;" styleClass="shaddow">
				<f:facet name="header">Person Form</f:facet>

				<p:outputLabel value="National Id" for="nationalId" />
				<p:inputText type="text" value="#{controller.model.nationalId}"
					id="nationalId" placeholder="NationalId" required="true"/>

				<p:outputLabel value="Name" for="name" />
				<p:inputText type="text" value="#{controller.model.name}" id="name"
					placeholder="Name" required="true"/>

				<p:outputLabel value="Email" for="email" />
				<p:inputText type="email" value="#{controller.model.email}"
					id="email" placeholder="Email" required="true"/>

				<p:outputLabel value="Address" for="address" />
				<p:inputTextarea id="address" value="#{controller.model.address}"
					readOnly="false" required="false" placeholder="Address" />
				<f:facet name="footer">
					<div align="center">
						<p:commandButton value="Add" action="#{controller.add}"
							rendered="#{controller.allowAdd}" process="@form" />
						<p:commandButton value="Update" action="#{controller.update}"
							rendered="#{controller.allowUpdate}" process="@form" />
						<p:commandButton value="Delete" action="#{controller.delete}"
							rendered="#{controller.allowDelete}" process="@this" />
						<p:commandButton value="Reset" action="#{controller.reset}"
							process="@this" />
					</div>
				</f:facet>

			</p:panelGrid>
		</h:form>
		<hr />
		<h:form>
			<p:dataTable value="#{controller.modelList}" var="model"
				rowKey="#{model.id}" paginator="true" paginatorAlwaysVisible="false"
				paginatorPosition="bottom" selectionMode="single"
				filteredValue="#{controller.filterList}"
				selection="#{controller.model}" emptyMessage="" rowIndexVar="row"
				styleClass="shaddow">
				<p:ajax event="rowSelect" />
				<p:autoUpdate />
				<f:facet name="header">Person Data Table</f:facet>
				<p:column headerText="#">#{row+1}</p:column>
				<p:column headerText="national id" sortBy="#{model.nationalId}"
					filterBy="#{model.nationalId}" filterMatchMode="contains">
					<h:outputText
						value="#{model.nationalId==null?'-':model.nationalId}" />
				</p:column>
				<p:column headerText="name" sortBy="#{model.name}"
					filterBy="#{model.name}" filterMatchMode="contains">
					<h:outputText value="#{model.name==null?'-':model.name}" />
				</p:column>
				<p:column headerText="email" sortBy="#{model.email}"
					filterBy="#{model.email}" filterMatchMode="contains">
					<h:outputText value="#{model.email==null?'-':model.email}" />
				</p:column>
				<p:column headerText="address" sortBy="#{model.address}"
					filterBy="#{model.address}" filterMatchMode="contains">
					<h:outputText value="#{model.address==null?'-':model.address}" />
				</p:column>
			</p:dataTable>
		</h:form>
	</ui:define>
</ui:composition>
</html>
  1. Service Client class is located at src/main/java/com/app/person/ServiceClient.java which contains the following:

package com.app.person;

import com.jk.services.client.JKMatureServiceClient;

public class ServiceClient extends JKMatureServiceClient<Model>{

	@Override
	public String getServiceUrlPropertyName() {
		return "app.services.persons.url";
	}

}
  1. Main java class located at src/main/java/com/app/App.java which contains the following:

package com.app;

import com.jk.web.embedded.JKWebApplication;

public class App {
	public static void main(String[] args) {
		JKWebApplication.run(8181);
	}
}

Alternatively, you can clone or download the tutorial repository then import the project into your IDE.

How to run Project:

  1. Set up the project with the content shown above.

  2. Inside your IDE, go to the src/main/java/com/app/App.java class.

Main Class

  1. Next, run it as a Java Application.

Run as Java Application

  1. Your program will start running and will open your browser to show you the result of the run. Alternatively, after running the code, you can open any browser to localhost on port 8181, and it will show you the run output as well.

localhost:8181

Example Explanation

  1. The first page prompts you to fill in the form fields and has two main buttons under it.

Example Run 1

  1. The [Add] button will add the data you entered to the microservice which will then display them in the table below the form.

Example Run 2

  1. The [Reset] button will clear the form fields.