Spring Web Services CRUD Tutorial with Hibernate and Maven

Spring MVC CRUD Web Services with Hibernate (No XML) — 2026 Guide

Spring MVC CRUD Web Services with Hibernate (No XML)

In this tutorial, we will build a complete Spring MVC CRUD REST web service backed by Hibernate and MySQL using annotation-based configuration only — no web.xml, no spring-servlet.xml.

You will learn how AbstractAnnotationConfigDispatcherServletInitializer replaces web.xml, how to configure a DataSource, SessionFactory, and HibernateTransactionManager as Spring beans, and how to expose CRUD operations via a @RestController.

Project Structure

MyConfig.java (Java Config)

This is the central configuration class. It replaces the traditional applicationContext.xml and spring-servlet.xml files.

package com.example.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import com.example.model.User;

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan(basePackages = { "com.example" })
@PropertySource(value = { "classpath:application.properties" })
public class MyConfig {

    @Autowired
    private Environment environment;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.class"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.user"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.pass"));
        System.out.println("Deep database " + dataSource);
        return dataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        // sessionFactory.setPackagesToScan(new String[] {"com.example.model"});
        sessionFactory.setAnnotatedClasses(User.class);
        sessionFactory.setHibernateProperties(hibernateProperties());
        System.out.println("deep session " + sessionFactory);
        return sessionFactory;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        //properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto",
                environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        System.out.println(properties);
        return properties;
    }

    @Bean
    public HibernateTransactionManager getTransactionManager() {
        System.out.println("transaction "+"hello");
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        System.out.println("transaction "+transactionManager);
        return transactionManager;
    }

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver cm=new CommonsMultipartResolver();
        cm.setMaxUploadSize(100000); return cm; }
}

FrontController.java (No web.xml)

This class replaces the traditional web.xml file. It extends AbstractAnnotationConfigDispatcherServletInitializer and works in a standard Servlet container (Tomcat, Jetty).

package com.example.controller;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.example.config.MyConfig;

public class FrontController extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return new Class[] {MyConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        // TODO Auto-generated method stub
        return new String[] {"/"};
    }
}

UserController.java

The @RestController exposes five REST endpoints for CRUD operations. Spring automatically converts Java objects to/from JSON via Jackson.

package com.example.controller;

import java.util.List;
import javax.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
import com.example.model.User;
import com.example.service.UserService;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping(value= {"insert"})
    public int addUser(@RequestBody User user) {
        return userService.insert(user);
    }

    @PutMapping(value= {"update"})
    public int updateUser(@RequestBody User user) {
        return userService.update(user);
    }

    @DeleteMapping(value= {"delete/{id}"})
    public int deleteUser(@PathVariable int id) {
        return userService.delete(id);
    }

    @GetMapping(value= {"fetch/{id}"})
    public User fetchUser(@PathVariable int id) {
        return userService.fetch(id);
    }

    @GetMapping(value= {"fetchall"})
    public List<User> fetchAllUser() {
        return userService.fetchAll();
    }
}

UserDao.java & UserDaoImpl.java

UserDao.java (Interface)

package com.example.dao;
import java.util.List;
import com.example.model.User;

public interface UserDao {

    public int insert(User user);

    public int delete(int id);

    public int update(User user);

    public User fetch(int id);

    public List<User> fetchAll();
}

UserDaoImpl.java (Implementation)

package com.example.dao;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.model.User;

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public int insert(User user) {
        System.out.println(sessionFactory);
        int id = (Integer) sessionFactory.getCurrentSession().save(user);
        return id;
    }

    @Override
    public int delete(int id) {
        int i = 0;
        User user = sessionFactory.getCurrentSession().get(User.class, id);
        if (user != null) {
            sessionFactory.getCurrentSession().delete(user);
            i=1;
        }
        return i;
    }

    @Override
    public int update(User user) {
        int i=0;
        User u = sessionFactory.getCurrentSession().get(User.class, user.getId());
        u.setEmail(user.getEmail());
        u.setName(user.getName());
        if(u!=null) {
            sessionFactory.getCurrentSession().update(u);
            i=1;
        }
        return i;
    }

    @Override
    public User fetch(int id) {
        System.out.println(id);
        User user = sessionFactory.getCurrentSession().get(User.class, id);
        System.out.println(user);
        if(user!=null) {
            return user;
        }
        return new User();
    }

    @Override
    public List<User> fetchAll() {
        CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);

        Root<User> p = query.from(User.class);
        query.select(p);
        //query.where(cb.equal(p.get("statusStepOne"), 0));
        //query.setFirstResult(0);
        //query.setMaxResults(1);
        Query<User> qq=sessionFactory.getCurrentSession().createQuery(query);
        List<User> list = qq.getResultList();
        return list;
    }
}

User.java (Entity)

package com.example.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="myrecords")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String email;

public User() {
    super();
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getEmail() {
    return email;
}
public void setEmail(String email) {
    this.email = email;
}
}

UserService.java & UserServiceImpl.java

UserService.java (Interface)

package com.example.service;
import java.util.List;
import com.example.model.User;

public interface UserService {

    public int insert(User user);

    public int delete(int id);

    public int update(User user);

    public User fetch(int id);

    public List<User> fetchAll();
}

UserServiceImpl.java

package com.example.service;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.dao.UserDao;
import com.example.model.User;
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    @Transactional
    public int insert(User user) {
        return userDao.insert(user);
    }

    @Override
    @Transactional
    public int delete(int id) {
        return userDao.delete(id);
    }

    @Override
    @Transactional
    public int update(User user) {
        return userDao.update(user);
    }

    @Override
    @Transactional
    public User fetch(int id) {
        return userDao.fetch(id);
    }

    @Override
    @Transactional
    public List<User> fetchAll() {
        return userDao.fetchAll();
    }
}

application.properties

jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.class=com.mysql.jdbc.Driver
jdbc.pass=root
jdbc.user=root

hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql = true
hibernate.format_sql = true
hibernate.hbm2ddl.auto = update

pom.xml

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

    <modelVersion>4.0.0</modelVersion>
    <groupId>SpringCurdWebServices</groupId>
    <artifactId>SpringCurdWebServices</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <release>10</release>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.1</version>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.17.Final</version>
        </dependency>
        <!-- Hibernate Validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.3</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
    </dependencies>
</project>

Frequently Asked Questions

How do I configure Spring MVC without web.xml?

Extend AbstractAnnotationConfigDispatcherServletInitializer and override three methods: getRootConfigClasses(), getServletConfigClasses(), and getServletMappings(). Spring automatically detects this class and registers the DispatcherServlet.

What is @EnableWebMvc in Spring?

@EnableWebMvc imports the Spring MVC configuration from WebMvcConfigurationSupport. It enables support for @Controller, @RequestMapping, HTTP message converters (like Jackson JSON), and view resolvers.

What is the difference between @Repository, @Service, and @Controller?

They are all specializations of @Component. @Repository is for the data access layer and translates SQL exceptions. @Service is for business logic. @Controller is for handling web requests. Using the right one makes the code more readable and enables layer-specific features.

Why is @Transactional needed on service methods?

Hibernate requires an active transaction to perform inserts, updates, and deletes. @Transactional tells Spring to wrap the method in a transaction, so the Session is opened and committed automatically.

Why use CriteriaBuilder instead of HQL for fetchAll()?

Both work, but CriteriaBuilder provides type-safe queries that are checked at compile time. HQL is string-based and errors only appear at runtime. For simple queries, HQL is shorter; for complex dynamic queries, Criteria API is safer.

Conclusion

In this tutorial, you built a complete Spring MVC CRUD REST web service using annotation-based configuration — no web.xml, no XML config files. You learned how AbstractAnnotationConfigDispatcherServletInitializer replaces the servlet descriptor, how to configure Hibernate as Spring beans, and how to expose clean REST endpoints with @RestController.

You can extend this project by adding validation with @Valid, error handling with @ControllerAdvice, pagination with CriteriaBuilder, or migrate to Spring Boot where all of this configuration is auto-detected.

Related topics: Spring Boot REST API Tutorial, Spring Data JPA CRUD, Hibernate Criteria API, Spring Exception Handling, Spring Validation, Migrating Spring MVC to Spring Boot

No comments: