Spring Application Deployment on WebSphere Liberty with Oracle Database

This guide provides a complete setup for deploying a traditional Spring application on WebSphere Liberty using ojdbc8 driver and Java 8, focusing on the backend components without views. Project Structure spring-liberty-app/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ ├── config/ │ │ │ │ └── AppConfig.java │ │ │ │ └── WebConfig.java │ │ │ │ └── AppInitializer.java │ │ │ ├── controller/ │ │ │ │ └── EmployeeController.java │ │ │ ├── dao/ │ │ │ │ └── EmployeeDAO.java │ │ │ ├── model/ │ │ │ │ └── Employee.java │ │ │ └── service/ │ │ │ └── EmployeeService.java │ │ ├── liberty/ │ │ │ └── config/ │ │ │ └── server.xml │ │ ├── resources/ │ │ │ └── log4j.properties │ └── test/ │ └── java/ Maven Configuration (pom.xml) 4.0.0 com.example spring-liberty-app 1.0-SNAPSHOT war 1.8 1.8 5.3.20 21.5.0.0 5.6.10.Final UTF-8 org.springframework spring-context ${spring.version} org.springframework spring-webmvc ${spring.version} org.springframework spring-jdbc ${spring.version} org.springframework spring-orm ${spring.version} javax.servlet javax.servlet-api 4.0.1 provided com.fasterxml.jackson.core jackson-databind 2.13.3 com.oracle.database.jdbc ojdbc8 ${ojdbc8.version} provided org.hibernate hibernate-core ${hibernate.version} org.slf4j slf4j-api 1.7.36 org.slf4j slf4j-log4j12 1.7.36 log4j log4j 1.2.17 spring-liberty-app org.apache.maven.plugins maven-compiler-plugin 3.10.1 1.8 1.8 org.apache.maven.plugins maven-war-plugin 3.3.2 false io.openliberty.tools liberty-maven-plugin 3.7.1 springServer usr 9080 9443 /api lib true com.oracle.database.jdbc ojdbc8 ${ojdbc8.version} Liberty Server Configuration (server.xml) Create a file at src/main/liberty/config/server.xml: servlet-4.0 jdbc-4.2 jndi-1.0 localConnector-1.0 jpa-2.2 Java Classes Model Class (Employee.java) Create src/main/java/com/example/model/Employee.java: package com.example.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.SequenceGenerator; import javax.persistence.Table; @Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_seq") @SequenceGenerator(name = "emp_seq", sequenceName = "employee_seq", allocationSize = 1) private Long id; @Column(name = "name", nullable = false) private String name; @Column(name = "department") private String department; @Column(name = "salary") private Double salary; @Column(name = "email") private String email; // Default constructor public Employee() { } // Constructor with fields public Employee(String name, String department, Double salary, String email) { this.name = name; this.department = department; this.salary = salary; this.email = email; } // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDepartm

Apr 12, 2025 - 14:44
 0
Spring Application Deployment on WebSphere Liberty with Oracle Database

This guide provides a complete setup for deploying a traditional Spring application on WebSphere Liberty using ojdbc8 driver and Java 8, focusing on the backend components without views.

Project Structure

spring-liberty-app/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── config/
│   │   │           │   └── AppConfig.java
│   │   │           │   └── WebConfig.java
│   │   │           │   └── AppInitializer.java
│   │   │           ├── controller/
│   │   │           │   └── EmployeeController.java
│   │   │           ├── dao/
│   │   │           │   └── EmployeeDAO.java
│   │   │           ├── model/
│   │   │           │   └── Employee.java
│   │   │           └── service/
│   │   │               └── EmployeeService.java
│   │   ├── liberty/
│   │   │   └── config/
│   │   │       └── server.xml
│   │   ├── resources/
│   │   │   └── log4j.properties
│   └── test/
│       └── java/

Maven Configuration (pom.xml)

 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   4.0.0

   com.example
   spring-liberty-app
   1.0-SNAPSHOT
   war

   
      1.8
      1.8
      5.3.20
      21.5.0.0
      5.6.10.Final
      UTF-8
   

   
      
      
         org.springframework
         spring-context
         ${spring.version}
      
      
         org.springframework
         spring-webmvc
         ${spring.version}
      
      
         org.springframework
         spring-jdbc
         ${spring.version}
      
      
         org.springframework
         spring-orm
         ${spring.version}
      

      
      
         javax.servlet
         javax.servlet-api
         4.0.1
         provided
      

      
      
         com.fasterxml.jackson.core
         jackson-databind
         2.13.3
      

      
      
         com.oracle.database.jdbc
         ojdbc8
         ${ojdbc8.version}
         provided
      

      
      
         org.hibernate
         hibernate-core
         ${hibernate.version}
      

      
      
         org.slf4j
         slf4j-api
         1.7.36
      
      
         org.slf4j
         slf4j-log4j12
         1.7.36
      
      
         log4j
         log4j
         1.2.17
      
   

   
      spring-liberty-app
      
         
            org.apache.maven.plugins
            maven-compiler-plugin
            3.10.1
            
               1.8
               1.8
            
         

         
            org.apache.maven.plugins
            maven-war-plugin
            3.3.2
            
               false
            
         

         
            io.openliberty.tools
            liberty-maven-plugin
            3.7.1
            
               springServer
               usr
               
                  9080
                  9443
                  /api
               
               
               
                  
                     lib
                     true
                     
                        com.oracle.database.jdbc
                        ojdbc8
                        ${ojdbc8.version}
                     
                  
               
            
         
      
   

Liberty Server Configuration (server.xml)

Create a file at src/main/liberty/config/server.xml:

 description="Spring Application Server">
    
        servlet-4.0
        jdbc-4.2
        jndi-1.0
        localConnector-1.0
        jpa-2.2
    

     id="defaultHttpEndpoint" host="*" httpPort="${default.http.port}" httpsPort="${default.https.port}" />

     id="OracleLib">
         dir="${server.config.dir}/lib" includes="ojdbc8.jar" />
    

     id="OracleDataSource" jndiName="jdbc/myOracleDS">
         libraryRef="OracleLib" />
         URL="jdbc:oracle:thin:@//localhost:1521/ORCLPDB1"
                          user="scott" 
                          password="tiger" />
         maxPoolSize="50" minPoolSize="10" />
    

     autoExpand="true" />

     id="spring-liberty-app" location="spring-liberty-app.war" name="spring-liberty-app" type="war" context-root="${app.context.root}">
         commonLibraryRef="OracleLib" />
    

Java Classes

Model Class (Employee.java)

Create src/main/java/com/example/model/Employee.java:

package com.example.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_seq")
    @SequenceGenerator(name = "emp_seq", sequenceName = "employee_seq", allocationSize = 1)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "department")
    private String department;

    @Column(name = "salary")
    private Double salary;

    @Column(name = "email")
    private String email;

    // Default constructor
    public Employee() {
    }

    // Constructor with fields
    public Employee(String name, String department, Double salary, String email) {
        this.name = name;
        this.department = department;
        this.salary = salary;
        this.email = email;
    }

    // Getters and Setters
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public String getEmail() {
        return email;
    }

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

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", department=" + department + 
               ", salary=" + salary + ", email=" + email + "]";
    }
}

DAO Layer (EmployeeDAO.java)

Create src/main/java/com/example/dao/EmployeeDAO.java:

package com.example.dao;

import com.example.model.Employee;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.List;

@Repository
public class EmployeeDAO {

    @PersistenceContext
    private EntityManager entityManager;

    public List<Employee> getAllEmployees() {
        TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e ORDER BY e.id", Employee.class);
        return query.getResultList();
    }

    public Employee findById(Long id) {
        return entityManager.find(Employee.class, id);
    }

    public void save(Employee employee) {
        if (employee.getId() == null) {
            entityManager.persist(employee);
        } else {
            entityManager.merge(employee);
        }
    }

    public void delete(Long id) {
        Employee employee = findById(id);
        if (employee != null) {
            entityManager.remove(employee);
        }
    }

    public List<Employee> findByDepartment(String department) {
        TypedQuery<Employee> query = entityManager.createQuery(
            "SELECT e FROM Employee e WHERE e.department = :dept", Employee.class);
        query.setParameter("dept", department);
        return query.getResultList();
    }
}

Service Layer (EmployeeService.java)

Create src/main/java/com/example/service/EmployeeService.java:

package com.example.service;

import com.example.dao.EmployeeDAO;
import com.example.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class EmployeeService {

    @Autowired
    private EmployeeDAO employeeDAO;

    public List<Employee> getAllEmployees() {
        return employeeDAO.getAllEmployees();
    }

    public Employee findById(Long id) {
        return employeeDAO.findById(id);
    }

    public void saveEmployee(Employee employee) {
        employeeDAO.save(employee);
    }

    public void deleteEmployee(Long id) {
        employeeDAO.delete(id);
    }

    public List<Employee> findByDepartment(String department) {
        return employeeDAO.findByDepartment(department);
    }
}

Controller (EmployeeController.java)

Create src/main/java/com/example/controller/EmployeeController.java:

package com.example.controller;

import com.example.model.Employee;
import com.example.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @GetMapping
    public List<Employee> getAllEmployees() {
        return employeeService.getAllEmployees();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Employee> getEmployeeById(@PathVariable Long id) {
        Employee employee = employeeService.findById(id);
        if (employee == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(employee, HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<Employee> createEmployee(@RequestBody Employee employee) {
        employeeService.saveEmployee(employee);
        return new ResponseEntity<>(employee, HttpStatus.CREATED);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employeeDetails) {
        Employee employee = employeeService.findById(id);
        if (employee == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        employee.setName(employeeDetails.getName());
        employee.setDepartment(employeeDetails.getDepartment());
        employee.setSalary(employeeDetails.getSalary());
        employee.setEmail(employeeDetails.getEmail());

        employeeService.saveEmployee(employee);
        return new ResponseEntity<>(employee, HttpStatus.OK);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Map<String, Boolean>> deleteEmployee(@PathVariable Long id) {
        Employee employee = employeeService.findById(id);
        if (employee == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        employeeService.deleteEmployee(id);

        Map<String, Boolean> response = new HashMap<>();
        response.put("deleted", Boolean.TRUE);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    @GetMapping("/department")
    public ResponseEntity<List<Employee>> getEmployeesByDepartment(@RequestParam String name) {
        List<Employee> employees = employeeService.findByDepartment(name);
        return new ResponseEntity<>(employees, HttpStatus.OK);
    }
}

Spring Configuration Classes

WebConfig.java

Create a file at src/main/java/com/example/config/WebConfig.java:

package com.example.config;

        import org.springframework.context.annotation.ComponentScan;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.web.servlet.config.annotation.EnableWebMvc;

        @Configuration
        @EnableWebMvc
        @ComponentScan(basePackages = "com.example.controller")
        public class WebConfig {
        // Additional configuration can go here if needed
        }

AppConfig.java

Create a file at src/main/java/com/example/config/AppConfig.java:

package com.example.config;

import javax.naming.NamingException;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.util.Properties;

@Configuration
@ComponentScan(basePackages = {"com.example.service", "com.example.dao"})
@EnableTransactionManagement
public class AppConfig {

   @Bean
   public JndiObjectFactoryBean dataSource() {
      JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
      jndiObjectFactoryBean.setJndiName("jdbc/myOracleDS");
      jndiObjectFactoryBean.setResourceRef(true);
      return jndiObjectFactoryBean;
   }

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
      LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
      em.setDataSource((DataSource) dataSource().getObject());
      em.setPackagesToScan("com.example.model");

      HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
      vendorAdapter.setShowSql(true);
      vendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle12cDialect");
      em.setJpaVendorAdapter(vendorAdapter);

      Properties properties = new Properties();
      properties.setProperty("hibernate.format_sql", "true");
      properties.setProperty("hibernate.use_sql_comments", "true");
      properties.setProperty("hibernate.hbm2ddl.auto", "update");
      em.setJpaProperties(properties);

      return em;
   }

   @Bean
   public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(emf);
      return transactionManager;
   }
}

AppInitializer.java

Create a file at src/main/java/com/example/config/AppInitializer.java:

package com.example.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class AppInitializer implements WebApplicationInitializer {

   @Override
   public void onStartup(ServletContext servletContext) throws ServletException {

      // Root application context (equivalent to applicationContext.xml)
      AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
      rootContext.setConfigLocation("com.example.config"); // package with @Configuration classes

      servletContext.addListener(new ContextLoaderListener(rootContext));

      // Dispatcher servlet context (equivalent to dispatcher-servlet.xml)
      AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
      dispatcherContext.register(WebConfig.class); // your WebConfig class

      ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher",
              new DispatcherServlet(dispatcherContext));

      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
   }
}

Logging Configuration

Create a file at src/main/resources/log4j.properties:

# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Hibernate logging options
log4j.logger.org.hibernate=INFO
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

# Spring logging
log4j.logger.org.springframework=INFO

Building and Deployment Steps

  1. Build the application:
   mvn clean package
  1. Create and configure Liberty server:
   mvn liberty:create liberty:install-feature
  1. Deploy the application:
   mvn liberty:deploy
  1. Start the Liberty server:
   mvn liberty:start
  1. Your REST API will be accessible at:
   http://localhost:9080/api/employees

API Endpoints

Method URL Description
GET /api/employees Get all employees
GET /api/employees/{id} Get employee by ID
POST /api/employees Create a new employee
PUT /api/employees/{id} Update an employee
DELETE /api/employees/{id} Delete an employee
GET /api/employees/department?name={dept} Get employees by department

Testing with curl

Here are some curl commands to test your API:

  1. Get all employees:
   curl -X GET http://localhost:9080/api/employees
  1. Get a specific employee:
   curl -X GET http://localhost:9080/api/employees/1
  1. Create a new employee:
   curl -X POST http://localhost:9080/api/employees \
     -H "Content-Type: application/json" \
     -d '{"name":"John Doe","department":"IT","salary":75000,"email":"john.doe@example.com"}'
  1. Update an employee:
   curl -X PUT http://localhost:9080/api/employees/1 \
     -H "Content-Type: application/json" \
     -d '{"name":"John Doe","department":"Engineering","salary":80000,"email":"john.doe@example.com"}'
  1. Delete an employee:
   curl -X DELETE http://localhost:9080/api/employees/1
  1. Get employees by department:
   curl -X GET http://localhost:9080/api/employees/department?name=IT

Important Notes

  1. Replace the database connection details in server.xml with your actual Oracle database credentials.

  2. The Oracle JDBC driver (ojdbc8.jar) needs to be accessible to your Liberty server. Make sure it's properly located in the server's lib directory.

  3. If you encounter class loading issues, verify that the commonLibraryRef attribute in the application tag in server.xml is correctly pointing to your Oracle library.

  4. This application uses JPA/Hibernate for database operations. The hibernate.hbm2ddl.auto=update property will attempt to create/update tables in your database schema.

  5. Liberty's JPA implementation might differ slightly from standalone Hibernate. If you encounter any JPA-related issues, consult the WebSphere Liberty documentation for specifics.

  6. When deploying in a production environment, remember to adjust the logging levels and security settings appropriately.

Repo link

Code can found here: https://github.com/khalilou88/spring-liberty-oracle-app